From 34ad856873d1749698b75fd1b45ba7906fd92f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mime=20=C4=8Cuvalo?= Date: Wed, 17 Apr 2024 12:11:08 +0100 Subject: [PATCH] textfields: nix disableTab option; make TextShapes have custom Tab behavior as intended (#3506) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 - [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 - [ ] `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 --- .../SpeechBubble/SpeechBubbleUtil.tsx | 1 - packages/tldraw/api-report.md | 4 +-- packages/tldraw/api/api.json | 28 ++++----------- .../arrow/components/ArrowTextLabel.tsx | 1 - .../src/lib/shapes/geo/GeoShapeUtil.tsx | 1 - .../src/lib/shapes/note/NoteShapeUtil.tsx | 1 - .../src/lib/shapes/shared/TextLabel.tsx | 5 +-- .../src/lib/shapes/shared/useEditableText.ts | 21 ++--------- .../src/lib/shapes/text/TextShapeUtil.tsx | 35 +++++++++++++++++++ 9 files changed, 45 insertions(+), 52 deletions(-) diff --git a/apps/examples/src/examples/speech-bubble/SpeechBubble/SpeechBubbleUtil.tsx b/apps/examples/src/examples/speech-bubble/SpeechBubble/SpeechBubbleUtil.tsx index 001739ce7..7d63acdc3 100644 --- a/apps/examples/src/examples/speech-bubble/SpeechBubble/SpeechBubbleUtil.tsx +++ b/apps/examples/src/examples/speech-bubble/SpeechBubble/SpeechBubbleUtil.tsx @@ -203,7 +203,6 @@ export class SpeechBubbleUtil extends ShapeUtil { text={text} labelColor={theme[color].solid} isSelected={isSelected} - disableTab wrap /> diff --git a/packages/tldraw/api-report.md b/packages/tldraw/api-report.md index e6e590898..d5bc01f14 100644 --- a/packages/tldraw/api-report.md +++ b/packages/tldraw/api-report.md @@ -2507,9 +2507,7 @@ export function useDefaultHelpers(): { export function useDialogs(): TLUiDialogsContextType; // @public (undocumented) -export function useEditableText(id: TLShapeId, type: string, text: string, opts?: { - disableTab: boolean; -}): { +export function useEditableText(id: TLShapeId, type: string, text: string): { handleBlur: () => void; handleChange: (e: React_2.ChangeEvent) => void; handleDoubleClick: (e: any) => any; diff --git a/packages/tldraw/api/api.json b/packages/tldraw/api/api.json index 9fb5b3376..a68690d00 100644 --- a/packages/tldraw/api/api.json +++ b/packages/tldraw/api/api.json @@ -15735,7 +15735,7 @@ }, { "kind": "Content", - "text": ") => {\n id: import(\"@tldraw/editor\")." + "text": ") => {\n id: " }, { "kind": "Reference", @@ -15819,7 +15819,7 @@ }, { "kind": "Content", - "text": ") => {\n id: import(\"@tldraw/editor\")." + "text": ") => {\n id: " }, { "kind": "Reference", @@ -15894,7 +15894,7 @@ }, { "kind": "Content", - "text": ") => {\n id: import(\"@tldraw/editor\")." + "text": ") => {\n id: " }, { "kind": "Reference", @@ -15903,7 +15903,7 @@ }, { "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", @@ -27480,14 +27480,6 @@ "kind": "Content", "text": "string" }, - { - "kind": "Content", - "text": ", opts?: " - }, - { - "kind": "Content", - "text": "{\n disableTab: boolean;\n}" - }, { "kind": "Content", "text": "): " @@ -27575,8 +27567,8 @@ ], "fileUrlPath": "packages/tldraw/src/lib/shapes/shared/useEditableText.ts", "returnTypeTokenRange": { - "startIndex": 9, - "endIndex": 26 + "startIndex": 7, + "endIndex": 24 }, "releaseTag": "Public", "overloadIndex": 1, @@ -27604,14 +27596,6 @@ "endIndex": 6 }, "isOptional": false - }, - { - "parameterName": "opts", - "parameterTypeTokenRange": { - "startIndex": 7, - "endIndex": 8 - }, - "isOptional": true } ], "name": "useEditableText" diff --git a/packages/tldraw/src/lib/shapes/arrow/components/ArrowTextLabel.tsx b/packages/tldraw/src/lib/shapes/arrow/components/ArrowTextLabel.tsx index a2bfd3915..f4f133c41 100644 --- a/packages/tldraw/src/lib/shapes/arrow/components/ArrowTextLabel.tsx +++ b/packages/tldraw/src/lib/shapes/arrow/components/ArrowTextLabel.tsx @@ -35,7 +35,6 @@ export const ArrowTextLabel = React.memo(function ArrowTextLabel({ labelColor={theme[labelColor].solid} textWidth={width} isSelected={isSelected} - disableTab style={{ transform: `translate(${position.x}px, ${position.y}px)`, }} diff --git a/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx b/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx index b249c3531..e9e884d0e 100644 --- a/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx +++ b/packages/tldraw/src/lib/shapes/geo/GeoShapeUtil.tsx @@ -421,7 +421,6 @@ export class GeoShapeUtil extends BaseBoxShapeUtil { text={text} isSelected={isSelected} labelColor={theme[props.labelColor].solid} - disableTab wrap /> diff --git a/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx b/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx index 4a0e1144f..89ae4a330 100644 --- a/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx +++ b/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx @@ -190,7 +190,6 @@ export class NoteShapeUtil extends ShapeUtil { isNote isSelected={isSelected} labelColor={theme[color].note.text} - disableTab wrap onKeyDown={handleKeyDown} /> diff --git a/packages/tldraw/src/lib/shapes/shared/TextLabel.tsx b/packages/tldraw/src/lib/shapes/shared/TextLabel.tsx index d34e009af..81adb2a9a 100644 --- a/packages/tldraw/src/lib/shapes/shared/TextLabel.tsx +++ b/packages/tldraw/src/lib/shapes/shared/TextLabel.tsx @@ -27,7 +27,6 @@ type TextLabelProps = { bounds?: Box isNote?: boolean isSelected: boolean - disableTab?: boolean onKeyDown?: (e: React.KeyboardEvent) => void classNamePrefix?: string style?: React.CSSProperties @@ -51,15 +50,13 @@ export const TextLabel = React.memo(function TextLabel({ onKeyDown: handleKeyDownCustom, classNamePrefix, style, - disableTab = false, textWidth, textHeight, }: TextLabelProps) { const { rInput, isEmpty, isEditing, isEditingAnything, ...editableTextRest } = useEditableText( id, type, - text, - { disableTab } + text ) const [initialText, setInitialText] = useState(text) diff --git a/packages/tldraw/src/lib/shapes/shared/useEditableText.ts b/packages/tldraw/src/lib/shapes/shared/useEditableText.ts index 696a2279f..fe25c8144 100644 --- a/packages/tldraw/src/lib/shapes/shared/useEditableText.ts +++ b/packages/tldraw/src/lib/shapes/shared/useEditableText.ts @@ -2,7 +2,6 @@ import { TLShapeId, TLUnknownShape, getPointerInfo, - preventDefault, stopEventPropagation, useEditor, useValue, @@ -11,12 +10,7 @@ import React, { useCallback, useEffect, useRef } from 'react' import { INDENT, TextHelpers } from './TextHelpers' /** @public */ -export function useEditableText( - id: TLShapeId, - type: string, - text: string, - opts = { disableTab: false } as { disableTab: boolean } -) { +export function useEditableText(id: TLShapeId, type: string, text: string) { const editor = useEditor() const rInput = useRef(null) @@ -134,20 +128,9 @@ export function useEditableText( } 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. diff --git a/packages/tldraw/src/lib/shapes/text/TextShapeUtil.tsx b/packages/tldraw/src/lib/shapes/text/TextShapeUtil.tsx index 7ff86dd9f..7378d16b6 100644 --- a/packages/tldraw/src/lib/shapes/text/TextShapeUtil.tsx +++ b/packages/tldraw/src/lib/shapes/text/TextShapeUtil.tsx @@ -7,18 +7,22 @@ import { SvgExportContext, TLOnEditEndHandler, TLOnResizeHandler, + TLShapeId, TLShapeUtilFlag, TLTextShape, Vec, WeakMapCache, getDefaultColorTheme, + preventDefault, textShapeMigrations, textShapeProps, toDomPrecision, useEditor, } from '@tldraw/editor' +import { useCallback } from 'react' import { useDefaultColorTheme } from '../shared/ShapeFill' import { SvgTextLabel } from '../shared/SvgTextLabel' +import { TextHelpers } from '../shared/TextHelpers' import { TextLabel } from '../shared/TextLabel' import { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from '../shared/default-shape-constants' import { getFontDefForExport } from '../shared/defaultStyleDefs' @@ -73,6 +77,7 @@ export class TextShapeUtil extends ShapeUtil { const { width, height } = this.getMinDimensions(shape) const isSelected = shape.id === this.editor.getOnlySelectedShapeId() const theme = useDefaultColorTheme() + const handleKeyDown = useTextShapeKeydownHandler(id) return ( { transformOrigin: 'top left', }} wrap + onKeyDown={handleKeyDown} /> ) } @@ -332,3 +338,32 @@ function getTextSize(editor: Editor, props: TLTextShape['props']) { height: Math.max(fontSize, result.h), } } + +function useTextShapeKeydownHandler(id: TLShapeId) { + const editor = useEditor() + + return useCallback( + (e: React.KeyboardEvent) => { + 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] + ) +}