Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/huge-friends-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@genseki/ui': patch
---

[FIX] General UI fixes

- Consistent disabled state tokens across form primitives (Input, Textarea, Select, Switch, RadioGroup, Checkbox, Toggle, Tabs, Slider, Command, ColorPicker, Calendar)
- InputGroup auto-detects disabled descendant input/textarea and aria-disabled, so wrappers around RichTextEditor and fieldset-disabled forms render the disabled chrome consistently
- 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)
- Filter popover: trigger keeps a focus ring while the popover is open, and the popover content aligns to the trigger's end edge
- Filter popover: highlight the currently active column in the left list
- Filter popover: disable "Reset All" when no filter is selected
6 changes: 1 addition & 5 deletions packages/ui/src/components/primitives/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,7 @@ function Calendar({
defaultClassNames.outside,
classNames?.outside
),
disabled: cn(
'text-muted-foreground opacity-50',
defaultClassNames.disabled,
classNames?.disabled
),
disabled: cn('text-text-disabled', defaultClassNames.disabled, classNames?.disabled),
hidden: cn('invisible', defaultClassNames.hidden, classNames?.hidden),
}}
components={{
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/primitives/color-picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export const ColorPickerHue = ({ className, ...props }: ColorPickerHueProps) =>
<Slider.Track className="relative my-1 h-6 w-full grow rounded-full bg-[linear-gradient(90deg,#FF0000,#FFFF00,#00FF00,#00FFFF,#0000FF,#FF00FF,#FF0000)]">
<Slider.Range className="absolute h-full" />
</Slider.Track>
<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" />
<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" />
</Slider.Root>
)
}
Expand All @@ -241,7 +241,7 @@ export const ColorPickerAlpha = ({ className, ...props }: ColorPickerAlphaProps)
<div className="absolute inset-0 rounded-full bg-gradient-to-r from-transparent to-black/50" />
<Slider.Range className="absolute h-full rounded-full bg-transparent" />
</Slider.Track>
<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" />
<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" />
</Slider.Root>
)
}
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/primitives/command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function CommandInput({
<CommandPrimitive.Input
data-slot="command-input"
className={cn(
'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',
'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',
className
)}
{...props}
Expand Down Expand Up @@ -129,7 +129,7 @@ function CommandItem({ className, ...props }: React.ComponentProps<typeof Comman
<CommandPrimitive.Item
data-slot="command-item"
className={cn(
"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",
"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",
className
)}
{...props}
Expand Down
22 changes: 18 additions & 4 deletions packages/ui/src/components/primitives/filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,27 @@ export function Filter<T extends FilterOptions>({ options, onChange, classNames
(acc, [_, options]) => acc + options.filter((option) => option.isSelected).length,
0
)
const internalTotalSelected = Object.values(internalOptions).reduce(
(acc, opts) => acc + opts.filter((option) => option.isSelected).length,
0
)

return (
<Popover open={openModal} onOpenChange={handleOpenChange}>
<PopoverTrigger asChild>
<Button variant="outline" className={cn('w-fit', classNames?.trigger)}>
<Button
variant="outline"
className={cn(
'w-fit data-[state=open]:border-ring data-[state=open]:ring-ring data-[state=open]:ring-[2px]',
classNames?.trigger
)}
>
<Typography className="text-icon-tertiary">Filter</Typography>
<CountBadge count={totalSelected} />
<SlidersHorizontalIcon className="text-icon-tertiary" />
</Button>
</PopoverTrigger>
<PopoverContent asChild>
<PopoverContent align="end" asChild>
<div
className={cn(
'w-fit py-6 bg-surface-primary border border-border-primary rounded-xl flex flex-col gap-4 min-w-[600px] h-[436px]',
Expand All @@ -115,7 +125,11 @@ export function Filter<T extends FilterOptions>({ options, onChange, classNames
{columns.map((column) => (
<li
key={column}
className="w-full p-4 rounded-sm hover:bg-surface-primary-hover flex items-center cursor-pointer justify-between"
aria-selected={selectedColumn === column}
className={cn(
'w-full p-4 rounded-sm hover:bg-surface-primary-hover flex items-center cursor-pointer justify-between',
selectedColumn === column && 'bg-surface-primary-hover'
)}
onClick={() => setSelectedColumn(column)}
>
<Typography weight="normal" type="body">
Expand Down Expand Up @@ -155,7 +169,7 @@ export function Filter<T extends FilterOptions>({ options, onChange, classNames
</div>

<div className="w-full px-6 pt-4 border-t flex items-center justify-end gap-2 border-border-primary">
<Button variant="outline" onClick={reset}>
<Button variant="outline" onClick={reset} disabled={internalTotalSelected === 0}>
<TrashIcon />
<Typography>Reset All</Typography>
</Button>
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/src/components/primitives/input-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ function InputGroup({
role="group"
className={cn(
'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',
'has-[input:disabled]:bg-surface-primary-disabled has-[input:disabled]:border-border-disabled has-[input:disabled]:cursor-not-allowed',
'has-[textarea:disabled]:bg-surface-primary-disabled has-[textarea:disabled]:border-border-disabled has-[textarea:disabled]:cursor-not-allowed',
'aria-disabled:bg-surface-primary-disabled aria-disabled:border-border-disabled aria-disabled:cursor-not-allowed',
'aria-disabled:[&_[data-slot=input-group-control]]:!bg-transparent aria-disabled:[&_[data-slot=input-group-control]]:!text-text-disabled',
'h-auto min-w-0 has-[>textarea]:h-auto',
'has-[>input]:h-18 has-[>input]:[&_[data-slot=input-group-control]]:h-full',

// Variants based on alignment.
'has-[>[data-align=inline-start]]:[&>input]:pl-4',
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/primitives/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function Input({
type={type}
className={cn(
'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',
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:text-text-disabled disabled:border-border-primary disabled:placeholder:text-text-disabled',
'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',
'focus-visible:border-ring focus-visible:ring-ring focus-visible:ring-[2px]',
'aria-invalid:ring-destructive dark:aria-invalid:ring-destructive aria-invalid:border-destructive',
className
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/primitives/radio-group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function RadioGroupItem({
<RadioGroupPrimitive.Item
data-slot="radio-group-item"
className={cn(
'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',
'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',
className
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/primitives/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function SelectTrigger({
data-slot="select-trigger"
data-size={size}
className={cn(
"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",
"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",
className
)}
{...props}
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/primitives/slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function Slider({
min={min}
max={max}
className={cn(
'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',
'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',
className
)}
{...props}
Expand All @@ -49,7 +49,7 @@ function Slider({
<SliderPrimitive.Thumb
data-slot="slider-thumb"
key={index}
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"
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"
/>
))}
</SliderPrimitive.Root>
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/primitives/switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function Switch({ className, ...props }: React.ComponentProps<typeof SwitchPrimi
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring dark:data-[state=unchecked]:bg-input/80 inline-flex h-fit w-16 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[2px] disabled:cursor-not-allowed disabled:opacity-50',
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring dark:data-[state=unchecked]:bg-input/80 inline-flex h-fit w-16 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[2px] disabled:cursor-not-allowed disabled:data-[state=checked]:bg-surface-disabled disabled:data-[state=unchecked]:bg-surface-disabled disabled:border-border-disabled',
className
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/primitives/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const tabListVariants = cva<{ variant: Record<Variants, any> }>(
)

const tabVariants = cva<{ variant: Record<Variants, any> }>(
"inline-flex flex-1 items-center justify-center text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-8",
"inline-flex flex-1 items-center justify-center text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none disabled:pointer-events-none disabled:text-text-disabled [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-8",
{
variants: {
variant: {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/primitives/textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
data-slot="textarea"
className={cn(
'border-input placeholder: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 flex field-sizing-content min-h-32 w-full rounded-md border bg-transparent px-7 py-6 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[2px]',
'disabled:pointer-events-none disabled::cursor-not-allowed disabled:text-text-disabled disabled:border-border-primary disabled:placeholder:text-text-disabled',
'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',
className
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/primitives/toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '../../utils/cn'

const toggleVariants = cva(
"inline-flex items-center justify-center gap-4 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-8 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[2px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive aria-invalid:border-destructive whitespace-nowrap",
"inline-flex items-center justify-center gap-4 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:bg-surface-disabled disabled:text-text-disabled data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-8 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[2px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive aria-invalid:border-destructive whitespace-nowrap",
{
variants: {
variant: {
Expand Down
Loading