Skip to content

Commit e574da1

Browse files
Merge pull request #355 from softnetics/touch/fix/ui
fix(ui): consistent disabled tokens + filter popover UX + input-group height
2 parents 11bee56 + 2240d53 commit e574da1

14 files changed

Lines changed: 49 additions & 22 deletions

File tree

.changeset/huge-friends-flash.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@genseki/ui': patch
3+
---
4+
5+
[FIX] General UI fixes
6+
7+
- Consistent disabled state tokens across form primitives (Input, Textarea, Select, Switch, RadioGroup, Checkbox, Toggle, Tabs, Slider, Command, ColorPicker, Calendar)
8+
- InputGroup auto-detects disabled descendant input/textarea and aria-disabled, so wrappers around RichTextEditor and fieldset-disabled forms render the disabled chrome consistently
9+
- InputGroup wrapping a direct `<input>` is now exactly h-18 to match sibling Buttons (was 74px due to wrapper border on top of inner Input h-18)
10+
- Filter popover: trigger keeps a focus ring while the popover is open, and the popover content aligns to the trigger's end edge
11+
- Filter popover: highlight the currently active column in the left list
12+
- Filter popover: disable "Reset All" when no filter is selected

packages/ui/src/components/primitives/calendar.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,7 @@ function Calendar({
137137
defaultClassNames.outside,
138138
classNames?.outside
139139
),
140-
disabled: cn(
141-
'text-muted-foreground opacity-50',
142-
defaultClassNames.disabled,
143-
classNames?.disabled
144-
),
140+
disabled: cn('text-text-disabled', defaultClassNames.disabled, classNames?.disabled),
145141
hidden: cn('invisible', defaultClassNames.hidden, classNames?.hidden),
146142
}}
147143
components={{

packages/ui/src/components/primitives/color-picker.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ export const ColorPickerHue = ({ className, ...props }: ColorPickerHueProps) =>
214214
<Slider.Track className="relative my-1 h-6 w-full grow rounded-full bg-[linear-gradient(90deg,#FF0000,#FFFF00,#00FF00,#00FFFF,#0000FF,#FF00FF,#FF0000)]">
215215
<Slider.Range className="absolute h-full" />
216216
</Slider.Track>
217-
<Slider.Thumb className="block h-8 w-8 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
217+
<Slider.Thumb className="block h-8 w-8 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:bg-surface-disabled disabled:border-border-disabled" />
218218
</Slider.Root>
219219
)
220220
}
@@ -241,7 +241,7 @@ export const ColorPickerAlpha = ({ className, ...props }: ColorPickerAlphaProps)
241241
<div className="absolute inset-0 rounded-full bg-gradient-to-r from-transparent to-black/50" />
242242
<Slider.Range className="absolute h-full rounded-full bg-transparent" />
243243
</Slider.Track>
244-
<Slider.Thumb className="block h-8 w-8 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
244+
<Slider.Thumb className="block h-8 w-8 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:bg-surface-disabled disabled:border-border-disabled" />
245245
</Slider.Root>
246246
)
247247
}

