fix(ui): fix checkbox tick not visible in light/dark mode
The checkmark SVG was nested inside a span, making peer-checked selectors ineffective since peer only works on siblings. Fix by moving the checkmark and indeterminate SVGs to be direct siblings of the hidden input element, allowing Tailwind's peer-checked and peer-data-[indeterminate] selectors to properly toggle visibility.
This commit is contained in:
parent
6482c31f17
commit
48aa12f351
2 changed files with 47 additions and 43 deletions
|
|
@ -1,13 +1,7 @@
|
|||
import { cn } from '@tpmjs/utils/cn';
|
||||
import { forwardRef, useEffect, useRef } from 'react';
|
||||
import type { CheckboxProps } from './types';
|
||||
import {
|
||||
checkboxLabelVariants,
|
||||
checkboxUIVariants,
|
||||
checkboxVariants,
|
||||
checkmarkVariants,
|
||||
indeterminateVariants,
|
||||
} from './variants';
|
||||
import { checkboxLabelVariants, checkboxUIVariants, checkboxVariants } from './variants';
|
||||
|
||||
/**
|
||||
* Checkbox component
|
||||
|
|
@ -93,37 +87,8 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|||
/>
|
||||
);
|
||||
|
||||
const checkboxUI = (
|
||||
<span className={cn(checkboxUIVariants({ state, size }))}>
|
||||
{/* Checkmark icon */}
|
||||
<svg
|
||||
className={cn(checkmarkVariants({ size }))}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M13.5 4.5L6 12L2.5 8.5"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
{/* Indeterminate line */}
|
||||
<svg
|
||||
className={cn(indeterminateVariants({ size }))}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M4 8H12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
|
||||
</svg>
|
||||
</span>
|
||||
);
|
||||
// Visual checkbox box (background, border, etc.) - no icons inside
|
||||
const checkboxUI = <span className={cn(checkboxUIVariants({ state, size }))} />;
|
||||
|
||||
const labelElement = label ? (
|
||||
<label
|
||||
|
|
@ -137,9 +102,48 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
|||
return (
|
||||
<div className={cn('inline-flex items-center', disabled && 'cursor-not-allowed')}>
|
||||
{labelPosition === 'left' && labelElement}
|
||||
<div className="relative inline-flex">
|
||||
<div className="relative inline-flex items-center justify-center">
|
||||
{checkboxInput}
|
||||
{checkboxUI}
|
||||
{/* Checkmark icon - sibling of input so peer-checked works */}
|
||||
<svg
|
||||
className={cn(
|
||||
'pointer-events-none absolute inset-0 opacity-0 scale-0 transition-all duration-200 text-primary-foreground',
|
||||
'peer-checked:opacity-100 peer-checked:scale-100',
|
||||
size === 'sm' && 'h-4 w-4',
|
||||
size === 'md' && 'h-5 w-5',
|
||||
size === 'lg' && 'h-6 w-6'
|
||||
)}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M13.5 4.5L6 12L2.5 8.5"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
{/* Indeterminate line - sibling of input so peer selectors work */}
|
||||
<svg
|
||||
className={cn(
|
||||
'pointer-events-none absolute inset-0 opacity-0 scale-0 transition-all duration-200 text-primary-foreground',
|
||||
'peer-data-[indeterminate=true]:opacity-100 peer-data-[indeterminate=true]:scale-100',
|
||||
'peer-checked:opacity-0 peer-checked:scale-0',
|
||||
size === 'sm' && 'h-4 w-4',
|
||||
size === 'md' && 'h-5 w-5',
|
||||
size === 'lg' && 'h-6 w-6'
|
||||
)}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M4 8H12" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
|
||||
</svg>
|
||||
</div>
|
||||
{labelPosition === 'right' && labelElement}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { createVariants } from '../system/variants';
|
||||
import { formControlBase } from '../system/formVariants';
|
||||
import { createVariants } from '../system/variants';
|
||||
|
||||
/**
|
||||
* Checkbox variant definitions
|
||||
|
|
@ -100,17 +100,17 @@ export const checkboxUIVariants = createVariants({
|
|||
|
||||
/**
|
||||
* Checkmark icon variants
|
||||
* Note: Uses group-[] selectors because the SVG is nested inside the checkboxUI span,
|
||||
* not a direct sibling of the input. The checkboxUI span has peer-checked classes.
|
||||
*/
|
||||
export const checkmarkVariants = createVariants({
|
||||
base: [
|
||||
// Positioning
|
||||
'absolute inset-0',
|
||||
// Hidden by default
|
||||
// Hidden by default, visible when parent has peer-checked state
|
||||
'opacity-0 scale-0',
|
||||
// Transitions
|
||||
'transition-all duration-200',
|
||||
// Visible when checked
|
||||
'peer-checked:opacity-100 peer-checked:scale-100',
|
||||
// Color
|
||||
'text-primary-foreground',
|
||||
].join(' '),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue