Buttons: the recipe's thin veils let btn-secondary/btn-ghost/glass-pill blend into the grass and sky - they now carry a stronger pale-glass veil (the Ask-pill look) over the blurred scene, ghosts plus a rim and full-contrast text. Homework make/check results gained the same red "!" report control as the feeds and the guide (a synthetic short-answer activity maps into the report flow; pinned in phase3). Reduced motion: the manual toggle only fed framer's MotionConfig, which strips transform animations - while components branched on the OS-only useReducedMotion - so translucent sheets still spring-faded their opacity in over the page (the "ugly visual glitch with the settings panel"). All 16 components now read useAppReducedMotion() (OS or toggle), and the settings sheet/scrim and the library's phone sheet go instant. Verified frame by frame: opacity 1.00 from the first frame. Contrast 0 findings, axe clean; mobile 126/126, chat 102/102, providers 20/20, wizard 95/95, phase3 31/31, bubbles 34/34, i18n 13/13, native 33/33. Version 0.5.4, SW -> freezmo-v76.
37 lines
1,023 B
TypeScript
37 lines
1,023 B
TypeScript
"use client";
|
|
|
|
import { motion } from "framer-motion";
|
|
import { useAppReducedMotion as useReducedMotion } from "@/lib/motion-pref";
|
|
|
|
import { springSnappy } from "@/lib/motion";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
/**
|
|
* The gliding highlight shared by segmented controls and pickers. One
|
|
* `layoutId` per control makes the pill slide between its items; under
|
|
* reduced motion it simply appears in place.
|
|
*/
|
|
export function SegmentedPill({
|
|
layoutId,
|
|
className,
|
|
plain,
|
|
}: {
|
|
layoutId: string;
|
|
className?: string;
|
|
/** Skip the ice gradient (for pickers that keep their own selected look). */
|
|
plain?: boolean;
|
|
}) {
|
|
const reduceMotion = useReducedMotion();
|
|
const base = plain ? "slide-pill" : "slide-pill grad-ice shadow-[0_6px_16px_-8px_rgb(56_189_248/0.7)]";
|
|
if (reduceMotion) {
|
|
return <span aria-hidden className={cn(base, className)} />;
|
|
}
|
|
return (
|
|
<motion.span
|
|
aria-hidden
|
|
layoutId={layoutId}
|
|
transition={springSnappy}
|
|
className={cn(base, className)}
|
|
/>
|
|
);
|
|
}
|