mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-22 02:41:23 +01:00
focus/key handling for directory preview (#291)
This commit is contained in:
parent
a104a6e446
commit
53d3ad04b7
@ -123,6 +123,9 @@ function appSelectionChange(e: Event) {
|
||||
}
|
||||
|
||||
function AppFocusHandler() {
|
||||
return null;
|
||||
|
||||
// for debugging
|
||||
React.useEffect(() => {
|
||||
document.addEventListener("focusin", appFocusIn);
|
||||
document.addEventListener("focusout", appFocusOut);
|
||||
|
@ -232,6 +232,7 @@ const BlockFull = React.memo(({ nodeModel, viewModel }: FullBlockProps) => {
|
||||
value=""
|
||||
ref={focusElemRef}
|
||||
id={`${nodeModel.blockId}-dummy-focus`}
|
||||
className="dummy-focus"
|
||||
onChange={() => {}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -18,7 +18,6 @@ import { WshServer } from "@/app/store/wshserver";
|
||||
import { MagnifyIcon } from "@/element/magnify";
|
||||
import { NodeModel } from "@/layout/index";
|
||||
import * as keyutil from "@/util/keyutil";
|
||||
import { checkKeyPressed, keydownWrapper } from "@/util/keyutil";
|
||||
import * as util from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import * as jotai from "jotai";
|
||||
@ -284,19 +283,7 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
||||
return jotai.atom(false);
|
||||
}) as jotai.PrimitiveAtom<boolean>;
|
||||
const connBtnRef = React.useRef<HTMLDivElement>();
|
||||
|
||||
const viewIconElem = getViewIconElem(viewIconUnion, blockData);
|
||||
|
||||
function handleKeyDown(waveEvent: WaveKeyboardEvent): boolean {
|
||||
if (checkKeyPressed(waveEvent, "Cmd:m")) {
|
||||
nodeModel.toggleMagnify();
|
||||
return true;
|
||||
}
|
||||
if (viewModel?.keyDownHandler) {
|
||||
return viewModel.keyDownHandler(waveEvent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const innerStyle: React.CSSProperties = {};
|
||||
if (!preview && customBg?.bg != null) {
|
||||
innerStyle.background = customBg.bg;
|
||||
@ -319,7 +306,6 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
||||
onClick={blockModel?.onClick}
|
||||
onFocusCapture={blockModel?.onFocusCapture}
|
||||
ref={blockModel?.blockRef}
|
||||
onKeyDown={keydownWrapper(handleKeyDown)}
|
||||
>
|
||||
<BlockMask nodeModel={nodeModel} />
|
||||
<div className="block-frame-default-inner" style={innerStyle}>
|
||||
|
@ -42,6 +42,9 @@ function shouldDispatchToBlock(): boolean {
|
||||
const activeElem = document.activeElement;
|
||||
if (activeElem != null && activeElem instanceof HTMLElement) {
|
||||
if (activeElem.tagName == "INPUT" || activeElem.tagName == "TEXTAREA") {
|
||||
if (activeElem.classList.contains("dummy-focus")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (activeElem.contentEditable == "true") {
|
||||
@ -134,7 +137,23 @@ async function handleCmdN() {
|
||||
}
|
||||
|
||||
function appHandleKeyDown(waveEvent: WaveKeyboardEvent): boolean {
|
||||
return handleGlobalWaveKeyboardEvents(waveEvent);
|
||||
const handled = handleGlobalWaveKeyboardEvents(waveEvent);
|
||||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
const layoutModel = getLayoutModelForActiveTab();
|
||||
const focusedNode = globalStore.get(layoutModel.focusedNode);
|
||||
const blockId = focusedNode?.data?.blockId;
|
||||
if (blockId != null && shouldDispatchToBlock()) {
|
||||
const viewModel = getViewModel(blockId);
|
||||
if (viewModel?.keyDownHandler) {
|
||||
const handledByBlock = viewModel.keyDownHandler(waveEvent);
|
||||
if (handledByBlock) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function registerControlShiftStateUpdateHandler() {
|
||||
@ -149,18 +168,7 @@ function registerControlShiftStateUpdateHandler() {
|
||||
|
||||
function registerElectronReinjectKeyHandler() {
|
||||
getApi().onReinjectKey((event: WaveKeyboardEvent) => {
|
||||
console.log("reinject key event", event);
|
||||
const handled = handleGlobalWaveKeyboardEvents(event);
|
||||
if (handled) {
|
||||
return;
|
||||
}
|
||||
const layoutModel = getLayoutModelForActiveTab();
|
||||
const focusedNode = globalStore.get(layoutModel.focusedNode);
|
||||
const blockId = focusedNode?.data?.blockId;
|
||||
if (blockId != null && shouldDispatchToBlock()) {
|
||||
const viewModel = getViewModel(blockId);
|
||||
viewModel?.keyDownHandler?.(event);
|
||||
}
|
||||
appHandleKeyDown(event);
|
||||
});
|
||||
}
|
||||
|
||||
@ -200,6 +208,14 @@ function registerGlobalKeys() {
|
||||
genericClose(tabId);
|
||||
return true;
|
||||
});
|
||||
globalKeyMap.set("Cmd:m", () => {
|
||||
const layoutModel = getLayoutModelForActiveTab();
|
||||
const focusedNode = globalStore.get(layoutModel.focusedNode);
|
||||
if (focusedNode != null) {
|
||||
layoutModel.magnifyNodeToggle(focusedNode.id);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
globalKeyMap.set("Ctrl:Shift:ArrowUp", () => {
|
||||
const tabId = globalStore.get(atoms.activeTabId);
|
||||
switchBlockInDirection(tabId, NavigateDirection.Up);
|
||||
|
@ -104,6 +104,7 @@ const Tab = React.memo(
|
||||
const curLen = Array.from(editableRef.current.innerText).length;
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (editableRef.current.innerText.trim() === "") {
|
||||
editableRef.current.innerText = originalName;
|
||||
}
|
||||
@ -111,8 +112,11 @@ const Tab = React.memo(
|
||||
} else if (event.key === "Escape") {
|
||||
editableRef.current.innerText = originalName;
|
||||
editableRef.current.blur();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else if (curLen >= 10 && !["Backspace", "Delete", "ArrowLeft", "ArrowRight"].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -574,8 +574,8 @@ function DirectoryPreview({ fileNameAtom, model }: DirectoryPreviewProps) {
|
||||
setFilteredData(filtered);
|
||||
}, [unfilteredData, showHiddenFiles, searchText]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(waveEvent: WaveKeyboardEvent): boolean => {
|
||||
useEffect(() => {
|
||||
model.directoryKeyDownHandler = (waveEvent: WaveKeyboardEvent): boolean => {
|
||||
if (keyutil.checkKeyPressed(waveEvent, "Escape")) {
|
||||
setSearchText("");
|
||||
return;
|
||||
@ -596,9 +596,23 @@ function DirectoryPreview({ fileNameAtom, model }: DirectoryPreviewProps) {
|
||||
setSearchText("");
|
||||
return true;
|
||||
}
|
||||
},
|
||||
[filteredData, setFocusIndex, selectedPath]
|
||||
);
|
||||
if (keyutil.checkKeyPressed(waveEvent, "Backspace")) {
|
||||
if (searchText.length == 0) {
|
||||
return true;
|
||||
}
|
||||
setSearchText((current) => current.slice(0, -1));
|
||||
return true;
|
||||
}
|
||||
if (keyutil.isCharacterKeyEvent(waveEvent)) {
|
||||
setSearchText((current) => current + waveEvent.key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return () => {
|
||||
model.directoryKeyDownHandler = null;
|
||||
};
|
||||
}, [filteredData, selectedPath]);
|
||||
|
||||
useEffect(() => {
|
||||
if (filteredData.length != 0 && focusIndex > filteredData.length - 1) {
|
||||
@ -606,14 +620,6 @@ function DirectoryPreview({ fileNameAtom, model }: DirectoryPreviewProps) {
|
||||
}
|
||||
}, [filteredData]);
|
||||
|
||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||
React.useEffect(() => {
|
||||
model.directoryInputElem = inputRef.current;
|
||||
return () => {
|
||||
model.directoryInputElem = null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="dir-table-container"
|
||||
@ -621,19 +627,8 @@ function DirectoryPreview({ fileNameAtom, model }: DirectoryPreviewProps) {
|
||||
const event = e as React.ChangeEvent<HTMLInputElement>;
|
||||
setSearchText(event.target.value.toLowerCase());
|
||||
}}
|
||||
onKeyDownCapture={(e) => keyutil.keydownWrapper(handleKeyDown)(e)}
|
||||
onFocusCapture={() => document.getSelection().collapseToEnd()}
|
||||
// onFocusCapture={() => document.getSelection().collapseToEnd()}
|
||||
>
|
||||
<div className="dir-table-search-line">
|
||||
<input
|
||||
type="text"
|
||||
className="dir-table-search-box"
|
||||
ref={inputRef}
|
||||
onChange={() => {}} //for nuisance warnings
|
||||
maxLength={400}
|
||||
value={searchText}
|
||||
/>
|
||||
</div>
|
||||
<DirectoryTable
|
||||
model={model}
|
||||
data={filteredData}
|
||||
|
@ -60,7 +60,7 @@ export class PreviewModel implements ViewModel {
|
||||
showHiddenFiles: jotai.PrimitiveAtom<boolean>;
|
||||
refreshVersion: jotai.PrimitiveAtom<number>;
|
||||
refreshCallback: () => void;
|
||||
directoryInputElem: HTMLInputElement;
|
||||
directoryKeyDownHandler: (waveEvent: WaveKeyboardEvent) => boolean;
|
||||
|
||||
setPreviewFileName(fileName: string) {
|
||||
services.ObjectService.UpdateObjectMeta(`block:${this.blockId}`, { file: fileName });
|
||||
@ -416,10 +416,6 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
|
||||
giveFocus(): boolean {
|
||||
if (this.directoryInputElem) {
|
||||
this.directoryInputElem.focus({ preventScroll: true });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -437,6 +433,12 @@ export class PreviewModel implements ViewModel {
|
||||
this.goParentDirectory();
|
||||
return true;
|
||||
}
|
||||
if (this.directoryKeyDownHandler) {
|
||||
const handled = this.directoryKeyDownHandler(e);
|
||||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { TypingIndicator } from "@/app/element/typingindicator";
|
||||
import { WOS, atoms, fetchWaveFile, getUserName, globalStore } from "@/store/global";
|
||||
import * as services from "@/store/services";
|
||||
import { WshServer } from "@/store/wshserver";
|
||||
import { adaptFromReactOrNativeKeyEvent, checkKeyPressed } from "@/util/keyutil";
|
||||
import * as util from "@/util/util";
|
||||
import * as jotai from "jotai";
|
||||
import type { OverlayScrollbars } from "overlayscrollbars";
|
||||
@ -586,12 +587,13 @@ const WaveAi = ({ model }: { model: WaveAiModel; blockId: string }) => {
|
||||
};
|
||||
|
||||
const handleTextAreaKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (e.key === "Enter") {
|
||||
const waveEvent = adaptFromReactOrNativeKeyEvent(e);
|
||||
if (checkKeyPressed(waveEvent, "Enter")) {
|
||||
e.preventDefault();
|
||||
handleEnterKeyPressed();
|
||||
} else if (e.key === "ArrowUp") {
|
||||
} else if (checkKeyPressed(waveEvent, "ArrowUp")) {
|
||||
handleArrowUpPressed(e);
|
||||
} else if (e.key === "ArrowDown") {
|
||||
} else if (checkKeyPressed(waveEvent, "ArrowDown")) {
|
||||
handleArrowDownPressed(e);
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user