packages/ui/src/components/primitives/command.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function CommandInput({
6363
<CommandPrimitive.Input
6464
data-slot="command-input"
6565
className={cn(
66-
'placeholder:text-muted-foreground flex h-20 w-full rounded-md bg-transparent py-6 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
66+
'placeholder:text-muted-foreground flex h-20 w-full rounded-md bg-transparent py-6 text-sm outline-hidden disabled:cursor-not-allowed disabled:bg-surface-disabled disabled:text-text-disabled disabled:placeholder:text-text-disabled',
6767
className
6868
)}
6969
{...props}
@@ -129,7 +129,7 @@ function CommandItem({ className, ...props }: React.ComponentProps<typeof Comman
129129
<CommandPrimitive.Item
130130
data-slot="command-item"
131131
className={cn(
132-
"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-4 rounded-sm px-4 py-3 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-8",
132+
"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-4 rounded-sm px-4 py-3 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:text-text-disabled [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-8",
133133
className
134134
)}
135135
{...props}

packages/ui/src/components/primitives/filter.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,27 @@ export function Filter<T extends FilterOptions>({ options, onChange, classNames
8989
(acc, [_, options]) => acc + options.filter((option) => option.isSelected).length,
9090
0
9191
)
92+
const internalTotalSelected = Object.values(internalOptions).reduce(
93+
(acc, opts) => acc + opts.filter((option) => option.isSelected).length,
94+
0
95+
)
9296

9397
return (
9498
<Popover open={openModal} onOpenChange={handleOpenChange}>
9599
<PopoverTrigger asChild>
96-
<Button variant="outline" className={cn('w-fit', classNames?.trigger)}>
100+
<Button
101+
variant="outline"
102+
className={cn(
103+
'w-fit data-[state=open]:border-ring data-[state=open]:ring-ring data-[state=open]:ring-[2px]',
104+
classNames?.trigger
105+
)}
106+
>
97107
<Typography className="text-icon-tertiary">Filter</Typography>
98108
<CountBadge count={totalSelected} />
99109
<SlidersHorizontalIcon className="text-icon-tertiary" />
100110
</Button>
101111
</PopoverTrigger>
102-
<PopoverContent asChild>
112+
<PopoverContent align="end" asChild>
103113
<div
104114
className={cn(
105115
'w-fit py-6 bg-surface-primary border border-border-primary rounded-xl flex flex-col gap-4 min-w-[600px] h-[436px]',
@@ -115,7 +125,11 @@ export function Filter<T extends FilterOptions>({ options, onChange, classNames
115125
{columns.map((column) => (
116126
<li
117127
key={column}
118-
className="w-full p-4 rounded-sm hover:bg-surface-primary-hover flex items-center cursor-pointer justify-between"
128+
aria-selected={selectedColumn === column}
129+
className={cn(
130+
'w-full p-4 rounded-sm hover:bg-surface-primary-hover flex items-center cursor-pointer justify-between',
131+
selectedColumn === column && 'bg-surface-primary-hover'
132+
)}
119133
onClick={() => setSelectedColumn(column)}
120134
>
121135
<Typography weight="normal" type="body">
@@ -155,7 +169,7 @@ export function Filter<T extends FilterOptions>({ options, onChange, classNames
155169
</div>
156170

157171
<div className="w-full px-6 pt-4 border-t flex items-center justify-end gap-2 border-border-primary">
158-
<Button variant="outline" onClick={reset}>
172+
<Button variant="outline" onClick={reset} disabled={internalTotalSelected === 0}>
159173
<TrashIcon />
160174
<Typography>Reset All</Typography>
161175
</Button>

packages/ui/src/components/primitives/input-group.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ function InputGroup({
3131
role="group"
3232
className={cn(
3333
'group/input-group data-disabled:bg-surface-primary-disabled data-disabled:border-border-primary bg-background border-input dark:bg-input/30 relative flex items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none',
34+
'has-[input:disabled]:bg-surface-primary-disabled has-[input:disabled]:border-border-disabled has-[input:disabled]:cursor-not-allowed',
35+
'has-[textarea:disabled]:bg-surface-primary-disabled has-[textarea:disabled]:border-border-disabled has-[textarea:disabled]:cursor-not-allowed',
36+
'aria-disabled:bg-surface-primary-disabled aria-disabled:border-border-disabled aria-disabled:cursor-not-allowed',
37+
'aria-disabled:[&_[data-slot=input-group-control]]:!bg-transparent aria-disabled:[&_[data-slot=input-group-control]]:!text-text-disabled',
3438
'h-auto min-w-0 has-[>textarea]:h-auto',
39+
'has-[>input]:h-18 has-[>input]:[&_[data-slot=input-group-control]]:h-full',
3540

3641
// Variants based on alignment.
3742
'has-[>[data-align=inline-start]]:[&>input]:pl-4',

packages/ui/src/components/primitives/input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function Input({
1212
type={type}
1313
className={cn(
1414
'bg-background file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-18 w-full min-w-0 rounded-md border px-6 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:bg-transparent file:rounded-sm file:px-4 file:h-full file:border-0 file:text-sm file:font-medium',
15-
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:text-text-disabled disabled:border-border-primary disabled:placeholder:text-text-disabled',
15+
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-surface-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:placeholder:text-text-disabled',
1616
'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[2px]',
1717
'aria-invalid:ring-destructive dark:aria-invalid:ring-destructive aria-invalid:border-destructive',
1818
className

packages/ui/src/components/primitives/radio-group.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function RadioGroupItem({
2828
<RadioGroupPrimitive.Item
2929
data-slot="radio-group-item"
3030
className={cn(
31-
'relative border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive bg-background dark:bg-input/30 aspect-square size-8 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[2px] disabled:cursor-not-allowed disabled:opacity-50 box-content',
31+
'relative border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive bg-background dark:bg-input/30 aspect-square size-8 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[2px] disabled:cursor-not-allowed disabled:bg-surface-disabled disabled:border-border-disabled box-content',
3232
className
3333
)}
3434
{...props}

packages/ui/src/components/primitives/select.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function SelectTrigger({
3232
data-slot="select-trigger"
3333
data-size={size}
3434
className={cn(
35-
"group/trigger bg-background border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring aria-invalid:ring-destructive dark:aria-invalid:ring-destructive aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-4 rounded-md border px-6 py-4 text-base font-nromal whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[2px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-18 data-[size=sm]:h-16 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-8",
35+
"group/trigger bg-background border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring aria-invalid:ring-destructive dark:aria-invalid:ring-destructive aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-4 rounded-md border px-6 py-4 text-base font-nromal whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[2px] disabled:cursor-not-allowed disabled:bg-surface-disabled disabled:text-text-disabled disabled:border-border-disabled data-[size=default]:h-18 data-[size=sm]:h-16 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-8",
3636
className
3737
)}
3838
{...props}

packages/ui/src/components/primitives/slider.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function Slider({
2727
min={min}
2828
max={max}
2929
className={cn(
30-
'relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-88 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
30+
'relative flex w-full touch-none items-center select-none data-[disabled]:cursor-not-allowed [&[data-disabled]_[data-slot=slider-track]]:bg-surface-disabled [&[data-disabled]_[data-slot=slider-range]]:bg-border-disabled [&[data-disabled]_[data-slot=slider-thumb]]:bg-surface-disabled [&[data-disabled]_[data-slot=slider-thumb]]:border-border-disabled data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-88 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
3131
className
3232
)}
3333
{...props}
@@ -49,7 +49,7 @@ function Slider({
4949
<SliderPrimitive.Thumb
5050
data-slot="slider-thumb"
5151
key={index}
52-
className="border-primary ring-ring block size-8 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-2 focus-visible:ring-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
52+
className="border-primary ring-ring block size-8 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-2 focus-visible:ring-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:bg-surface-disabled disabled:border-border-disabled"
5353
/>
5454
))}
5555
</SliderPrimitive.Root>

0 commit comments

Comments
 (0)