mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-31 06:23:08 +02:00
Refactor proxy codebase
This commit is contained in:
95
packages/ui/src/components/IconButton.tsx
Normal file
95
packages/ui/src/components/IconButton.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import classNames from "classnames";
|
||||
import type { MouseEvent } from "react";
|
||||
import { forwardRef, useCallback } from "react";
|
||||
import { useTimedBoolean } from "../hooks/useTimedBoolean";
|
||||
import type { ButtonProps } from "./Button";
|
||||
import { Button } from "./Button";
|
||||
import type { IconProps } from "./Icon";
|
||||
import { Icon } from "./Icon";
|
||||
import { LoadingIcon } from "./LoadingIcon";
|
||||
|
||||
export type IconButtonProps = IconProps &
|
||||
ButtonProps & {
|
||||
showConfirm?: boolean;
|
||||
iconClassName?: string;
|
||||
iconSize?: IconProps["size"];
|
||||
iconColor?: IconProps["color"];
|
||||
title: string;
|
||||
showBadge?: boolean;
|
||||
};
|
||||
|
||||
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(
|
||||
{
|
||||
showConfirm,
|
||||
icon,
|
||||
color = "default",
|
||||
spin,
|
||||
onClick,
|
||||
className,
|
||||
iconClassName,
|
||||
tabIndex,
|
||||
size = "md",
|
||||
iconSize,
|
||||
showBadge,
|
||||
iconColor,
|
||||
isLoading,
|
||||
type = "button",
|
||||
...props
|
||||
}: IconButtonProps,
|
||||
ref,
|
||||
) {
|
||||
const [confirmed, setConfirmed] = useTimedBoolean();
|
||||
const handleClick = useCallback(
|
||||
(e: MouseEvent<HTMLButtonElement>) => {
|
||||
if (showConfirm) setConfirmed();
|
||||
onClick?.(e);
|
||||
},
|
||||
[onClick, setConfirmed, showConfirm],
|
||||
);
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
aria-hidden={icon === "empty"}
|
||||
disabled={icon === "empty"}
|
||||
tabIndex={(tabIndex ?? icon === "empty") ? -1 : undefined}
|
||||
onClick={handleClick}
|
||||
innerClassName="flex items-center justify-center"
|
||||
size={size}
|
||||
color={color}
|
||||
type={type}
|
||||
className={classNames(
|
||||
className,
|
||||
"group/button relative flex-shrink-0",
|
||||
"!px-0",
|
||||
size === "md" && "w-md",
|
||||
size === "sm" && "w-sm",
|
||||
size === "xs" && "w-xs",
|
||||
size === "2xs" && "w-5",
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{showBadge && (
|
||||
<div className="absolute top-0 right-0 w-1/2 h-1/2 flex items-center justify-center">
|
||||
<div className="w-2.5 h-2.5 bg-pink-500 rounded-full" />
|
||||
</div>
|
||||
)}
|
||||
{isLoading ? (
|
||||
<LoadingIcon size={iconSize} className={iconClassName} />
|
||||
) : (
|
||||
<Icon
|
||||
size={iconSize}
|
||||
icon={confirmed ? "check" : icon}
|
||||
spin={spin}
|
||||
color={iconColor}
|
||||
className={classNames(
|
||||
iconClassName,
|
||||
"group-hover/button:text-text",
|
||||
confirmed && "!text-success",
|
||||
props.disabled && "opacity-70",
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
19
packages/ui/src/hooks/useTimedBoolean.ts
Normal file
19
packages/ui/src/hooks/useTimedBoolean.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useUnmount } from 'react-use';
|
||||
|
||||
/** Returns a boolean that is true for a given number of milliseconds. */
|
||||
export function useTimedBoolean(millis = 1500): [boolean, () => void] {
|
||||
const [value, setValue] = useState(false);
|
||||
const timeout = useRef<NodeJS.Timeout | null>(null);
|
||||
const reset = () => timeout.current && clearTimeout(timeout.current);
|
||||
|
||||
useUnmount(reset);
|
||||
|
||||
const setToTrue = () => {
|
||||
setValue(true);
|
||||
reset();
|
||||
timeout.current = setTimeout(() => setValue(false), millis);
|
||||
};
|
||||
|
||||
return [value, setToTrue];
|
||||
}
|
||||
@@ -3,7 +3,10 @@ export type { ButtonProps } from "./components/Button";
|
||||
export { HeaderSize } from "./components/HeaderSize";
|
||||
export { Icon } from "./components/Icon";
|
||||
export type { IconProps } from "./components/Icon";
|
||||
export { IconButton } from "./components/IconButton";
|
||||
export type { IconButtonProps } from "./components/IconButton";
|
||||
export { LoadingIcon } from "./components/LoadingIcon";
|
||||
export { useTimedBoolean } from "./hooks/useTimedBoolean";
|
||||
export { WindowControls } from "./components/WindowControls";
|
||||
export { useIsFullscreen } from "./hooks/useIsFullscreen";
|
||||
export { useDebouncedValue } from "./hooks/useDebouncedValue";
|
||||
|
||||
Reference in New Issue
Block a user