Update checkbox component
This commit is contained in:
@@ -21,49 +21,59 @@ const CheckboxContainer = memo<CheckboxProps>(
|
||||
...props
|
||||
}) => {
|
||||
const isInverse = mode === "inverse";
|
||||
const isStandard = mode === "standard";
|
||||
|
||||
// Base tokens (rough placeholders leveraging existing CSS variables)
|
||||
const colorContent = isInverse
|
||||
? "var(--color-content-inverse-primary)"
|
||||
: "var(--color-content-default-primary)";
|
||||
// Generate unique ID for accessibility if not provided
|
||||
const { id: checkboxId, labelId } = useComponentId("checkbox", id);
|
||||
|
||||
// Visual container depending on state
|
||||
const baseBox = `flex items-center justify-center shrink-0 w-[var(--measures-sizing-024)] h-[var(--measures-sizing-024)] rounded-[var(--measures-radius-medium)] transition-all duration-200 ease-in-out`;
|
||||
// Base box styles per Figma
|
||||
const baseBox = `
|
||||
flex
|
||||
items-center
|
||||
justify-center
|
||||
shrink-0
|
||||
w-[24px]
|
||||
h-[24px]
|
||||
rounded-[4px]
|
||||
transition-all
|
||||
duration-200
|
||||
ease-in-out
|
||||
`.trim().replace(/\s+/g, " ");
|
||||
|
||||
const stateStyles: Record<string, string> = {
|
||||
default: "",
|
||||
hover: "",
|
||||
focus: "",
|
||||
// Get box styles based on state and checked status per Figma designs
|
||||
const getBoxStyles = (): string => {
|
||||
// Standard mode styles
|
||||
if (isStandard) {
|
||||
// Default state: tertiary border, with hover and focus states via CSS
|
||||
// Hover changes border to brand primary color
|
||||
// Focus removes border and shows shadow (double ring: 2px white inner, 4px dark outer)
|
||||
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid border-[var(--color-border-default-tertiary,#464646)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:border-transparent focus:shadow-[0px_0px_0px_2px_var(--color-border-invert-primary,white),0px_0px_0px_4px_var(--color-border-default-primary,#141414)] focus:outline-none`;
|
||||
}
|
||||
|
||||
// Inverse mode styles per Figma
|
||||
if (isInverse) {
|
||||
// Inverse: transparent background, white border
|
||||
// Hover changes border to brand primary color
|
||||
// Focus shows shadow (2px dark inner, 4px white outer) - note: reversed from standard
|
||||
return `${baseBox} bg-transparent border border-solid border-[var(--color-border-invert-primary,white)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:shadow-[0px_0px_0px_2px_var(--color-border-default-primary,#141414),0px_0px_0px_4px_var(--color-border-invert-primary,white)] focus:outline-none`;
|
||||
}
|
||||
|
||||
return baseBox;
|
||||
};
|
||||
|
||||
// Background behavior:
|
||||
// - Standard: background does not change on check; only checkmark appears
|
||||
// - Inverse: transparent background, checkmark appears on check
|
||||
const backgroundWhenChecked = isInverse
|
||||
? "var(--color-surface-default-transparent)"
|
||||
: "var(--color-surface-default-primary)";
|
||||
const combinedBoxStyles = getBoxStyles();
|
||||
|
||||
// Checkmark color per Figma
|
||||
const checkGlyphColor = checked
|
||||
? isInverse
|
||||
? "var(--color-content-inverse-primary)"
|
||||
: "var(--color-border-default-brand-primary)"
|
||||
? isStandard
|
||||
? "var(--color-content-default-brand-primary, #fefcc9)" // Light yellow/cream for standard mode
|
||||
: "var(--color-content-inverse-primary, #000000)" // Black for inverse mode
|
||||
: "transparent";
|
||||
const labelColor = colorContent;
|
||||
|
||||
const combinedBoxStyles = `${baseBox} ${stateStyles[state]}`;
|
||||
|
||||
// Force visible outline for standard / default / unchecked
|
||||
// Outline classes instead of inline styles so hover can override
|
||||
const defaultOutlineClass = isInverse
|
||||
? "outline outline-1 outline-[var(--color-border-inverse-primary)]"
|
||||
: "outline outline-1 outline-[var(--color-border-default-tertiary)]";
|
||||
|
||||
// Apply brand outline only on actual :hover, and only when standard/unchecked
|
||||
const conditionalHoverOutlineClass =
|
||||
"hover:outline hover:outline-1 hover:outline-[var(--color-border-default-brand-primary)]";
|
||||
|
||||
// Focus state for standard/unchecked with brand primary color and specific blur/spread
|
||||
const conditionalFocusClass =
|
||||
"focus:outline focus:outline-1 focus:outline-[var(--color-border-default-utility-info)] focus:shadow-[0_0_10px_1px_var(--color-surface-inverse-brand-primary)]";
|
||||
// Label color
|
||||
const labelColor = isInverse
|
||||
? "var(--color-content-inverse-primary)"
|
||||
: "var(--color-content-default-primary)";
|
||||
|
||||
const handleToggle = (e: React.MouseEvent | React.KeyboardEvent) => {
|
||||
if (disabled) return;
|
||||
@@ -74,9 +84,6 @@ const CheckboxContainer = memo<CheckboxProps>(
|
||||
});
|
||||
};
|
||||
|
||||
// Generate unique ID for accessibility if not provided
|
||||
const { id: checkboxId, labelId } = useComponentId("checkbox", id);
|
||||
|
||||
const accessibilityProps = {
|
||||
role: "checkbox" as const,
|
||||
"aria-checked": checked,
|
||||
@@ -107,10 +114,6 @@ const CheckboxContainer = memo<CheckboxProps>(
|
||||
value={value}
|
||||
className={className}
|
||||
combinedBoxStyles={combinedBoxStyles}
|
||||
defaultOutlineClass={defaultOutlineClass}
|
||||
conditionalHoverOutlineClass={conditionalHoverOutlineClass}
|
||||
conditionalFocusClass={conditionalFocusClass}
|
||||
backgroundWhenChecked={backgroundWhenChecked}
|
||||
checkGlyphColor={checkGlyphColor}
|
||||
labelColor={labelColor}
|
||||
accessibilityProps={accessibilityProps}
|
||||
|
||||
@@ -27,10 +27,6 @@ export interface CheckboxViewProps {
|
||||
value?: string;
|
||||
className: string;
|
||||
combinedBoxStyles: string;
|
||||
defaultOutlineClass: string;
|
||||
conditionalHoverOutlineClass: string;
|
||||
conditionalFocusClass: string;
|
||||
backgroundWhenChecked: string;
|
||||
checkGlyphColor: string;
|
||||
labelColor: string;
|
||||
accessibilityProps: React.HTMLAttributes<HTMLSpanElement>;
|
||||
|
||||
@@ -9,10 +9,6 @@ export function CheckboxView({
|
||||
value,
|
||||
className,
|
||||
combinedBoxStyles,
|
||||
defaultOutlineClass,
|
||||
conditionalHoverOutlineClass,
|
||||
conditionalFocusClass,
|
||||
backgroundWhenChecked,
|
||||
checkGlyphColor,
|
||||
labelColor,
|
||||
accessibilityProps,
|
||||
@@ -30,18 +26,16 @@ export function CheckboxView({
|
||||
{...accessibilityProps}
|
||||
onClick={onToggle}
|
||||
onKeyDown={onKeyDown}
|
||||
className={`${combinedBoxStyles} ${defaultOutlineClass} ${conditionalHoverOutlineClass} ${conditionalFocusClass} p-[var(--measures-spacing-004)]`}
|
||||
style={{
|
||||
backgroundColor: backgroundWhenChecked,
|
||||
}}
|
||||
className={`${combinedBoxStyles} p-[4px] ${disabled ? "" : "cursor-pointer"}`}
|
||||
>
|
||||
{/* Simple check glyph */}
|
||||
{/* Checkmark SVG per Figma - 16px size */}
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 12 12"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
className="block"
|
||||
>
|
||||
<polyline
|
||||
points="2.5 6 5 8.5 10 3.5"
|
||||
@@ -63,7 +57,7 @@ export function CheckboxView({
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
{/* Hidden native input for form compatibility (optional for now) */}
|
||||
{/* Hidden native input for form compatibility */}
|
||||
<input
|
||||
type="checkbox"
|
||||
name={name}
|
||||
|
||||
Reference in New Issue
Block a user