mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-22 21:42:49 +01:00
clean up additional button logic, add toggleiconbutton component
This commit is contained in:
parent
4533c813ce
commit
b0ed9d932a
@ -30,7 +30,7 @@ import {
|
||||
import { RpcApi } from "@/app/store/wshclientapi";
|
||||
import { TabRpcClient } from "@/app/store/wshrpcutil";
|
||||
import { ErrorBoundary } from "@/element/errorboundary";
|
||||
import { IconButton } from "@/element/iconbutton";
|
||||
import { IconButton, ToggleIconButton } from "@/element/iconbutton";
|
||||
import { MagnifyIcon } from "@/element/magnify";
|
||||
import { MenuButton } from "@/element/menubutton";
|
||||
import { NodeModel } from "@/layout/index";
|
||||
@ -278,6 +278,8 @@ const BlockFrame_Header = ({
|
||||
const HeaderTextElem = React.memo(({ elem, preview }: { elem: HeaderElem; preview: boolean }) => {
|
||||
if (elem.elemtype == "iconbutton") {
|
||||
return <IconButton decl={elem} className={clsx("block-frame-header-iconbutton", elem.className)} />;
|
||||
} else if (elem.elemtype == "toggleiconbutton") {
|
||||
return <ToggleIconButton decl={elem} className={clsx("block-frame-header-iconbutton", elem.className)} />;
|
||||
} else if (elem.elemtype == "input") {
|
||||
return <Input decl={elem} className={clsx("block-frame-input", elem.className)} preview={preview} />;
|
||||
} else if (elem.elemtype == "text") {
|
||||
|
@ -32,4 +32,17 @@
|
||||
cursor: default;
|
||||
opacity: 0.45 !important;
|
||||
}
|
||||
|
||||
&.toggle {
|
||||
border-radius: 3px;
|
||||
padding: 1px;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
border: 1px solid var(--accent-color);
|
||||
padding: 0;
|
||||
}
|
||||
&:hover {
|
||||
background: var(--highlight-bg-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,8 @@
|
||||
import { useLongClick } from "@/app/hook/useLongClick";
|
||||
import { makeIconClass } from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import { forwardRef, memo, useRef } from "react";
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { forwardRef, memo, useMemo, useRef } from "react";
|
||||
import "./iconbutton.scss";
|
||||
|
||||
type IconButtonProps = { decl: IconButtonDecl; className?: string };
|
||||
@ -21,6 +22,7 @@ export const IconButton = memo(
|
||||
"no-action": decl.noAction,
|
||||
})}
|
||||
title={decl.title}
|
||||
aria-label={decl.title}
|
||||
style={{ color: decl.iconColor ?? "inherit" }}
|
||||
>
|
||||
{typeof decl.icon === "string" ? <i className={makeIconClass(decl.icon, true, { spin })} /> : decl.icon}
|
||||
@ -28,3 +30,34 @@ export const IconButton = memo(
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
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)" : ""}`;
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
className={clsx("wave-iconbutton", "toggle", className, decl.className, {
|
||||
active,
|
||||
disabled: decl.disabled,
|
||||
"no-action": decl.noAction,
|
||||
})}
|
||||
title={title}
|
||||
aria-label={title}
|
||||
style={{ color: decl.iconColor ?? "inherit" }}
|
||||
onPointerDown={() => {
|
||||
console.log("active", active);
|
||||
setActive(!active);
|
||||
}}
|
||||
>
|
||||
{typeof decl.icon === "string" ? <i className={makeIconClass(decl.icon, true, { spin })} /> : decl.icon}
|
||||
</button>
|
||||
);
|
||||
})
|
||||
);
|
||||
|
@ -34,7 +34,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.right-buttons {
|
||||
.right-buttons:not(:empty) {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
padding-left: 5px;
|
||||
@ -42,5 +42,15 @@
|
||||
button {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&.additional {
|
||||
gap: 2px;
|
||||
button {
|
||||
font-size: 10px;
|
||||
i {
|
||||
margin: auto 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,35 @@ const meta: Meta<typeof Search> = {
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Popover>;
|
||||
|
||||
export const DefaultSearch: Story = {
|
||||
export const Default: Story = {
|
||||
render: (args) => {
|
||||
const props = useSearch();
|
||||
const setIsOpen = useSetAtom(props.isOpenAtom);
|
||||
const setIsOpen = useSetAtom(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(props.isOpen);
|
||||
useEffect(() => {
|
||||
setIsOpen(true);
|
||||
}, []);
|
||||
@ -44,8 +69,8 @@ export const DefaultSearch: Story = {
|
||||
export const Results10: Story = {
|
||||
render: (args) => {
|
||||
const props = useSearch();
|
||||
const setIsOpen = useSetAtom(props.isOpenAtom);
|
||||
const setNumResults = useSetAtom(props.numResultsAtom);
|
||||
const setIsOpen = useSetAtom(props.isOpen);
|
||||
const setNumResults = useSetAtom(props.resultsCount);
|
||||
useEffect(() => {
|
||||
setIsOpen(true);
|
||||
setNumResults(10);
|
||||
@ -71,9 +96,9 @@ export const Results10: Story = {
|
||||
export const InputAndResults10: Story = {
|
||||
render: (args) => {
|
||||
const props = useSearch();
|
||||
const setIsOpen = useSetAtom(props.isOpenAtom);
|
||||
const setNumResults = useSetAtom(props.numResultsAtom);
|
||||
const setSearch = useSetAtom(props.searchAtom);
|
||||
const setIsOpen = useSetAtom(props.isOpen);
|
||||
const setNumResults = useSetAtom(props.resultsCount);
|
||||
const setSearch = useSetAtom(props.searchValue);
|
||||
useEffect(() => {
|
||||
setIsOpen(true);
|
||||
setNumResults(10);
|
||||
@ -100,9 +125,9 @@ export const InputAndResults10: Story = {
|
||||
export const LongInputAndResults10: Story = {
|
||||
render: (args) => {
|
||||
const props = useSearch();
|
||||
const setIsOpen = useSetAtom(props.isOpenAtom);
|
||||
const setNumResults = useSetAtom(props.numResultsAtom);
|
||||
const setSearch = useSetAtom(props.searchAtom);
|
||||
const setIsOpen = useSetAtom(props.isOpen);
|
||||
const setNumResults = useSetAtom(props.resultsCount);
|
||||
const setSearch = useSetAtom(props.searchValue);
|
||||
useEffect(() => {
|
||||
setIsOpen(true);
|
||||
setNumResults(10);
|
||||
|
@ -5,7 +5,7 @@ import { autoUpdate, FloatingPortal, Middleware, offset, useFloating } from "@fl
|
||||
import clsx from "clsx";
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import { IconButton } from "./iconbutton";
|
||||
import { IconButton, ToggleIconButton } from "./iconbutton";
|
||||
import { Input } from "./input";
|
||||
import "./search.scss";
|
||||
|
||||
@ -16,21 +16,22 @@ type SearchProps = SearchAtoms & {
|
||||
onSearch?: (search: string) => void;
|
||||
onNext?: () => void;
|
||||
onPrev?: () => void;
|
||||
additionalButtons?: IconButtonDecl[];
|
||||
};
|
||||
|
||||
const SearchComponent = ({
|
||||
searchAtom,
|
||||
indexAtom,
|
||||
numResultsAtom,
|
||||
isOpenAtom,
|
||||
searchValue: searchAtom,
|
||||
resultsIndex: indexAtom,
|
||||
resultsCount: numResultsAtom,
|
||||
regex: regexAtom,
|
||||
caseSensitive: caseSensitiveAtom,
|
||||
wholeWord: wholeWordAtom,
|
||||
isOpen: isOpenAtom,
|
||||
anchorRef,
|
||||
offsetX = 10,
|
||||
offsetY = 10,
|
||||
onSearch,
|
||||
onNext,
|
||||
onPrev,
|
||||
additionalButtons,
|
||||
}: SearchProps) => {
|
||||
const [isOpen, setIsOpen] = useAtom<boolean>(isOpenAtom);
|
||||
const [search, setSearch] = useAtom<string>(searchAtom);
|
||||
@ -131,6 +132,31 @@ const SearchComponent = ({
|
||||
click: () => setIsOpen(false),
|
||||
};
|
||||
|
||||
const regexDecl: ToggleIconButtonDecl = regexAtom
|
||||
? {
|
||||
elemtype: "toggleiconbutton",
|
||||
icon: "asterisk",
|
||||
title: "Regex Search",
|
||||
active: regexAtom,
|
||||
}
|
||||
: null;
|
||||
const wholeWordDecl: ToggleIconButtonDecl = caseSensitiveAtom
|
||||
? {
|
||||
elemtype: "toggleiconbutton",
|
||||
icon: "w",
|
||||
title: "Whole Word",
|
||||
active: wholeWordAtom,
|
||||
}
|
||||
: null;
|
||||
const caseSensitiveDecl: ToggleIconButtonDecl = caseSensitiveAtom
|
||||
? {
|
||||
elemtype: "toggleiconbutton",
|
||||
icon: "font-case",
|
||||
title: "Case Sensitive",
|
||||
active: caseSensitiveAtom,
|
||||
}
|
||||
: null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{isOpen && (
|
||||
@ -150,13 +176,13 @@ const SearchComponent = ({
|
||||
>
|
||||
{index + 1}/{numResults}
|
||||
</div>
|
||||
{additionalButtons?.length && (
|
||||
<div className="right-buttons">
|
||||
{additionalButtons.map((decl, i) => (
|
||||
<IconButton key={i} decl={decl} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="right-buttons additional">
|
||||
{caseSensitiveDecl && <ToggleIconButton decl={caseSensitiveDecl} />}
|
||||
{wholeWordDecl && <ToggleIconButton decl={wholeWordDecl} />}
|
||||
{regexDecl && <ToggleIconButton decl={regexDecl} />}
|
||||
</div>
|
||||
|
||||
<div className="right-buttons">
|
||||
<IconButton decl={prevDecl} />
|
||||
<IconButton decl={nextDecl} />
|
||||
@ -171,16 +197,32 @@ const SearchComponent = ({
|
||||
|
||||
export const Search = memo(SearchComponent) as typeof SearchComponent;
|
||||
|
||||
export function useSearch(anchorRef?: React.RefObject<HTMLElement>, viewModel?: ViewModel): SearchProps {
|
||||
type SearchOptions = {
|
||||
anchorRef?: React.RefObject<HTMLElement>;
|
||||
viewModel?: ViewModel;
|
||||
regex?: boolean;
|
||||
caseSensitive?: boolean;
|
||||
wholeWord?: boolean;
|
||||
};
|
||||
|
||||
export function useSearch(options?: SearchOptions): SearchProps {
|
||||
const searchAtoms: SearchAtoms = useMemo(
|
||||
() => ({ searchAtom: atom(""), indexAtom: atom(0), numResultsAtom: atom(0), isOpenAtom: atom(false) }),
|
||||
() => ({
|
||||
searchValue: atom(""),
|
||||
resultsIndex: atom(0),
|
||||
resultsCount: atom(0),
|
||||
isOpen: atom(false),
|
||||
regex: options?.regex !== undefined ? atom(options.regex) : undefined,
|
||||
caseSensitive: options?.caseSensitive !== undefined ? atom(options.caseSensitive) : undefined,
|
||||
wholeWord: options?.wholeWord !== undefined ? atom(options.wholeWord) : undefined,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
anchorRef ??= useRef(null);
|
||||
const anchorRef = options?.anchorRef ?? useRef(null);
|
||||
useEffect(() => {
|
||||
if (viewModel) {
|
||||
viewModel.searchAtoms = searchAtoms;
|
||||
if (options?.viewModel) {
|
||||
options.viewModel.searchAtoms = searchAtoms;
|
||||
}
|
||||
}, [viewModel]);
|
||||
}, [options?.viewModel]);
|
||||
return { ...searchAtoms, anchorRef };
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ function registerGlobalKeys() {
|
||||
const bcm = getBlockComponentModel(getFocusedBlockInStaticTab());
|
||||
if (bcm.viewModel.searchAtoms) {
|
||||
console.log("activateSearch2");
|
||||
globalStore.set(bcm.viewModel.searchAtoms.isOpenAtom, true);
|
||||
globalStore.set(bcm.viewModel.searchAtoms.isOpen, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -334,8 +334,8 @@ function registerGlobalKeys() {
|
||||
function deactivateSearch(): boolean {
|
||||
console.log("deactivateSearch");
|
||||
const bcm = getBlockComponentModel(getFocusedBlockInStaticTab());
|
||||
if (bcm.viewModel.searchAtoms && globalStore.get(bcm.viewModel.searchAtoms.isOpenAtom)) {
|
||||
globalStore.set(bcm.viewModel.searchAtoms.isOpenAtom, false);
|
||||
if (bcm.viewModel.searchAtoms && globalStore.get(bcm.viewModel.searchAtoms.isOpen)) {
|
||||
globalStore.set(bcm.viewModel.searchAtoms.isOpen, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -25,7 +25,7 @@ import {
|
||||
} from "@/store/global";
|
||||
import * as services from "@/store/services";
|
||||
import * as keyutil from "@/util/keyutil";
|
||||
import { boundNumber, fireAndForget } from "@/util/util";
|
||||
import { boundNumber, fireAndForget, useAtomValueSafe } from "@/util/util";
|
||||
import { ISearchOptions } from "@xterm/addon-search";
|
||||
import clsx from "clsx";
|
||||
import debug from "debug";
|
||||
@ -364,7 +364,7 @@ class TermViewModel implements ViewModel {
|
||||
}
|
||||
|
||||
giveFocus(): boolean {
|
||||
if (this.searchAtoms && globalStore.get(this.searchAtoms.isOpenAtom)) {
|
||||
if (this.searchAtoms && globalStore.get(this.searchAtoms.isOpen)) {
|
||||
console.log("search is open, not giving focus");
|
||||
return true;
|
||||
}
|
||||
@ -793,72 +793,54 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
const connFontFamily = fullConfig.connections?.[blockData?.meta?.connection]?.["term:fontfamily"];
|
||||
|
||||
// search
|
||||
const searchProps = useSearch(viewRef, model);
|
||||
const { additionalButtons, stateAtoms } = React.useMemo(() => {
|
||||
const regexAtom = jotai.atom(false);
|
||||
const wholeWordAtom = jotai.atom(false);
|
||||
const caseSensitiveAtom = jotai.atom(false);
|
||||
const additionalButtons: IconButtonDecl[] = [
|
||||
{
|
||||
elemtype: "iconbutton",
|
||||
icon: "font-case",
|
||||
title: "Case Sensitive",
|
||||
click: () => {
|
||||
globalStore.set(caseSensitiveAtom, !globalStore.get(caseSensitiveAtom));
|
||||
},
|
||||
const searchProps = useSearch({
|
||||
anchorRef: viewRef,
|
||||
viewModel: model,
|
||||
caseSensitive: false,
|
||||
wholeWord: false,
|
||||
regex: false,
|
||||
});
|
||||
const caseSensitive = useAtomValueSafe<boolean>(searchProps.caseSensitive);
|
||||
const wholeWord = useAtomValueSafe<boolean>(searchProps.wholeWord);
|
||||
const regex = useAtomValueSafe<boolean>(searchProps.regex);
|
||||
const searchVal = jotai.useAtomValue<string>(searchProps.searchValue);
|
||||
const searchOpts: ISearchOptions = React.useMemo(
|
||||
() => ({
|
||||
incremental: true,
|
||||
regex,
|
||||
wholeWord,
|
||||
caseSensitive,
|
||||
decorations: {
|
||||
matchOverviewRuler: "#e0e0e0",
|
||||
activeMatchColorOverviewRuler: "#e0e0e0",
|
||||
activeMatchBorder: "#58c142",
|
||||
matchBorder: "#e0e0e0",
|
||||
},
|
||||
{
|
||||
elemtype: "iconbutton",
|
||||
icon: "w",
|
||||
title: "Whole Word",
|
||||
click: () => {
|
||||
globalStore.set(wholeWordAtom, !globalStore.get(wholeWordAtom));
|
||||
},
|
||||
},
|
||||
{
|
||||
elemtype: "iconbutton",
|
||||
icon: "asterisk",
|
||||
title: "Regex Search",
|
||||
click: () => {
|
||||
globalStore.set(regexAtom, !globalStore.get(regexAtom));
|
||||
},
|
||||
},
|
||||
];
|
||||
return {
|
||||
additionalButtons,
|
||||
stateAtoms: { caseSensitiveAtom, wholeWordAtom, regexAtom },
|
||||
};
|
||||
}, []);
|
||||
searchProps.additionalButtons = additionalButtons;
|
||||
const caseSensitive = jotai.useAtomValue<boolean>(stateAtoms.caseSensitiveAtom);
|
||||
const wholeWord = jotai.useAtomValue<boolean>(stateAtoms.wholeWordAtom);
|
||||
const regex = jotai.useAtomValue<boolean>(stateAtoms.regexAtom);
|
||||
const searchVal = jotai.useAtomValue<string>(searchProps.searchAtom);
|
||||
const searchOpts: ISearchOptions = {
|
||||
incremental: true,
|
||||
regex,
|
||||
wholeWord,
|
||||
caseSensitive,
|
||||
decorations: {
|
||||
matchOverviewRuler: "#e0e0e0",
|
||||
activeMatchColorOverviewRuler: "#e0e0e0",
|
||||
activeMatchBorder: "#58c142",
|
||||
matchBorder: "#e0e0e0",
|
||||
}),
|
||||
[regex, wholeWord, caseSensitive]
|
||||
);
|
||||
searchProps.onSearch = React.useCallback(
|
||||
(searchText: string) => {
|
||||
if (searchText == "") {
|
||||
model.termRef.current?.searchAddon.clearDecorations();
|
||||
return;
|
||||
}
|
||||
model.termRef.current?.searchAddon.findNext(searchText, searchOpts);
|
||||
},
|
||||
};
|
||||
searchProps.onSearch = React.useCallback((searchText: string) => {
|
||||
if (searchText == "") {
|
||||
model.termRef.current?.searchAddon.clearDecorations();
|
||||
return;
|
||||
}
|
||||
model.termRef.current?.searchAddon.findNext(searchText, searchOpts);
|
||||
}, []);
|
||||
[searchOpts]
|
||||
);
|
||||
searchProps.onPrev = React.useCallback(() => {
|
||||
model.termRef.current?.searchAddon.findPrevious(searchVal, searchOpts);
|
||||
}, [searchVal]);
|
||||
}, [searchVal, searchOpts]);
|
||||
searchProps.onNext = React.useCallback(() => {
|
||||
model.termRef.current?.searchAddon.findNext(searchVal, searchOpts);
|
||||
}, [searchVal]);
|
||||
}, [searchVal, searchOpts]);
|
||||
|
||||
// rerun search when the searchOpts change
|
||||
React.useEffect(() => {
|
||||
model.termRef.current?.searchAddon.clearDecorations();
|
||||
searchProps.onSearch(searchVal);
|
||||
}, [searchOpts]);
|
||||
// end search
|
||||
|
||||
React.useEffect(() => {
|
||||
@ -906,8 +888,8 @@ const TerminalView = ({ blockId, model }: TerminalViewProps) => {
|
||||
});
|
||||
rszObs.observe(connectElemRef.current);
|
||||
termWrap.onSearchResultsDidChange = (results) => {
|
||||
globalStore.set(searchProps.indexAtom, results.resultIndex);
|
||||
globalStore.set(searchProps.numResultsAtom, results.resultCount);
|
||||
globalStore.set(searchProps.resultsIndex, results.resultIndex);
|
||||
globalStore.set(searchProps.resultsCount, results.resultCount);
|
||||
};
|
||||
fireAndForget(termWrap.initTerminal.bind(termWrap));
|
||||
if (wasFocused) {
|
||||
|
@ -299,7 +299,7 @@ export class WebViewModel implements ViewModel {
|
||||
fireAndForget(() => ObjectService.UpdateObjectMeta(WOS.makeORef("block", this.blockId), { url }));
|
||||
globalStore.set(this.url, url);
|
||||
if (this.searchAtoms) {
|
||||
globalStore.set(this.searchAtoms.isOpenAtom, false);
|
||||
globalStore.set(this.searchAtoms.isOpen, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,7 +395,7 @@ export class WebViewModel implements ViewModel {
|
||||
|
||||
giveFocus(): boolean {
|
||||
console.log("webview giveFocus");
|
||||
if (this.searchAtoms && globalStore.get(this.searchAtoms.isOpenAtom)) {
|
||||
if (this.searchAtoms && globalStore.get(this.searchAtoms.isOpen)) {
|
||||
console.log("search is open, not giving focus");
|
||||
return true;
|
||||
}
|
||||
@ -549,9 +549,9 @@ const WebView = memo(({ model, onFailLoad }: WebViewProps) => {
|
||||
|
||||
// Search
|
||||
const searchProps = useSearch(model.webviewRef, model);
|
||||
const searchVal = useAtomValue<string>(searchProps.searchAtom);
|
||||
const setSearchIndex = useSetAtom(searchProps.indexAtom);
|
||||
const setNumSearchResults = useSetAtom(searchProps.numResultsAtom);
|
||||
const searchVal = useAtomValue<string>(searchProps.searchValue);
|
||||
const setSearchIndex = useSetAtom(searchProps.resultsIndex);
|
||||
const setNumSearchResults = useSetAtom(searchProps.resultsCount);
|
||||
searchProps.onSearch = useCallback((search: string) => {
|
||||
try {
|
||||
if (search) {
|
||||
|
28
frontend/types/custom.d.ts
vendored
28
frontend/types/custom.d.ts
vendored
@ -143,6 +143,7 @@ declare global {
|
||||
|
||||
type HeaderElem =
|
||||
| IconButtonDecl
|
||||
| ToggleIconButtonDecl
|
||||
| HeaderText
|
||||
| HeaderInput
|
||||
| HeaderDiv
|
||||
@ -150,19 +151,27 @@ declare global {
|
||||
| ConnectionButton
|
||||
| MenuButton;
|
||||
|
||||
type IconButtonDecl = {
|
||||
elemtype: "iconbutton";
|
||||
type IconButtonCommon = {
|
||||
icon: string | React.ReactNode;
|
||||
iconColor?: string;
|
||||
iconSpin?: boolean;
|
||||
className?: string;
|
||||
title?: string;
|
||||
click?: (e: React.MouseEvent<any>) => void;
|
||||
longClick?: (e: React.MouseEvent<any>) => void;
|
||||
disabled?: boolean;
|
||||
noAction?: boolean;
|
||||
};
|
||||
|
||||
type IconButtonDecl = IconButtonCommon & {
|
||||
elemtype: "iconbutton";
|
||||
click?: (e: React.MouseEvent<any>) => void;
|
||||
longClick?: (e: React.MouseEvent<any>) => void;
|
||||
};
|
||||
|
||||
type ToggleIconButtonDecl = IconButtonCommon & {
|
||||
elemtype: "toggleiconbutton";
|
||||
active: jotai.WritableAtom<boolean, [boolean], void>;
|
||||
};
|
||||
|
||||
type HeaderTextButton = {
|
||||
elemtype: "textbutton";
|
||||
text: string;
|
||||
@ -229,10 +238,13 @@ declare global {
|
||||
} & MenuButtonProps;
|
||||
|
||||
type SearchAtoms = {
|
||||
searchAtom: PrimitiveAtom<string>;
|
||||
indexAtom: PrimitiveAtom<number>;
|
||||
numResultsAtom: PrimitiveAtom<number>;
|
||||
isOpenAtom: PrimitiveAtom<boolean>;
|
||||
searchValue: PrimitiveAtom<string>;
|
||||
resultsIndex: PrimitiveAtom<number>;
|
||||
resultsCount: PrimitiveAtom<number>;
|
||||
isOpen: PrimitiveAtom<boolean>;
|
||||
regex?: PrimitiveAtom<boolean>;
|
||||
caseSensitive?: PrimitiveAtom<boolean>;
|
||||
wholeWord?: PrimitiveAtom<boolean>;
|
||||
};
|
||||
|
||||
interface ViewModel {
|
||||
|
Loading…
Reference in New Issue
Block a user