Major mini editor refactoring (#225)
Replaces most editing components with CM components, enabling vim mode and completions everywhere Fixes #205 Fixes #221 Fixes #222 Fixes #223
This commit is contained in:
+51
-48
@@ -1,8 +1,15 @@
|
||||
import { useEffect, useRef, useState } from "../deps.ts";
|
||||
import {
|
||||
CompletionContext,
|
||||
CompletionResult,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "../deps.ts";
|
||||
import { FilterOption } from "../../common/types.ts";
|
||||
import fuzzysort from "https://esm.sh/fuzzysort@2.0.1";
|
||||
import { FunctionalComponent } from "https://esm.sh/v99/preact@10.11.3/src/index";
|
||||
import { FeatherProps } from "https://esm.sh/v99/preact-feather@4.2.1/dist/types";
|
||||
import { MiniEditor } from "./mini_editor.tsx";
|
||||
|
||||
function magicSorter(a: FilterOption, b: FilterOption): number {
|
||||
if (a.orderId && b.orderId) {
|
||||
@@ -56,6 +63,9 @@ export function FilterList({
|
||||
label,
|
||||
onSelect,
|
||||
onKeyPress,
|
||||
completer,
|
||||
vimMode,
|
||||
darkMode,
|
||||
allowNew = false,
|
||||
helpText = "",
|
||||
completePrefix,
|
||||
@@ -67,13 +77,15 @@ export function FilterList({
|
||||
label: string;
|
||||
onKeyPress?: (key: string, currentText: string) => void;
|
||||
onSelect: (option: FilterOption | undefined) => void;
|
||||
vimMode: boolean;
|
||||
darkMode: boolean;
|
||||
completer: (context: CompletionContext) => Promise<CompletionResult | null>;
|
||||
allowNew?: boolean;
|
||||
completePrefix?: string;
|
||||
helpText: string;
|
||||
newHint?: string;
|
||||
icon?: FunctionalComponent<FeatherProps>;
|
||||
}) {
|
||||
const searchBoxRef = useRef<HTMLInputElement>(null);
|
||||
const [text, setText] = useState("");
|
||||
const [matchingOptions, setMatchingOptions] = useState(
|
||||
fuzzySorter("", options),
|
||||
@@ -93,7 +105,7 @@ export function FilterList({
|
||||
}
|
||||
setMatchingOptions(results);
|
||||
|
||||
setText(originalPhrase);
|
||||
// setText(originalPhrase);
|
||||
setSelectionOption(0);
|
||||
}
|
||||
|
||||
@@ -101,12 +113,9 @@ export function FilterList({
|
||||
updateFilter(text);
|
||||
}, [options]);
|
||||
|
||||
useEffect(() => {
|
||||
searchBoxRef.current!.focus();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
function closer() {
|
||||
console.log("Invoking closer");
|
||||
onSelect(undefined);
|
||||
}
|
||||
|
||||
@@ -117,73 +126,67 @@ export function FilterList({
|
||||
};
|
||||
}, []);
|
||||
|
||||
let exiting = false;
|
||||
|
||||
const returnEl = (
|
||||
<div className="sb-filter-wrapper">
|
||||
<div className="sb-filter-box">
|
||||
<div className="sb-header">
|
||||
<label>{label}</label>
|
||||
<input
|
||||
type="text"
|
||||
value={text}
|
||||
placeholder={placeholder}
|
||||
ref={searchBoxRef}
|
||||
onBlur={(e) => {
|
||||
if (!exiting && searchBoxRef.current) {
|
||||
searchBoxRef.current.focus();
|
||||
}
|
||||
<MiniEditor
|
||||
text={text}
|
||||
vimMode={vimMode}
|
||||
vimStartInInsertMode={true}
|
||||
focus={true}
|
||||
darkMode={darkMode}
|
||||
completer={completer}
|
||||
placeholderText={placeholder}
|
||||
onEnter={() => {
|
||||
onSelect(matchingOptions[selectedOption]);
|
||||
return true;
|
||||
}}
|
||||
onKeyUp={(e) => {
|
||||
onEscape={() => {
|
||||
onSelect(undefined);
|
||||
}}
|
||||
onChange={(text) => {
|
||||
updateFilter(text);
|
||||
}}
|
||||
onKeyUp={(view, e) => {
|
||||
if (onKeyPress) {
|
||||
onKeyPress(e.key, text);
|
||||
onKeyPress(e.key, view.state.sliceDoc());
|
||||
}
|
||||
switch (e.key) {
|
||||
case "ArrowUp":
|
||||
setSelectionOption(Math.max(0, selectedOption - 1));
|
||||
break;
|
||||
return true;
|
||||
case "ArrowDown":
|
||||
setSelectionOption(
|
||||
Math.min(matchingOptions.length - 1, selectedOption + 1),
|
||||
);
|
||||
break;
|
||||
case "Enter":
|
||||
exiting = true;
|
||||
onSelect(matchingOptions[selectedOption]);
|
||||
e.preventDefault();
|
||||
break;
|
||||
return true;
|
||||
case "PageUp":
|
||||
setSelectionOption(Math.max(0, selectedOption - 5));
|
||||
break;
|
||||
return true;
|
||||
case "PageDown":
|
||||
setSelectionOption(Math.max(0, selectedOption + 5));
|
||||
break;
|
||||
return true;
|
||||
case "Home":
|
||||
setSelectionOption(0);
|
||||
break;
|
||||
return true;
|
||||
case "End":
|
||||
setSelectionOption(matchingOptions.length - 1);
|
||||
break;
|
||||
case "Escape":
|
||||
exiting = true;
|
||||
onSelect(undefined);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case " ":
|
||||
if (completePrefix && !text) {
|
||||
return true;
|
||||
case " ": {
|
||||
const text = view.state.sliceDoc();
|
||||
if (completePrefix && text === " ") {
|
||||
console.log("Doing the complete thing");
|
||||
setText(completePrefix);
|
||||
updateFilter(completePrefix);
|
||||
e.preventDefault();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
updateFilter((e.target as any).value);
|
||||
}
|
||||
}
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@@ -204,8 +207,8 @@ export function FilterList({
|
||||
setSelectionOption(idx);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
exiting = true;
|
||||
console.log("Selecting", option);
|
||||
e.stopPropagation();
|
||||
onSelect(option);
|
||||
}}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user