mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-05-18 20:08:19 +00:00
chore: initial Untitled UI Vite scaffold with FontAwesome Pro
This commit is contained in:
138
src/components/base/toggle/toggle.tsx
Normal file
138
src/components/base/toggle/toggle.tsx
Normal file
@@ -0,0 +1,138 @@
|
||||
import type { ReactNode } from "react";
|
||||
import type { SwitchProps as AriaSwitchProps } from "react-aria-components";
|
||||
import { Switch as AriaSwitch } from "react-aria-components";
|
||||
import { cx } from "@/utils/cx";
|
||||
|
||||
interface ToggleBaseProps {
|
||||
size?: "sm" | "md";
|
||||
slim?: boolean;
|
||||
className?: string;
|
||||
isHovered?: boolean;
|
||||
isFocusVisible?: boolean;
|
||||
isSelected?: boolean;
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
export const ToggleBase = ({ className, isHovered, isDisabled, isFocusVisible, isSelected, slim, size = "sm" }: ToggleBaseProps) => {
|
||||
const styles = {
|
||||
default: {
|
||||
sm: {
|
||||
root: "h-5 w-9 p-0.5",
|
||||
switch: cx("size-4", isSelected && "translate-x-4"),
|
||||
},
|
||||
md: {
|
||||
root: "h-6 w-11 p-0.5",
|
||||
switch: cx("size-5", isSelected && "translate-x-5"),
|
||||
},
|
||||
},
|
||||
slim: {
|
||||
sm: {
|
||||
root: "h-4 w-8",
|
||||
switch: cx("size-4", isSelected && "translate-x-4"),
|
||||
},
|
||||
md: {
|
||||
root: "h-5 w-10",
|
||||
switch: cx("size-5", isSelected && "translate-x-5"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const classes = slim ? styles.slim[size] : styles.default[size];
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
"cursor-pointer rounded-full bg-tertiary outline-focus-ring transition duration-150 ease-linear",
|
||||
isSelected && "bg-brand-solid",
|
||||
isSelected && isHovered && "bg-brand-solid_hover",
|
||||
isDisabled && "cursor-not-allowed bg-disabled",
|
||||
isFocusVisible && "outline-2 outline-offset-2",
|
||||
|
||||
slim && "ring-1 ring-secondary ring-inset",
|
||||
slim && isSelected && "ring-transparent",
|
||||
classes.root,
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
transition: "transform 0.15s ease-in-out, translate 0.15s ease-in-out, border-color 0.1s linear, background-color 0.1s linear",
|
||||
}}
|
||||
className={cx(
|
||||
"rounded-full bg-fg-white shadow-sm",
|
||||
isDisabled && "bg-toggle-button-fg_disabled",
|
||||
|
||||
slim && "shadow-xs",
|
||||
slim && "border border-toggle-border",
|
||||
slim && isSelected && "border-toggle-slim-border_pressed",
|
||||
slim && isSelected && isHovered && "border-toggle-slim-border_pressed-hover",
|
||||
|
||||
classes.switch,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface ToggleProps extends AriaSwitchProps {
|
||||
size?: "sm" | "md";
|
||||
label?: string;
|
||||
hint?: ReactNode;
|
||||
slim?: boolean;
|
||||
}
|
||||
|
||||
export const Toggle = ({ label, hint, className, size = "sm", slim, ...ariaSwitchProps }: ToggleProps) => {
|
||||
const sizes = {
|
||||
sm: {
|
||||
root: "gap-2",
|
||||
textWrapper: "",
|
||||
label: "text-sm font-medium",
|
||||
hint: "text-sm",
|
||||
},
|
||||
md: {
|
||||
root: "gap-3",
|
||||
textWrapper: "gap-0.5",
|
||||
label: "text-md font-medium",
|
||||
hint: "text-md",
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<AriaSwitch
|
||||
{...ariaSwitchProps}
|
||||
className={(renderProps) =>
|
||||
cx(
|
||||
"flex w-max items-start",
|
||||
renderProps.isDisabled && "cursor-not-allowed",
|
||||
sizes[size].root,
|
||||
typeof className === "function" ? className(renderProps) : className,
|
||||
)
|
||||
}
|
||||
>
|
||||
{({ isSelected, isDisabled, isFocusVisible, isHovered }) => (
|
||||
<>
|
||||
<ToggleBase
|
||||
slim={slim}
|
||||
size={size}
|
||||
isHovered={isHovered}
|
||||
isDisabled={isDisabled}
|
||||
isFocusVisible={isFocusVisible}
|
||||
isSelected={isSelected}
|
||||
className={slim ? "mt-0.5" : ""}
|
||||
/>
|
||||
|
||||
{(label || hint) && (
|
||||
<div className={cx("flex flex-col", sizes[size].textWrapper)}>
|
||||
{label && <p className={cx("text-secondary select-none", sizes[size].label)}>{label}</p>}
|
||||
{hint && (
|
||||
<span className={cx("text-tertiary", sizes[size].hint)} onClick={(event) => event.stopPropagation()}>
|
||||
{hint}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</AriaSwitch>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user