- Adjusted button styles across various components for consistency and better UX. - Enhanced layout of action controls to utilize whitespace more effectively. - Updated slider styles for a more modern appearance and improved usability. - Refined input fields and labels for better accessibility and readability. - Introduced new app surface styles for a cohesive design across the application. - Added tests for canvas cursor behavior to ensure correct cursor display during operations.
38 lines
3.3 KiB
TypeScript
38 lines
3.3 KiB
TypeScript
import { MagicWand } from "@phosphor-icons/react";
|
||
import { commandIds } from "@commands/ids";
|
||
import type { AppStore } from "@editor/store";
|
||
import type { MagicWandSettings } from "@editor/tools";
|
||
import { BottomControlDivider } from "./Divider";
|
||
import { BottomControlSlider } from "./Slider";
|
||
import { bottomControlFieldClass, bottomControlIconSlotClass, bottomControlLabelClass, bottomControlMenuClass } from "./styles";
|
||
|
||
export function MagicWandControls({ settings, dispatch }: { settings: MagicWandSettings; dispatch: AppStore["dispatch"] }) {
|
||
return (
|
||
<div className={bottomControlMenuClass()}>
|
||
<span className={bottomControlIconSlotClass()} title="Magic wand"><MagicWand size={24} /></span>
|
||
<BottomControlDivider />
|
||
<Slider label="Tol" value={settings.tolerance} min={0} max={255} onChange={(tolerance) => dispatch(commandIds.toolSetMagicWandSettings, { tolerance })} />
|
||
<BottomControlDivider />
|
||
<Slider label="Feather" value={settings.feather} min={0} max={20} onChange={(feather) => dispatch(commandIds.toolSetMagicWandSettings, { feather })} />
|
||
<BottomControlDivider />
|
||
<Slider label="Choke" value={settings.choke} min={-20} max={20} onChange={(choke) => dispatch(commandIds.toolSetMagicWandSettings, { choke })} />
|
||
<BottomControlDivider />
|
||
<Slider label="Clean" value={settings.despeckle} min={0} max={20} onChange={(despeckle) => dispatch(commandIds.toolSetMagicWandSettings, { despeckle })} />
|
||
<BottomControlDivider />
|
||
<button type="button" className={`rounded-md px-3 py-1.5 text-xs font-medium transition ${settings.contiguous ? "bg-sky-300 text-slate-950" : "bg-white/[0.06] text-white/70"}`} aria-label="Contiguous selection" aria-pressed={settings.contiguous} title="Select only connected pixels" onClick={() => dispatch(commandIds.toolSetMagicWandSettings, { contiguous: !settings.contiguous })}>Contiguous</button>
|
||
<BottomControlDivider />
|
||
{(["replace", "add", "subtract"] as const).map((mode) => (
|
||
<button key={mode} type="button" className={`rounded-md px-3 py-1.5 text-xs font-medium capitalize transition ${settings.mode === mode ? "bg-sky-300 text-slate-950" : "bg-white/[0.06] text-white/70"}`} aria-pressed={settings.mode === mode} onClick={() => dispatch(commandIds.toolSetMagicWandSettings, { mode })}>{mode}</button>
|
||
))}
|
||
<span className="flex items-center gap-1 px-1 text-[0.65rem] text-white/45" aria-label="Shift click adds; Alt click subtracts" title="Shift-click adds · Alt-click subtracts">
|
||
<kbd className="rounded border border-white/10 px-1 py-0.5 font-sans text-white/65">⇧ +</kbd>
|
||
<kbd className="rounded border border-white/10 px-1 py-0.5 font-sans text-white/65">⌥ −</kbd>
|
||
</span>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function Slider({ label, value, min, max, onChange }: { label: string; value: number; min: number; max: number; onChange: (value: number) => void }) {
|
||
return <label className={`${bottomControlFieldClass()} min-w-0`}><span className={bottomControlLabelClass()}>{label}</span><BottomControlSlider min={min} max={max} value={value} className="min-w-8 w-[clamp(2rem,7vw,5rem)] shrink" aria-label={`Magic wand ${label}`} onValueChange={onChange} /><span className="w-7 shrink-0 text-right text-xs font-medium text-white/85">{Math.round(value)}</span></label>;
|
||
}
|