mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
fix(ui): align the select chevron symmetrically with the value inset
Both select primitives parked the trailing chevron visibly farther from the right edge than the value text sits from the left. The shadcn trigger gets a -2 px optical nudge to offset the chevron glyph's internal padding. The native select drops the OS-drawn arrow (`appearance-none`) and paints a chevron background at a 12 px right inset mirroring the left `px-3` padding, kept on the single `<select>` element so call-site width and margin classes still compose unchanged.
This commit is contained in:
1 parent
0e184e7f1b
commit
646ef164ae
2 files changed
+30
-3
No files matched your search
@@ -37,20 +37,40 @@ import { cn } from "@/lib/utils";
|
||||
*/
|
||||
// v1.4.34 IW-G — floor at 44 px on mobile to clear WCAG 2.5.5; shrink
|
||||
// to 40 px on sm+ where the pointer precision is higher.
|
||||
//
|
||||
// Chevron symmetry: `appearance-none` drops the browser-drawn dropdown arrow,
|
||||
// whose right inset is OS-controlled and reads visibly farther from the edge
|
||||
// than the value text sits from the left. We paint our own chevron as a
|
||||
// background SVG positioned `right 0.75rem center` (12 px) so its inset mirrors
|
||||
// the left text padding (`px-3`) — matching the shadcn `<SelectTrigger>`.
|
||||
// Doing it as a background (rather than an overlay element) keeps `<select>` a
|
||||
// single element, so every call site's width / margin className still composes
|
||||
// straight onto it. `pe-9` reserves room so a long value never runs under the
|
||||
// chevron. The chevron glyph is the same path Lucide's `ChevronDownIcon` draws,
|
||||
// at `currentColor` with 50 % opacity to match the trigger.
|
||||
const CHEVRON_SVG =
|
||||
"url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='0.5'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\")";
|
||||
|
||||
const NATIVE_SELECT_CLASS =
|
||||
"border-input bg-background text-foreground ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-11 sm:h-10 w-full rounded-md border px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none";
|
||||
"border-input bg-background text-foreground ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-11 sm:h-10 w-full appearance-none rounded-md border ps-3 pe-9 py-1 text-sm shadow-xs transition-[color,box-shadow] focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none bg-[image:var(--native-select-chevron)] bg-[length:1rem] bg-[position:right_0.75rem_center] bg-no-repeat";
|
||||
|
||||
export type NativeSelectProps = React.SelectHTMLAttributes<HTMLSelectElement>;
|
||||
|
||||
export const NativeSelect = React.forwardRef<
|
||||
HTMLSelectElement,
|
||||
NativeSelectProps
|
||||
>(function NativeSelect({ className, children, ...props }, ref) {
|
||||
>(function NativeSelect({ className, children, style, ...props }, ref) {
|
||||
return (
|
||||
<select
|
||||
ref={ref}
|
||||
data-slot="native-select"
|
||||
className={cn(NATIVE_SELECT_CLASS, className)}
|
||||
style={
|
||||
{
|
||||
"--native-select-chevron": CHEVRON_SVG,
|
||||
...style,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -56,7 +56,14 @@ function SelectTrigger({
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
{/* `-me-0.5` (-2 px end margin) optically aligns the chevron with the
|
||||
left text inset. The trigger box is `px-3` (12 px both sides), but
|
||||
the Lucide chevron glyph carries ~2 px of empty space inside its
|
||||
16 px bounding box, so the *visible* stroke landed ~2 px farther
|
||||
from the right edge than the value text sits from the left — the
|
||||
trigger read lopsided. Pulling the icon box 2 px toward the edge
|
||||
makes the visible chevron and the value text inset symmetric. */}
|
||||
<ChevronDownIcon className="-me-0.5 size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user