From 52f0c14c78dff585b95882ef173ca01e8417ba55 Mon Sep 17 00:00:00 2001 From: Zef Hemel Date: Wed, 21 Dec 2022 16:08:51 +0100 Subject: [PATCH] Fixes #207 --- web/components/basic_modals.tsx | 123 +++++++++++++++ web/components/filter.tsx | 4 +- web/editor.tsx | 158 +++++++++++++------- web/reducer.ts | 30 ++++ web/styles/main.scss | 2 +- web/styles/{filter_box.scss => modals.scss} | 19 ++- web/styles/theme.scss | 16 +- web/syscalls/editor.ts | 8 +- web/types.ts | 28 ++++ 9 files changed, 312 insertions(+), 76 deletions(-) create mode 100644 web/components/basic_modals.tsx rename web/styles/{filter_box.scss => modals.scss} (82%) diff --git a/web/components/basic_modals.tsx b/web/components/basic_modals.tsx new file mode 100644 index 00000000..b33c0e33 --- /dev/null +++ b/web/components/basic_modals.tsx @@ -0,0 +1,123 @@ +import type { CompletionContext, CompletionResult } from "../deps.ts"; +import { useRef, useState } from "../deps.ts"; +import { MiniEditor } from "./mini_editor.tsx"; + +export function Prompt({ + message, + defaultValue, + vimMode, + darkMode, + completer, + callback, +}: { + message: string; + defaultValue?: string; + vimMode: boolean; + darkMode: boolean; + completer: (context: CompletionContext) => Promise; + callback: (value?: string) => void; +}) { + const [text, setText] = useState(defaultValue || ""); + const returnEl = ( +
+
+
+ + { + callback(text); + return true; + }} + onEscape={() => { + callback(); + }} + onChange={(text) => { + setText(text); + }} + /> + + +
+
+
+ ); + + return returnEl; +} + +export function Confirm({ + message, + callback, +}: { + message: string; + callback: (value: boolean) => void; +}) { + const okButtonRef = useRef(null); + setTimeout(() => { + okButtonRef.current?.focus(); + }); + const returnEl = ( +
+
+
{ + e.stopPropagation(); + e.preventDefault(); + switch (e.key) { + case "Enter": + callback(true); + break; + case "Escape": + callback(false); + break; + } + }} + > + +
+ + +
+
+
+
+ ); + + return returnEl; +} diff --git a/web/components/filter.tsx b/web/components/filter.tsx index d0fd7d25..691a64bf 100644 --- a/web/components/filter.tsx +++ b/web/components/filter.tsx @@ -127,8 +127,8 @@ export function FilterList({ }, []); const returnEl = ( -
-
+
+
{ + return new Promise((resolve) => { + this.viewDispatch({ + type: "show-prompt", + message, + defaultValue, + callback: (value: string | undefined) => { + this.viewDispatch({ type: "hide-prompt" }); + this.focus(); + resolve(value); + }, + }); + }); + } + + confirm( + message: string, + ): Promise { + return new Promise((resolve) => { + this.viewDispatch({ + type: "show-confirm", + message, + callback: (value: boolean) => { + this.viewDispatch({ type: "hide-confirm" }); + this.focus(); + resolve(value); + }, + }); + }); + } + dispatchAppEvent(name: AppEvent, data?: any): Promise { return this.eventHook.dispatchEvent(name, data); } @@ -924,6 +946,28 @@ export class Editor { onSelect={viewState.filterBoxOnSelect} /> )} + {viewState.showPrompt && ( + { + dispatch({ type: "hide-prompt" }); + viewState.promptCallback!(value); + }} + /> + )} + {viewState.showConfirm && ( + { + dispatch({ type: "hide-confirm" }); + viewState.confirmCallback!(value); + }} + /> + )} { - return prompt(message, defaultValue); + ): Promise => { + return editor.prompt(message, defaultValue); }, "editor.confirm": ( _ctx, message: string, - ): boolean => { - return confirm(message); + ): Promise => { + return editor.confirm(message); }, "editor.getUiOption": (_ctx, key: string): any => { return (editor.viewState.uiOptions as any)[key]; diff --git a/web/types.ts b/web/types.ts index 1463cb43..d730684b 100644 --- a/web/types.ts +++ b/web/types.ts @@ -42,12 +42,24 @@ export type AppViewState = { forcedROMode: boolean; }; + // Filter box showFilterBox: boolean; filterBoxLabel: string; filterBoxPlaceHolder: string; filterBoxOptions: FilterOption[]; filterBoxHelpText: string; filterBoxOnSelect: (option: FilterOption | undefined) => void; + + // Prompt + showPrompt: boolean; + promptMessage?: string; + promptDefaultValue?: string; + promptCallback?: (value: string | undefined) => void; + + // Confirm + showConfirm: boolean; + confirmMessage?: string; + confirmCallback?: (value: boolean) => void; }; export const initialViewState: AppViewState = { @@ -78,6 +90,9 @@ export const initialViewState: AppViewState = { filterBoxOnSelect: () => {}, filterBoxOptions: [], filterBoxPlaceHolder: "", + + showPrompt: false, + showConfirm: false, }; export type Action = @@ -112,4 +127,17 @@ export type Action = onSelect: (option: FilterOption | undefined) => void; } | { type: "hide-filterbox" } + | { + type: "show-prompt"; + message: string; + defaultValue: string; + callback: (value: string | undefined) => void; + } + | { type: "hide-prompt" } + | { + type: "show-confirm"; + message: string; + callback: (value: boolean) => void; + } + | { type: "hide-confirm" } | { type: "set-ui-option"; key: string; value: any };