mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-19 02:11:47 +01:00
This adds support for searching the terminal buffer using the `@xterm/addon-search` library. It also adds three options for searching: regex, case-sensitive, and whole-word. These can be included or excluded from the search options for `useSearch` depending on whether the search backend supports it.  I didn't like any of the Font Awesome icons for these toggles so until we have time to make some of our own icons that better match the Font Awesome style, I've appropriated VSCode's icons from their [codicons font](https://github.com/microsoft/vscode-codicons). To implement the toggle-able buttons for these options, I've introduced a new HeaderElem component, `ToggleIconButton`. This is styled similarly to `IconButton`, but when you hover over it, it also shows a highlighted background and when active, it shows as fully-opaque and with an accented border. Also removes the `useDismiss` behavior for the search box to better match behavior in other apps. Also fixes the scrollbar observer from my previous PR so it's wider.
65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
// Copyright 2023, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import { useLongClick } from "@/app/hook/useLongClick";
|
|
import { makeIconClass } from "@/util/util";
|
|
import clsx from "clsx";
|
|
import { atom, useAtom } from "jotai";
|
|
import { forwardRef, memo, useMemo, useRef } from "react";
|
|
import "./iconbutton.scss";
|
|
|
|
type IconButtonProps = { decl: IconButtonDecl; className?: string };
|
|
export const IconButton = memo(
|
|
forwardRef<HTMLButtonElement, IconButtonProps>(({ decl, className }, ref) => {
|
|
ref = ref ?? useRef<HTMLButtonElement>(null);
|
|
const spin = decl.iconSpin ?? false;
|
|
useLongClick(ref, decl.click, decl.longClick, decl.disabled);
|
|
const disabled = decl.disabled ?? false;
|
|
return (
|
|
<button
|
|
ref={ref}
|
|
className={clsx("wave-iconbutton", className, decl.className, {
|
|
disabled,
|
|
"no-action": decl.noAction,
|
|
})}
|
|
title={decl.title}
|
|
aria-label={decl.title}
|
|
style={{ color: decl.iconColor ?? "inherit" }}
|
|
disabled={disabled}
|
|
>
|
|
{typeof decl.icon === "string" ? <i className={makeIconClass(decl.icon, true, { spin })} /> : decl.icon}
|
|
</button>
|
|
);
|
|
})
|
|
);
|
|
|
|
type ToggleIconButtonProps = { decl: ToggleIconButtonDecl; className?: string };
|
|
|
|
export const ToggleIconButton = memo(
|
|
forwardRef<HTMLButtonElement, ToggleIconButtonProps>(({ decl, className }, ref) => {
|
|
const activeAtom = useMemo(() => decl.active ?? atom(false), [decl.active]);
|
|
const [active, setActive] = useAtom(activeAtom);
|
|
ref = ref ?? useRef<HTMLButtonElement>(null);
|
|
const spin = decl.iconSpin ?? false;
|
|
const title = `${decl.title}${active ? " (Active)" : ""}`;
|
|
const disabled = decl.disabled ?? false;
|
|
return (
|
|
<button
|
|
ref={ref}
|
|
className={clsx("wave-iconbutton", "toggle", className, decl.className, {
|
|
active,
|
|
disabled,
|
|
"no-action": decl.noAction,
|
|
})}
|
|
title={title}
|
|
aria-label={title}
|
|
style={{ color: decl.iconColor ?? "inherit" }}
|
|
onClick={() => setActive(!active)}
|
|
disabled={disabled}
|
|
>
|
|
{typeof decl.icon === "string" ? <i className={makeIconClass(decl.icon, true, { spin })} /> : decl.icon}
|
|
</button>
|
|
);
|
|
})
|
|
);
|