Start organizational migration

This commit is contained in:
adilallo
2026-02-05 18:21:56 -07:00
parent 69074b23f3
commit db3c0274f6
161 changed files with 145 additions and 145 deletions
@@ -0,0 +1,134 @@
"use client";
import { memo } from "react";
import { useComponentId } from "../../../hooks";
import { CheckboxView } from "./Checkbox.view";
import type { CheckboxProps } from "./Checkbox.types";
import { normalizeMode, normalizeState } from "../../../../lib/propNormalization";
const CheckboxContainer = memo<CheckboxProps>(
({
checked = false,
mode: modeProp = "standard",
state: stateProp = "default",
disabled = false,
label,
className = "",
onChange,
id,
name,
value,
ariaLabel,
...props
}) => {
// Normalize props to handle both PascalCase (Figma) and lowercase (codebase)
const mode = normalizeMode(modeProp);
const state = normalizeState(stateProp);
const isInverse = mode === "inverse";
const isStandard = mode === "standard";
// Generate unique ID for accessibility if not provided
const { id: checkboxId, labelId } = useComponentId("checkbox", id);
// 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, " ");
// 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;
};
const combinedBoxStyles = getBoxStyles();
// Checkmark color per Figma
const checkGlyphColor = checked
? 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";
// 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;
onChange?.({
checked: !checked,
value,
event: e,
});
};
const accessibilityProps = {
role: "checkbox" as const,
"aria-checked": checked,
...(disabled && { "aria-disabled": true, tabIndex: -1 }),
...(!disabled && { tabIndex: 0 }),
...(ariaLabel && { "aria-label": ariaLabel }),
...(label && !ariaLabel && { "aria-labelledby": labelId }),
id: checkboxId,
...props,
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLSpanElement>) => {
if (e.key === " " || e.key === "Enter") {
e.preventDefault();
handleToggle(e);
}
};
return (
<CheckboxView
labelId={labelId}
checked={checked}
mode={mode}
state={state}
disabled={disabled}
label={label}
name={name}
value={value}
className={className}
combinedBoxStyles={combinedBoxStyles}
checkGlyphColor={checkGlyphColor}
labelColor={labelColor}
accessibilityProps={accessibilityProps}
onToggle={handleToggle}
onKeyDown={handleKeyDown}
/>
);
},
);
CheckboxContainer.displayName = "Checkbox";
export default CheckboxContainer;
@@ -0,0 +1,45 @@
import type { ModeValue, StateValue } from "../../../../lib/propNormalization";
export interface CheckboxProps {
checked?: boolean;
/**
* Mode variant. Accepts both "standard"/"Standard" and "inverse"/"Inverse" (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
*/
mode?: ModeValue;
/**
* Visual state. Accepts "default"/"Default", "hover"/"Hover", "focus"/"Focus" (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
*/
state?: StateValue;
disabled?: boolean;
label?: string;
className?: string;
onChange?: (_data: {
checked: boolean;
value?: string;
event: React.MouseEvent | React.KeyboardEvent;
}) => void;
id?: string;
name?: string;
value?: string;
ariaLabel?: string;
}
export interface CheckboxViewProps {
labelId: string;
checked: boolean;
mode: "standard" | "inverse";
state: "default" | "hover" | "focus" | "selected";
disabled: boolean;
label?: string;
name?: string;
value?: string;
className: string;
combinedBoxStyles: string;
checkGlyphColor: string;
labelColor: string;
accessibilityProps: React.HTMLAttributes<HTMLSpanElement>;
onToggle: (_e: React.MouseEvent | React.KeyboardEvent) => void;
onKeyDown: (_e: React.KeyboardEvent<HTMLSpanElement>) => void;
}
@@ -0,0 +1,74 @@
import type { CheckboxViewProps } from "./Checkbox.types";
export function CheckboxView({
labelId,
checked,
disabled,
label,
name,
value,
className,
combinedBoxStyles,
checkGlyphColor,
labelColor,
accessibilityProps,
onToggle,
onKeyDown,
}: CheckboxViewProps) {
return (
<label
className={`inline-flex items-center gap-[8px] cursor-pointer select-none ${
disabled ? "opacity-60 cursor-not-allowed" : ""
} ${className}`}
onMouseDown={(e) => e.preventDefault()}
>
<span
{...accessibilityProps}
onClick={onToggle}
onKeyDown={onKeyDown}
className={`${combinedBoxStyles} p-[4px] ${disabled ? "" : "cursor-pointer"}`}
>
{/* 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"
stroke={checkGlyphColor}
strokeWidth="1.25"
fill="none"
strokeLinecap="square"
strokeLinejoin="miter"
vectorEffect="non-scaling-stroke"
/>
</svg>
</span>
{label && (
<span
id={labelId}
className="font-inter text-[14px] leading-[18px]"
style={{ color: labelColor }}
>
{label}
</span>
)}
{/* Hidden native input for form compatibility */}
<input
type="checkbox"
name={name}
value={value}
checked={checked}
onChange={() => {}}
tabIndex={-1}
aria-hidden="true"
className="sr-only"
readOnly
/>
</label>
);
}
@@ -0,0 +1,2 @@
export { default } from "./Checkbox.container";
export type { CheckboxProps } from "./Checkbox.types";