fix: rely on native local edit textarea input
This commit is contained in:
parent
852498b6bb
commit
87a1514a0f
@ -235,12 +235,6 @@ type LocalEditRegionInteractionState = {
|
|||||||
startRect: NormalizedCropRect;
|
startRect: NormalizedCropRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
type LocalEditPromptCompositionSnapshot = {
|
|
||||||
end: number;
|
|
||||||
start: number;
|
|
||||||
value: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type AnglePreviewDragState = {
|
type AnglePreviewDragState = {
|
||||||
pointerId: number;
|
pointerId: number;
|
||||||
startX: number;
|
startX: number;
|
||||||
@ -2072,10 +2066,6 @@ export function ImageNode({
|
|||||||
Record<string, HTMLTextAreaElement | null>
|
Record<string, HTMLTextAreaElement | null>
|
||||||
>({});
|
>({});
|
||||||
const localEditPromptDraftRefs = useRef<Record<string, string>>({});
|
const localEditPromptDraftRefs = useRef<Record<string, string>>({});
|
||||||
const localEditPromptCompositionStartRefs = useRef<
|
|
||||||
Record<string, LocalEditPromptCompositionSnapshot | undefined>
|
|
||||||
>({});
|
|
||||||
const localEditPromptComposingRefs = useRef<Record<string, boolean>>({});
|
|
||||||
const localEditRegionsRef = useRef<LocalEditRegion[]>(localEditRegions);
|
const localEditRegionsRef = useRef<LocalEditRegion[]>(localEditRegions);
|
||||||
|
|
||||||
const updateNode = useCanvasStore((state) => state.updateNode);
|
const updateNode = useCanvasStore((state) => state.updateNode);
|
||||||
@ -2683,110 +2673,6 @@ export function ImageNode({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const restoreLocalEditPromptSelection = useCallback(
|
|
||||||
(regionId: string, position: number) => {
|
|
||||||
if (typeof window === "undefined") return;
|
|
||||||
window.requestAnimationFrame(() => {
|
|
||||||
const input = localEditPromptInputRefs.current[regionId];
|
|
||||||
if (!input) return;
|
|
||||||
const safePosition = clampNumber(position, 0, input.value.length);
|
|
||||||
input.setSelectionRange(safePosition, safePosition);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const applyLocalEditPromptTextEdit = useCallback(
|
|
||||||
(
|
|
||||||
regionId: string,
|
|
||||||
input: HTMLTextAreaElement,
|
|
||||||
inputEvent: InputEvent
|
|
||||||
) => {
|
|
||||||
const inputType = inputEvent.inputType || "";
|
|
||||||
if (!inputType || inputEvent.isComposing) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (inputType === "insertCompositionText") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentValue = localEditPromptDraftRefs.current[regionId] ?? input.value;
|
|
||||||
const selectionStart = input.selectionStart ?? currentValue.length;
|
|
||||||
const selectionEnd = input.selectionEnd ?? selectionStart;
|
|
||||||
const start = clampNumber(selectionStart, 0, currentValue.length);
|
|
||||||
const end = clampNumber(selectionEnd, start, currentValue.length);
|
|
||||||
let nextValue: string | null = null;
|
|
||||||
let nextCursor = start;
|
|
||||||
|
|
||||||
if (inputType.startsWith("insert")) {
|
|
||||||
const insertedText = inputEvent.data ?? "";
|
|
||||||
if (!insertedText) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
nextValue = `${currentValue.slice(0, start)}${insertedText}${currentValue.slice(end)}`;
|
|
||||||
nextCursor = start + insertedText.length;
|
|
||||||
} else if (inputType === "deleteContentBackward") {
|
|
||||||
if (start !== end) {
|
|
||||||
nextValue = `${currentValue.slice(0, start)}${currentValue.slice(end)}`;
|
|
||||||
nextCursor = start;
|
|
||||||
} else if (start > 0) {
|
|
||||||
nextValue = `${currentValue.slice(0, start - 1)}${currentValue.slice(end)}`;
|
|
||||||
nextCursor = start - 1;
|
|
||||||
} else {
|
|
||||||
nextValue = currentValue;
|
|
||||||
nextCursor = start;
|
|
||||||
}
|
|
||||||
} else if (inputType === "deleteContentForward") {
|
|
||||||
if (start !== end) {
|
|
||||||
nextValue = `${currentValue.slice(0, start)}${currentValue.slice(end)}`;
|
|
||||||
} else if (start < currentValue.length) {
|
|
||||||
nextValue = `${currentValue.slice(0, start)}${currentValue.slice(start + 1)}`;
|
|
||||||
} else {
|
|
||||||
nextValue = currentValue;
|
|
||||||
}
|
|
||||||
nextCursor = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextValue === null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateLocalEditPromptDraft(regionId, nextValue);
|
|
||||||
restoreLocalEditPromptSelection(regionId, nextCursor);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[restoreLocalEditPromptSelection, updateLocalEditPromptDraft]
|
|
||||||
);
|
|
||||||
|
|
||||||
const applyLocalEditPromptCompositionFallback = useCallback(
|
|
||||||
(
|
|
||||||
regionId: string,
|
|
||||||
input: HTMLTextAreaElement,
|
|
||||||
compositionText: string
|
|
||||||
) => {
|
|
||||||
const snapshot = localEditPromptCompositionStartRefs.current[regionId];
|
|
||||||
delete localEditPromptCompositionStartRefs.current[regionId];
|
|
||||||
if (!snapshot || !compositionText) {
|
|
||||||
updateLocalEditPromptDraft(regionId, input.value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const draftValue = localEditPromptDraftRefs.current[regionId] ?? input.value;
|
|
||||||
if (input.value !== snapshot.value || draftValue !== snapshot.value) {
|
|
||||||
updateLocalEditPromptDraft(regionId, input.value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextValue = `${snapshot.value.slice(0, snapshot.start)}${compositionText}${snapshot.value.slice(snapshot.end)}`;
|
|
||||||
updateLocalEditPromptDraft(regionId, nextValue);
|
|
||||||
restoreLocalEditPromptSelection(
|
|
||||||
regionId,
|
|
||||||
snapshot.start + compositionText.length
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[restoreLocalEditPromptSelection, updateLocalEditPromptDraft]
|
|
||||||
);
|
|
||||||
|
|
||||||
const refreshBoxCutoutMetrics = useCallback(() => {
|
const refreshBoxCutoutMetrics = useCallback(() => {
|
||||||
const imageElement = displayImageRef.current;
|
const imageElement = displayImageRef.current;
|
||||||
if (!imageElement) {
|
if (!imageElement) {
|
||||||
@ -3885,8 +3771,6 @@ export function ImageNode({
|
|||||||
delete next[regionId];
|
delete next[regionId];
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
delete localEditPromptCompositionStartRefs.current[regionId];
|
|
||||||
delete localEditPromptComposingRefs.current[regionId];
|
|
||||||
commitLocalEditRegions(
|
commitLocalEditRegions(
|
||||||
localEditRegionsRef.current.filter((region) => region.id !== regionId)
|
localEditRegionsRef.current.filter((region) => region.id !== regionId)
|
||||||
);
|
);
|
||||||
@ -3988,7 +3872,6 @@ export function ImageNode({
|
|||||||
|
|
||||||
const clearLocalEditRegions = useCallback(() => {
|
const clearLocalEditRegions = useCallback(() => {
|
||||||
localEditPromptDraftRefs.current = {};
|
localEditPromptDraftRefs.current = {};
|
||||||
localEditPromptCompositionStartRefs.current = {};
|
|
||||||
setLocalEditPromptDrafts({});
|
setLocalEditPromptDrafts({});
|
||||||
commitLocalEditRegions([]);
|
commitLocalEditRegions([]);
|
||||||
setEditingLocalEditRegionId(null);
|
setEditingLocalEditRegionId(null);
|
||||||
@ -8252,43 +8135,6 @@ export function ImageNode({
|
|||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}}
|
}}
|
||||||
onBeforeInput={(event) => {
|
|
||||||
if (
|
|
||||||
applyLocalEditPromptTextEdit(
|
|
||||||
region.id,
|
|
||||||
event.currentTarget,
|
|
||||||
event.nativeEvent as InputEvent
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onCompositionEnd={(event) => {
|
|
||||||
localEditPromptComposingRefs.current[region.id] =
|
|
||||||
false;
|
|
||||||
applyLocalEditPromptCompositionFallback(
|
|
||||||
region.id,
|
|
||||||
event.currentTarget,
|
|
||||||
event.data
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
onCompositionStart={(event) => {
|
|
||||||
localEditPromptComposingRefs.current[region.id] =
|
|
||||||
true;
|
|
||||||
localEditPromptCompositionStartRefs.current[
|
|
||||||
region.id
|
|
||||||
] = {
|
|
||||||
end:
|
|
||||||
event.currentTarget.selectionEnd ??
|
|
||||||
event.currentTarget.value.length,
|
|
||||||
start:
|
|
||||||
event.currentTarget.selectionStart ??
|
|
||||||
event.currentTarget.value.length,
|
|
||||||
value:
|
|
||||||
localEditPromptDraftRefs.current[region.id] ??
|
|
||||||
event.currentTarget.value,
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
onFocus={(event) => {
|
onFocus={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
setEditingLocalEditRegionId((current) =>
|
setEditingLocalEditRegionId((current) =>
|
||||||
@ -8304,8 +8150,7 @@ export function ImageNode({
|
|||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
const isComposing =
|
const isComposing =
|
||||||
event.nativeEvent.isComposing ||
|
event.nativeEvent.isComposing ||
|
||||||
event.key === "Process" ||
|
event.key === "Process";
|
||||||
localEditPromptComposingRefs.current[region.id];
|
|
||||||
if (isComposing) {
|
if (isComposing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user