Skip to content

Commit c78eda4

Browse files
committed
fix: improve text edit
1 parent 2b789ae commit c78eda4

File tree

1 file changed

+59
-9
lines changed

1 file changed

+59
-9
lines changed

src/lib/components/element/text/Edit.tsx

+59-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { MouseEvent, RefObject, useEffect, useRef } from 'react';
1+
import { MouseEvent, RefObject, useCallback, useEffect, useRef, useState } from 'react';
22
import { TMonitor, useDrag, useDrop } from 'react-use-drag-and-drop';
3-
import { useObserverValue } from 'react-observing';
3+
import { useObserver, useObserverValue } from 'react-observing';
4+
import { useFrame } from 'react-frame-component';
45

56
import { TDraggableElement, TElement, TParentElement } from '../../../types';
67
import { useUiEditorContext } from '../../../UiEditorContext';
@@ -28,9 +29,10 @@ interface IEditProps {
2829
}
2930
export const Edit = ({ element, parents, onMouseOver, onMouseLeave, onSelect, onDragLeave, onDragOver, onDrop, onHoverBar, onSelectBar }: IEditProps) => {
3031
const elementRef = useRef<HTMLElement>(null);
32+
const { window, document } = useFrame();
3133

34+
const [text, setText] = useObserver(element.text);
3235
const name = useObserverValue(element.name);
33-
const text = useObserverValue(element.text);
3436
const id = useObserverValue(element.id);
3537

3638
const { onDragStart, onDragEnd } = useUiEditorContext();
@@ -39,6 +41,14 @@ export const Edit = ({ element, parents, onMouseOver, onMouseLeave, onSelect, on
3941
const { hoveredId } = useHoverBar();
4042

4143

44+
const [editable, setEditable] = useState(false);
45+
useEffect(() => {
46+
if (!elementRef.current || !editable) return;
47+
elementRef.current.focus();
48+
onSelectBar(element, null)
49+
}, [editable, onSelectBar]);
50+
51+
4252
useMatchEffect({
4353
value: hoveredId,
4454
matchWidthValue: element?.id,
@@ -49,16 +59,17 @@ export const Edit = ({ element, parents, onMouseOver, onMouseLeave, onSelect, on
4959
value: selectedId,
5060
matchWidthValue: element?.id,
5161
effect: () => onSelectBar(element, elementRef.current),
52-
}, [selectedId, element]);
62+
}, [selectedId, element, text]);
5363

5464

5565
const { isDragging, preview } = useDrag<TDraggableElement>({
5666
id,
67+
canDrag: !editable,
5768
element: elementRef,
5869
data: { element, parents, },
5970
start: () => { onDragStart() },
6071
end: () => { hideInsertBar(); onDragEnd(); },
61-
}, [id, element, parents, hideInsertBar, onDragStart, onDragEnd]);
72+
}, [id, editable, element, parents, hideInsertBar, onDragStart, onDragEnd]);
6273
useEffect(() => {
6374
preview(
6475
() => getCustomDragLayer(name),
@@ -76,19 +87,58 @@ export const Edit = ({ element, parents, onMouseOver, onMouseLeave, onSelect, on
7687
}, [element, parents, onDrop, onDragOver, onDragLeave]);
7788

7889

90+
const handleFocus = useCallback((e: React.FormEvent<HTMLSpanElement>) => {
91+
if (!window || !document) return;
92+
93+
const selection = window.getSelection();
94+
if (!selection) return;
95+
96+
const range = document.createRange();
97+
const span = e.currentTarget;
98+
99+
range.selectNodeContents(span);
100+
selection.removeAllRanges();
101+
selection.addRange(range);
102+
}, [window, document]);
103+
104+
const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLSpanElement>) => {
105+
e.stopPropagation();
106+
107+
if (e.code === 'Escape' || e.code === 'Enter' || e.code === 'NumpadEnter') {
108+
setEditable(false);
109+
onSelectBar(element, e.currentTarget)
110+
}
111+
}, [onSelectBar, element]);
112+
113+
const handleBlur = useCallback((e: React.FocusEvent<HTMLSpanElement>) => {
114+
setEditable(false);
115+
setText(e.currentTarget.innerText);
116+
onSelectBar(element, e.currentTarget)
117+
}, [onSelectBar, element]);
118+
119+
79120
return (
80121
<span
81-
children={text}
122+
contentEditable={editable}
123+
dangerouslySetInnerHTML={{ __html: text }}
124+
125+
onBlur={handleBlur}
126+
onFocus={handleFocus}
127+
onKeyDown={handleKeyDown}
128+
onDoubleClick={() => setEditable(true)}
129+
82130
ref={elementRef}
83131
onMouseLeave={onMouseLeave}
84-
onClick={e => onSelect(e, element)}
85-
onMouseOver={e => onMouseOver(e, element, elementRef.current)}
132+
onClick={e => !editable ? onSelect(e, element) : e.stopPropagation()}
133+
onMouseOver={e => !editable ? onMouseOver(e, element, elementRef.current) : e.stopPropagation()}
86134
style={{
87135
resize: 'none',
88136
cursor: 'default',
89-
userSelect: 'none',
90137
pointerEvents: 'all',
138+
91139
opacity: isDragging ? 0.5 : undefined,
140+
borderRadius: editable ? 4 : undefined,
141+
boxShadow: editable ? '0 0 6px 2px orange' : undefined,
92142
}}
93143
/>
94144
);

0 commit comments

Comments
 (0)