Buckets:
| import { TextareaRenderable, TextAttributes } from "@opentui/core" | |
| import { useTheme } from "../context/theme" | |
| import { useDialog, type DialogContext } from "./dialog" | |
| import { Show, createEffect, createSignal, onMount, type JSX } from "solid-js" | |
| import { Spinner } from "../component/spinner" | |
| import { useTuiConfig } from "../config" | |
| import { useBindings, useCommandShortcut } from "../keymap" | |
| export type DialogPromptProps = { | |
| title: string | |
| description?: () => JSX.Element | |
| placeholder?: string | |
| value?: string | |
| busy?: boolean | |
| busyText?: string | |
| onConfirm?: (value: string) => void | |
| onCancel?: () => void | |
| } | |
| export function DialogPrompt(props: DialogPromptProps) { | |
| const dialog = useDialog() | |
| const { theme } = useTheme() | |
| const tuiConfig = useTuiConfig() | |
| const submitShortcut = useCommandShortcut("dialog.prompt.submit") | |
| const [textareaTarget, setTextareaTarget] = createSignal<TextareaRenderable>() | |
| let textarea: TextareaRenderable | |
| function confirm() { | |
| if (props.busy) return | |
| props.onConfirm?.(textarea.plainText) | |
| } | |
| useBindings(() => ({ | |
| target: textareaTarget, | |
| enabled: textareaTarget() !== undefined && !props.busy, | |
| // Dialog form semantics must win over the global managed textarea input layer. | |
| priority: 1, | |
| commands: [ | |
| { | |
| name: "dialog.prompt.submit", | |
| title: "Submit dialog prompt", | |
| category: "Dialog", | |
| run: confirm, | |
| }, | |
| ], | |
| bindings: tuiConfig.keybinds.gather("dialog.prompt", ["dialog.prompt.submit"]), | |
| })) | |
| onMount(() => { | |
| dialog.setSize("medium") | |
| setTimeout(() => { | |
| if (!textarea || textarea.isDestroyed) return | |
| if (props.busy) return | |
| textarea.focus() | |
| }, 1) | |
| textarea.gotoLineEnd() | |
| }) | |
| createEffect(() => { | |
| if (!textarea || textarea.isDestroyed) return | |
| const traits = props.busy | |
| ? { | |
| suspend: true, | |
| status: "BUSY", | |
| } | |
| : {} | |
| textarea.traits = traits | |
| if (props.busy) { | |
| textarea.blur() | |
| return | |
| } | |
| textarea.focus() | |
| }) | |
| return ( | |
| <box paddingLeft={2} paddingRight={2} gap={1}> | |
| <box flexDirection="row" justifyContent="space-between"> | |
| <text attributes={TextAttributes.BOLD} fg={theme.text}> | |
| {props.title} | |
| </text> | |
| <text fg={theme.textMuted} onMouseUp={() => dialog.clear()}> | |
| esc | |
| </text> | |
| </box> | |
| <box gap={1}> | |
| {props.description} | |
| <textarea | |
| height={3} | |
| ref={(val: TextareaRenderable) => { | |
| textarea = val | |
| setTextareaTarget(val) | |
| }} | |
| initialValue={props.value} | |
| placeholder={props.placeholder ?? "Enter text"} | |
| placeholderColor={theme.textMuted} | |
| textColor={props.busy ? theme.textMuted : theme.text} | |
| focusedTextColor={props.busy ? theme.textMuted : theme.text} | |
| cursorColor={props.busy ? theme.backgroundElement : theme.text} | |
| /> | |
| <Show when={props.busy}> | |
| <Spinner color={theme.textMuted}>{props.busyText ?? "Working..."}</Spinner> | |
| </Show> | |
| </box> | |
| <box paddingBottom={1} gap={1} flexDirection="row"> | |
| <Show when={!props.busy} fallback={<text fg={theme.textMuted}>processing...</text>}> | |
| <Show when={submitShortcut()}> | |
| <text fg={theme.text}> | |
| {submitShortcut()} <span style={{ fg: theme.textMuted }}>submit</span> | |
| </text> | |
| </Show> | |
| </Show> | |
| </box> | |
| </box> | |
| ) | |
| } | |
| DialogPrompt.show = (dialog: DialogContext, title: string, options?: Omit<DialogPromptProps, "title">) => { | |
| return new Promise<string | null>((resolve) => { | |
| dialog.replace( | |
| () => ( | |
| <DialogPrompt title={title} {...options} onConfirm={(value) => resolve(value)} onCancel={() => resolve(null)} /> | |
| ), | |
| () => resolve(null), | |
| ) | |
| }) | |
| } | |
Xet Storage Details
- Size:
- 3.86 kB
- Xet hash:
- 8279e7799924a5cb7bae38427fa8ef987fc7b9edc58121ae53bdf41a110b595b
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.