feat(motion): add interactive micro-feedback
This commit is contained in:
@@ -18,19 +18,19 @@ export const themeDetails = {
|
||||
}
|
||||
} as const satisfies Record<ThemeName, { label: string; note: string }>;
|
||||
|
||||
export const motionModeNames = ["default", "reduced"] as const;
|
||||
export const motionModeNames = ["interactive", "static"] as const;
|
||||
export type MotionModeName = (typeof motionModeNames)[number];
|
||||
|
||||
export const defaultMotionMode: MotionModeName = "default";
|
||||
export const defaultMotionMode: MotionModeName = "interactive";
|
||||
|
||||
export const motionModeDetails = {
|
||||
default: {
|
||||
label: "Default",
|
||||
note: "Standard Cadence UI motion for hover, press, overlays, and hierarchy"
|
||||
interactive: {
|
||||
label: "Interactive",
|
||||
note: "Micro-interactions with hover lift, press feedback, focus transitions, and animated state changes"
|
||||
},
|
||||
reduced: {
|
||||
label: "Reduced",
|
||||
note: "Collapse durations, distances, and animated feedback"
|
||||
static: {
|
||||
label: "Static",
|
||||
note: "Keep visual states readable while removing motion-heavy feedback and animation"
|
||||
}
|
||||
} as const satisfies Record<MotionModeName, { label: string; note: string }>;
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
:root,
|
||||
:root[data-motion="default"],
|
||||
[data-motion="default"] {
|
||||
:root[data-motion="interactive"],
|
||||
[data-motion="interactive"] {
|
||||
--dur-instant: 1ms;
|
||||
--dur-fast: 120ms;
|
||||
--dur-fast: 140ms;
|
||||
--dur-base: 200ms;
|
||||
--dur-slow: 320ms;
|
||||
--dur-deliberate: 460ms;
|
||||
--dur-slow: 280ms;
|
||||
--dur-deliberate: 300ms;
|
||||
|
||||
--ease-standard: cubic-bezier(0.22, 1, 0.36, 1);
|
||||
--ease-emphasized: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--ease-exit: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-standard: cubic-bezier(0.25, 1, 0.5, 1);
|
||||
--ease-emphasized: cubic-bezier(0.22, 1, 0.36, 1);
|
||||
--ease-exit: cubic-bezier(0.3, 1, 0.5, 1);
|
||||
|
||||
--distance-xs: 4px;
|
||||
--distance-sm: 8px;
|
||||
@@ -21,8 +21,8 @@
|
||||
--scale-pop: 1.02;
|
||||
}
|
||||
|
||||
:root[data-motion="reduced"],
|
||||
[data-motion="reduced"] {
|
||||
:root[data-motion="static"],
|
||||
[data-motion="static"] {
|
||||
--dur-instant: 1ms;
|
||||
--dur-fast: 1ms;
|
||||
--dur-base: 1ms;
|
||||
@@ -38,12 +38,12 @@
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
|
||||
:root[data-motion="reduced"] *,
|
||||
:root[data-motion="reduced"] *::before,
|
||||
:root[data-motion="reduced"] *::after,
|
||||
[data-motion="reduced"] *,
|
||||
[data-motion="reduced"] *::before,
|
||||
[data-motion="reduced"] *::after {
|
||||
:root[data-motion="static"] *,
|
||||
:root[data-motion="static"] *::before,
|
||||
:root[data-motion="static"] *::after,
|
||||
[data-motion="static"] *,
|
||||
[data-motion="static"] *::before,
|
||||
[data-motion="static"] *::after {
|
||||
animation-duration: 1ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
scroll-behavior: auto !important;
|
||||
@@ -113,17 +113,32 @@
|
||||
}
|
||||
|
||||
.motion-pressable {
|
||||
transition-duration: var(--dur-fast);
|
||||
transition-duration: var(--dur-base);
|
||||
transition-property: color, background-color, border-color, box-shadow, transform;
|
||||
transition-timing-function: var(--ease-standard);
|
||||
transition-timing-function: var(--ease-emphasized);
|
||||
will-change: transform, box-shadow;
|
||||
}
|
||||
|
||||
.motion-pressable:hover {
|
||||
transform: translateY(calc(var(--distance-xs) * -0.25)) scale(var(--scale-hover));
|
||||
@media (hover: hover) {
|
||||
.motion-pressable:hover {
|
||||
transform: translateY(var(--ui-button-hover-translate, -1px))
|
||||
scale(var(--ui-button-hover-scale, 1.02));
|
||||
box-shadow: var(--ui-button-hover-shadow, var(--shadow-sm));
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-motion="static"] .motion-pressable:hover,
|
||||
[data-motion="static"] .motion-pressable:hover,
|
||||
:root[data-motion="static"] .motion-pressable:active,
|
||||
[data-motion="static"] .motion-pressable:active {
|
||||
box-shadow: inherit;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.motion-pressable:active {
|
||||
transform: scale(var(--scale-press));
|
||||
transform: translateY(0) scale(var(--ui-button-press-scale, var(--scale-press)));
|
||||
box-shadow: var(--ui-button-active-shadow, var(--shadow-xs));
|
||||
transition-duration: var(--dur-fast);
|
||||
}
|
||||
|
||||
.motion-enter-fade {
|
||||
|
||||
Reference in New Issue
Block a user