mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-08 19:38:51 +01:00
da2291f889
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. ![image](https://github.com/user-attachments/assets/e0b7e2ed-641b-463f-94a2-f24969fb3b06) 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.
153 lines
4.7 KiB
TypeScript
153 lines
4.7 KiB
TypeScript
// Copyright 2024, Command Line Inc.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
import { useSetAtom } from "jotai";
|
|
import { useEffect } from "react";
|
|
import { Popover } from "./popover";
|
|
import { Search, useSearch } from "./search";
|
|
|
|
const meta: Meta<typeof Search> = {
|
|
title: "Elements/Search",
|
|
component: Search,
|
|
args: {},
|
|
};
|
|
|
|
export default meta;
|
|
type Story = StoryObj<typeof Popover>;
|
|
|
|
export const Default: Story = {
|
|
render: (args) => {
|
|
const props = useSearch();
|
|
const setIsOpen = useSetAtom<boolean, [boolean], void>(props.isOpen);
|
|
useEffect(() => {
|
|
setIsOpen(true);
|
|
}, []);
|
|
return (
|
|
<div
|
|
className="viewbox"
|
|
ref={props.anchorRef as React.RefObject<HTMLDivElement>}
|
|
style={{
|
|
border: "2px solid black",
|
|
width: "100%",
|
|
height: "200px",
|
|
background: "var(--main-bg-color)",
|
|
}}
|
|
>
|
|
<Search {...args} {...props} />
|
|
</div>
|
|
);
|
|
},
|
|
args: {},
|
|
};
|
|
|
|
export const AdditionalButtons: Story = {
|
|
render: (args) => {
|
|
const props = useSearch({ regex: true, caseSensitive: true, wholeWord: true });
|
|
const setIsOpen = useSetAtom<boolean, [boolean], void>(props.isOpen);
|
|
useEffect(() => {
|
|
setIsOpen(true);
|
|
}, []);
|
|
return (
|
|
<div
|
|
className="viewbox"
|
|
ref={props.anchorRef as React.RefObject<HTMLDivElement>}
|
|
style={{
|
|
border: "2px solid black",
|
|
width: "100%",
|
|
height: "200px",
|
|
background: "var(--main-bg-color)",
|
|
}}
|
|
>
|
|
<Search {...args} {...props} />
|
|
</div>
|
|
);
|
|
},
|
|
args: {},
|
|
};
|
|
|
|
export const Results10: Story = {
|
|
render: (args) => {
|
|
const props = useSearch();
|
|
const setIsOpen = useSetAtom<boolean, [boolean], void>(props.isOpen);
|
|
const setNumResults = useSetAtom<number, [number], void>(props.resultsCount);
|
|
useEffect(() => {
|
|
setIsOpen(true);
|
|
setNumResults(10);
|
|
}, []);
|
|
return (
|
|
<div
|
|
className="viewbox"
|
|
ref={props.anchorRef as React.RefObject<HTMLDivElement>}
|
|
style={{
|
|
border: "2px solid black",
|
|
width: "100%",
|
|
height: "200px",
|
|
background: "var(--main-bg-color)",
|
|
}}
|
|
>
|
|
<Search {...args} {...props} />
|
|
</div>
|
|
);
|
|
},
|
|
args: {},
|
|
};
|
|
|
|
export const InputAndResults10: Story = {
|
|
render: (args) => {
|
|
const props = useSearch();
|
|
const setIsOpen = useSetAtom<boolean, [boolean], void>(props.isOpen);
|
|
const setNumResults = useSetAtom<number, [number], void>(props.resultsCount);
|
|
const setSearch = useSetAtom<string, [string], void>(props.searchValue);
|
|
useEffect(() => {
|
|
setIsOpen(true);
|
|
setSearch("search term");
|
|
setTimeout(() => setNumResults(10), 10);
|
|
}, []);
|
|
return (
|
|
<div
|
|
className="viewbox"
|
|
ref={props.anchorRef as React.RefObject<HTMLDivElement>}
|
|
style={{
|
|
border: "2px solid black",
|
|
width: "100%",
|
|
height: "200px",
|
|
background: "var(--main-bg-color)",
|
|
}}
|
|
>
|
|
<Search {...args} {...props} />
|
|
</div>
|
|
);
|
|
},
|
|
args: {},
|
|
};
|
|
|
|
export const LongInputAndResults10: Story = {
|
|
render: (args) => {
|
|
const props = useSearch();
|
|
const setIsOpen = useSetAtom<boolean, [boolean], void>(props.isOpen);
|
|
const setNumResults = useSetAtom<number, [number], void>(props.resultsCount);
|
|
const setSearch = useSetAtom<string, [string], void>(props.searchValue);
|
|
useEffect(() => {
|
|
setIsOpen(true);
|
|
setSearch("search term ".repeat(10).trimEnd());
|
|
setTimeout(() => setNumResults(10), 10);
|
|
}, []);
|
|
return (
|
|
<div
|
|
className="viewbox"
|
|
ref={props.anchorRef as React.RefObject<HTMLDivElement>}
|
|
style={{
|
|
border: "2px solid black",
|
|
width: "100%",
|
|
height: "200px",
|
|
background: "var(--main-bg-color)",
|
|
}}
|
|
>
|
|
<Search {...args} {...props} />
|
|
</div>
|
|
);
|
|
},
|
|
args: {},
|
|
};
|