mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
feat(studio): add FlatToggle primitive
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
FlatSegmentedRow,
|
||||
FlatSelectRow,
|
||||
FlatSlider,
|
||||
FlatToggle,
|
||||
PinnedZoneDivider,
|
||||
} from "./propertyPanelFlatPrimitives";
|
||||
|
||||
@@ -286,3 +287,44 @@ describe("FlatSelectRow", () => {
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
|
||||
describe("FlatToggle", () => {
|
||||
it("renders the off state with a dim label and dim knob, and fires onChange(true) on click", () => {
|
||||
const onChange = vi.fn();
|
||||
const { host, root } = renderInto(
|
||||
<FlatToggle label="Loop" checked={false} onChange={onChange} />,
|
||||
);
|
||||
const label = host.querySelector('[data-flat-toggle-label="true"]');
|
||||
expect(label?.className).toContain("text-panel-text-3");
|
||||
const pill = host.querySelector<HTMLButtonElement>('[data-flat-toggle="true"]');
|
||||
expect(pill).not.toBeNull();
|
||||
act(() => pill?.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
expect(onChange).toHaveBeenCalledWith(true);
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("renders the on state with an emphasized label and mint knob, and fires onChange(false) on click", () => {
|
||||
const onChange = vi.fn();
|
||||
const { host, root } = renderInto(<FlatToggle label="Loop" checked onChange={onChange} />);
|
||||
const label = host.querySelector('[data-flat-toggle-label="true"]');
|
||||
expect(label?.className).toContain("text-panel-text-2");
|
||||
const knob = host.querySelector('[data-flat-toggle-knob="true"]');
|
||||
expect(knob?.className).toContain("bg-panel-accent");
|
||||
const pill = host.querySelector<HTMLButtonElement>('[data-flat-toggle="true"]');
|
||||
act(() => pill?.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
expect(onChange).toHaveBeenCalledWith(false);
|
||||
act(() => root.unmount());
|
||||
});
|
||||
|
||||
it("does not fire onChange when disabled", () => {
|
||||
const onChange = vi.fn();
|
||||
const { host, root } = renderInto(
|
||||
<FlatToggle label="Loop" checked={false} disabled onChange={onChange} />,
|
||||
);
|
||||
const pill = host.querySelector<HTMLButtonElement>('[data-flat-toggle="true"]');
|
||||
expect(pill?.disabled).toBe(true);
|
||||
act(() => pill?.dispatchEvent(new MouseEvent("click", { bubbles: true })));
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
act(() => root.unmount());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -375,3 +375,49 @@ export function FlatSelectRow({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* FlatToggle — 24×14 pill switch */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
export function FlatToggle({
|
||||
label,
|
||||
checked,
|
||||
disabled,
|
||||
onChange,
|
||||
}: {
|
||||
label: string;
|
||||
checked: boolean;
|
||||
disabled?: boolean;
|
||||
onChange: (next: boolean) => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex min-h-[30px] items-center justify-between">
|
||||
<span
|
||||
data-flat-toggle-label="true"
|
||||
className={`text-[11px] ${checked ? "text-panel-text-2" : "text-panel-text-3"}`}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
data-flat-toggle="true"
|
||||
role="switch"
|
||||
aria-checked={checked}
|
||||
aria-label={label}
|
||||
disabled={disabled}
|
||||
onClick={() => onChange(!checked)}
|
||||
className={`relative h-[14px] w-6 flex-shrink-0 rounded-full transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${
|
||||
checked ? "bg-panel-accent/35" : "bg-panel-hover"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
data-flat-toggle-knob="true"
|
||||
className={`absolute top-0.5 h-2.5 w-2.5 rounded-full transition-all ${
|
||||
checked ? "right-0.5 bg-panel-accent" : "left-0.5 bg-panel-text-4"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user