feat(mui): 200-250ms interaction motion (button press/hover lift, input focus ring, card/chip transitions)
Buttons: 150ms press scale(0.97) + ripple; contained-primary hover lift + glow (gradient can't transition so animate transform/shadow/filter). Outlined inputs: soft brand focus ring fades in 200ms + outline color transition. Cards/chips: shadow transitions. Honors prefers-reduced-motion. Easing matches legacy cubic-bezier(0.4,0,0.2,1). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,4 +49,13 @@ describe("MUI theme", () => {
|
||||
const card = theme.components?.MuiCard?.styleOverrides?.root as any;
|
||||
expect(card?.borderRadius).toBe(16);
|
||||
});
|
||||
|
||||
it("adds 200-300ms interaction motion (press + focus ring)", () => {
|
||||
const btn = theme.components?.MuiButton?.styleOverrides?.root as any;
|
||||
expect(btn?.transition).toContain("transform");
|
||||
expect(btn?.["&:active"]?.transform).toBe("scale(0.97)");
|
||||
const input = theme.components?.MuiOutlinedInput?.styleOverrides
|
||||
?.root as any;
|
||||
expect(input?.["&.Mui-focused"]?.boxShadow).toContain("rgba");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,9 @@ const FONT_BODY = "'Plus Jakarta Sans', system-ui, sans-serif";
|
||||
const FONT_HEADING = "'Urbanist', sans-serif";
|
||||
const FONT_MONO = "'DM Mono', Menlo, monospace";
|
||||
|
||||
// Standard Material easing (matches the legacy --transition cubic-bezier).
|
||||
const EASE = "cubic-bezier(0.4, 0, 0.2, 1)";
|
||||
|
||||
export const theme = createTheme({
|
||||
cssVariables: {
|
||||
colorSchemeSelector: "[data-theme='%s']",
|
||||
@@ -51,10 +54,31 @@ export const theme = createTheme({
|
||||
MuiButton: {
|
||||
defaultProps: { disableElevation: true },
|
||||
styleOverrides: {
|
||||
root: { borderRadius: 999, paddingInline: "0.95rem" },
|
||||
root: {
|
||||
borderRadius: 999,
|
||||
paddingInline: "0.95rem",
|
||||
// Snappy press (150ms) + smooth color/shadow (250ms).
|
||||
transition: [
|
||||
`background-color 250ms ${EASE}`,
|
||||
`border-color 250ms ${EASE}`,
|
||||
`color 200ms ${EASE}`,
|
||||
`box-shadow 250ms ${EASE}`,
|
||||
`transform 150ms ${EASE}`,
|
||||
`filter 200ms ${EASE}`,
|
||||
].join(", "),
|
||||
"&:active": { transform: "scale(0.97)" },
|
||||
"@media (prefers-reduced-motion: reduce)": { transition: "none" },
|
||||
},
|
||||
containedPrimary: {
|
||||
backgroundImage: "linear-gradient(135deg, #e23a3a, #c01f1f)",
|
||||
boxShadow: "0 5px 14px rgba(214,48,49,0.32)",
|
||||
// The gradient can't transition, so animate lift + glow instead.
|
||||
"&:hover": {
|
||||
transform: "translateY(-1px)",
|
||||
filter: "brightness(1.04)",
|
||||
boxShadow: "0 8px 20px rgba(214,48,49,0.42)",
|
||||
},
|
||||
"&:active": { transform: "translateY(0) scale(0.97)" },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -64,11 +88,33 @@ export const theme = createTheme({
|
||||
borderRadius: 16,
|
||||
boxShadow:
|
||||
"0 6px 20px rgba(20,20,40,0.06), 0 1px 2px rgba(0,0,0,0.03)",
|
||||
transition: `box-shadow 250ms ${EASE}, transform 250ms ${EASE}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
styleOverrides: { root: { borderRadius: 999, fontWeight: 700 } },
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 999,
|
||||
fontWeight: 700,
|
||||
transition: `background-color 200ms ${EASE}, box-shadow 200ms ${EASE}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiOutlinedInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
// Soft brand focus ring fades in over 200ms.
|
||||
transition: `box-shadow 200ms ${EASE}`,
|
||||
"&.Mui-focused": {
|
||||
boxShadow: "0 0 0 3px rgba(199, 48, 48, 0.12)",
|
||||
},
|
||||
"@media (prefers-reduced-motion: reduce)": { transition: "none" },
|
||||
},
|
||||
notchedOutline: {
|
||||
transition: `border-color 200ms ${EASE}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user