Add workflow infrastructure — ESLint, Prettier, Husky, Vitest, 7 new skills
Phase 1: Session log archived (1096→91 lines), D031 token access convention
Phase 2: ESLint v9 + Prettier + jsx-a11y, initial config and lint fixes
Phase 3: 7 new skills (polish, harden, normalize, clarify, typeset, quieter, adapt)
+ Vercel reference docs, updated audit/review-component refs
Phase 4: Husky + lint-staged pre-commit hooks, preflight updated to 8 checks
Phase 5: Vitest + Testing Library + /write-tests skill
- Badge.tsx colour maps unified to CSS variables (D031)
- 5 empty interface→type alias fixes (Switch, Radio, Divider, IconButton, Link)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,37 +24,25 @@ export interface BadgeProps extends Omit<BoxProps, 'color'> {
|
||||
|
||||
// ─── Colour maps ─────────────────────────────────────────────────────────────
|
||||
|
||||
const filledColors: Record<BadgeColor, (t: Theme) => { bg: string; text: string }> = {
|
||||
default: (t) => ({ bg: t.palette.grey[700], text: t.palette.common.white }),
|
||||
brand: (t) => ({ bg: t.palette.primary.main, text: t.palette.common.white }),
|
||||
success: (t) => ({ bg: t.palette.success.main, text: t.palette.common.white }),
|
||||
warning: (t) => ({ bg: t.palette.warning.main, text: t.palette.common.white }),
|
||||
error: (t) => ({ bg: t.palette.error.main, text: t.palette.common.white }),
|
||||
info: (t) => ({ bg: t.palette.info.main, text: t.palette.common.white }),
|
||||
const filledColors: Record<BadgeColor, { bg: string; text: string }> = {
|
||||
default: { bg: 'var(--fa-color-neutral-700)', text: 'var(--fa-color-white)' },
|
||||
brand: { bg: 'var(--fa-color-interactive-default)', text: 'var(--fa-color-white)' },
|
||||
success: { bg: 'var(--fa-color-feedback-success)', text: 'var(--fa-color-white)' },
|
||||
warning: { bg: 'var(--fa-color-feedback-warning)', text: 'var(--fa-color-white)' },
|
||||
error: { bg: 'var(--fa-color-feedback-error)', text: 'var(--fa-color-white)' },
|
||||
info: { bg: 'var(--fa-color-feedback-info)', text: 'var(--fa-color-white)' },
|
||||
};
|
||||
|
||||
const softColors: Record<BadgeColor, (t: Theme) => { bg: string; text: string }> = {
|
||||
default: (t) => ({ bg: t.palette.grey[200], text: t.palette.grey[700] }),
|
||||
brand: () => ({
|
||||
bg: 'var(--fa-color-brand-200)',
|
||||
text: 'var(--fa-color-brand-700)',
|
||||
}),
|
||||
success: () => ({
|
||||
const softColors: Record<BadgeColor, { bg: string; text: string }> = {
|
||||
default: { bg: 'var(--fa-color-neutral-200)', text: 'var(--fa-color-neutral-700)' },
|
||||
brand: { bg: 'var(--fa-color-brand-200)', text: 'var(--fa-color-brand-700)' },
|
||||
success: {
|
||||
bg: 'var(--fa-color-feedback-success-subtle)',
|
||||
text: 'var(--fa-color-feedback-success)',
|
||||
}),
|
||||
warning: () => ({
|
||||
bg: 'var(--fa-color-feedback-warning-subtle)',
|
||||
text: 'var(--fa-color-text-warning)',
|
||||
}),
|
||||
error: () => ({
|
||||
bg: 'var(--fa-color-feedback-error-subtle)',
|
||||
text: 'var(--fa-color-feedback-error)',
|
||||
}),
|
||||
info: () => ({
|
||||
bg: 'var(--fa-color-feedback-info-subtle)',
|
||||
text: 'var(--fa-color-feedback-info)',
|
||||
}),
|
||||
},
|
||||
warning: { bg: 'var(--fa-color-feedback-warning-subtle)', text: 'var(--fa-color-text-warning)' },
|
||||
error: { bg: 'var(--fa-color-feedback-error-subtle)', text: 'var(--fa-color-feedback-error)' },
|
||||
info: { bg: 'var(--fa-color-feedback-info-subtle)', text: 'var(--fa-color-feedback-info)' },
|
||||
};
|
||||
|
||||
// ─── Component ───────────────────────────────────────────────────────────────
|
||||
@@ -82,18 +70,7 @@ const softColors: Record<BadgeColor, (t: Theme) => { bg: string; text: string }>
|
||||
* provide an `aria-label` prop so screen readers can announce the status.
|
||||
*/
|
||||
export const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
|
||||
(
|
||||
{
|
||||
color = 'default',
|
||||
variant = 'soft',
|
||||
size = 'medium',
|
||||
icon,
|
||||
children,
|
||||
sx,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
({ color = 'default', variant = 'soft', size = 'medium', icon, children, sx, ...props }, ref) => {
|
||||
const sizeMap = {
|
||||
small: {
|
||||
height: 'var(--fa-badge-height-sm)',
|
||||
@@ -123,9 +100,7 @@ export const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
|
||||
component="span"
|
||||
sx={[
|
||||
(theme: Theme) => {
|
||||
const colors = variant === 'filled'
|
||||
? filledColors[color](theme)
|
||||
: softColors[color](theme);
|
||||
const colors = variant === 'filled' ? filledColors[color] : softColors[color];
|
||||
|
||||
return {
|
||||
display: 'inline-flex',
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { DividerProps as MuiDividerProps } from '@mui/material/Divider';
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Props for the FA Divider component */
|
||||
export interface DividerProps extends MuiDividerProps {}
|
||||
export type DividerProps = MuiDividerProps;
|
||||
|
||||
// ─── Component ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -31,11 +31,9 @@ export interface DividerProps extends MuiDividerProps {}
|
||||
* <Divider variant="inset" />
|
||||
* ```
|
||||
*/
|
||||
export const Divider = React.forwardRef<HTMLHRElement, DividerProps>(
|
||||
(props, ref) => {
|
||||
return <MuiDivider ref={ref} {...props} />;
|
||||
},
|
||||
);
|
||||
export const Divider = React.forwardRef<HTMLHRElement, DividerProps>((props, ref) => {
|
||||
return <MuiDivider ref={ref} {...props} />;
|
||||
});
|
||||
|
||||
Divider.displayName = 'Divider';
|
||||
export default Divider;
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { IconButtonProps as MuiIconButtonProps } from '@mui/material/IconBu
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Props for the FA IconButton component */
|
||||
export interface IconButtonProps extends MuiIconButtonProps {}
|
||||
export type IconButtonProps = MuiIconButtonProps;
|
||||
|
||||
// ─── Component ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -30,11 +30,9 @@ export interface IconButtonProps extends MuiIconButtonProps {}
|
||||
* </IconButton>
|
||||
* ```
|
||||
*/
|
||||
export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
|
||||
(props, ref) => {
|
||||
return <MuiIconButton ref={ref} {...props} />;
|
||||
},
|
||||
);
|
||||
export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>((props, ref) => {
|
||||
return <MuiIconButton ref={ref} {...props} />;
|
||||
});
|
||||
|
||||
IconButton.displayName = 'IconButton';
|
||||
export default IconButton;
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { LinkProps as MuiLinkProps } from '@mui/material/Link';
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Props for the FA Link component */
|
||||
export interface LinkProps extends MuiLinkProps {}
|
||||
export type LinkProps = MuiLinkProps;
|
||||
|
||||
// ─── Component ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -28,11 +28,9 @@ export interface LinkProps extends MuiLinkProps {}
|
||||
* For button-styled links, use `Button` with `component="a"` and `href`.
|
||||
* For navigation menu items, use Link with `underline="none"`.
|
||||
*/
|
||||
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
|
||||
(props, ref) => {
|
||||
return <MuiLink ref={ref} {...props} />;
|
||||
},
|
||||
);
|
||||
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
|
||||
return <MuiLink ref={ref} {...props} />;
|
||||
});
|
||||
|
||||
Link.displayName = 'Link';
|
||||
export default Link;
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { RadioProps as MuiRadioProps } from '@mui/material/Radio';
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Props for the FA Radio component */
|
||||
export interface RadioProps extends MuiRadioProps {}
|
||||
export type RadioProps = MuiRadioProps;
|
||||
|
||||
// ─── Component ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -32,11 +32,9 @@ export interface RadioProps extends MuiRadioProps {}
|
||||
* </RadioGroup>
|
||||
* ```
|
||||
*/
|
||||
export const Radio = React.forwardRef<HTMLButtonElement, RadioProps>(
|
||||
(props, ref) => {
|
||||
return <MuiRadio ref={ref} {...props} />;
|
||||
},
|
||||
);
|
||||
export const Radio = React.forwardRef<HTMLButtonElement, RadioProps>((props, ref) => {
|
||||
return <MuiRadio ref={ref} {...props} />;
|
||||
});
|
||||
|
||||
Radio.displayName = 'Radio';
|
||||
export default Radio;
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { SwitchProps as MuiSwitchProps } from '@mui/material/Switch';
|
||||
// ─── Types ───────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Props for the FA Switch component */
|
||||
export interface SwitchProps extends MuiSwitchProps {}
|
||||
export type SwitchProps = MuiSwitchProps;
|
||||
|
||||
// ─── Component ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -29,11 +29,9 @@ export interface SwitchProps extends MuiSwitchProps {}
|
||||
* <FormControlLabel control={<Switch />} label="Include catering" />
|
||||
* ```
|
||||
*/
|
||||
export const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
|
||||
(props, ref) => {
|
||||
return <MuiSwitch ref={ref} {...props} />;
|
||||
},
|
||||
);
|
||||
export const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>((props, ref) => {
|
||||
return <MuiSwitch ref={ref} {...props} />;
|
||||
});
|
||||
|
||||
Switch.displayName = 'Switch';
|
||||
export default Switch;
|
||||
|
||||
Reference in New Issue
Block a user