Also fix Toggle component to properly handle onChange callback and onClick handler binding.
50 lines
1.3 KiB
TypeScript
50 lines
1.3 KiB
TypeScript
import type { JSX } from "solid-js";
|
|
import { splitProps } from "solid-js";
|
|
import { createControllableSignal } from "../../primitives/create-controllable-signal";
|
|
|
|
export interface ToggleProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
/** Controlled pressed state. */
|
|
pressed?: boolean;
|
|
/** Default pressed state (uncontrolled). @default false */
|
|
defaultPressed?: boolean;
|
|
/** Called when pressed state changes. */
|
|
onPressedChange?: (pressed: boolean) => void;
|
|
children?: JSX.Element;
|
|
}
|
|
|
|
/**
|
|
* A two-state button that can be toggled on and off.
|
|
* Uses aria-pressed to communicate state to assistive technology.
|
|
*/
|
|
export function Toggle(props: ToggleProps): JSX.Element {
|
|
const [local, rest] = splitProps(props, [
|
|
"pressed",
|
|
"defaultPressed",
|
|
"onPressedChange",
|
|
"disabled",
|
|
"children",
|
|
"onClick",
|
|
]);
|
|
|
|
const [isPressed, setPressed] = createControllableSignal<boolean>({
|
|
value: () => local.pressed,
|
|
defaultValue: () => local.defaultPressed ?? false,
|
|
onChange: local.onPressedChange ?? (() => {}),
|
|
});
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
aria-pressed={isPressed()}
|
|
data-state={isPressed() ? "on" : "off"}
|
|
disabled={local.disabled}
|
|
{...rest}
|
|
onClick={() => {
|
|
if (!local.disabled) setPressed(!isPressed());
|
|
}}
|
|
>
|
|
{local.children}
|
|
</button>
|
|
);
|
|
}
|