ui: add indeterminate state to Checkbox component
Add support for the indeterminate state in the Checkbox component, displaying a horizontal dash icon instead of a checkmark. This is useful for "select all" scenarios in tables where only some rows are selected. The indeterminate state maintains the unchecked visual style (white background with border) while showing the dash icon. Signed-off-by: Johan Persson <johanopersson@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/ui': patch
|
||||
---
|
||||
|
||||
Added indeterminate state support to the Checkbox component for handling partial selection scenarios like table header checkboxes.
|
||||
|
||||
Affected components: Checkbox
|
||||
@@ -460,6 +460,7 @@ export const CheckboxDefinition: {
|
||||
};
|
||||
readonly dataAttributes: {
|
||||
readonly selected: readonly [true, false];
|
||||
readonly indeterminate: readonly [true, false];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -62,7 +62,14 @@
|
||||
color: var(--bui-fg-solid);
|
||||
}
|
||||
|
||||
.bui-Checkbox[data-hovered]:not([data-selected]) & {
|
||||
.bui-Checkbox[data-indeterminate] & {
|
||||
background-color: var(--bui-bg-surface-1);
|
||||
box-shadow: inset 0 0 0 1px var(--bui-border);
|
||||
color: var(--bui-fg-primary);
|
||||
}
|
||||
|
||||
.bui-Checkbox[data-hovered]:not([data-selected]):not([data-indeterminate])
|
||||
& {
|
||||
box-shadow: inset 0 0 0 1px var(--bui-border-hover);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,16 +28,27 @@ export const Default = meta.story({
|
||||
},
|
||||
});
|
||||
|
||||
export const Indeterminate = meta.story({
|
||||
args: {
|
||||
children: 'Select all',
|
||||
isIndeterminate: true,
|
||||
},
|
||||
});
|
||||
|
||||
export const AllVariants = meta.story({
|
||||
...Default.input,
|
||||
render: () => (
|
||||
<Flex direction="column" gap="2">
|
||||
<Checkbox>Unchecked</Checkbox>
|
||||
<Checkbox isSelected>Checked</Checkbox>
|
||||
<Checkbox isIndeterminate>Indeterminate</Checkbox>
|
||||
<Checkbox isDisabled>Disabled</Checkbox>
|
||||
<Checkbox isSelected isDisabled>
|
||||
Checked & Disabled
|
||||
</Checkbox>
|
||||
<Checkbox isIndeterminate isDisabled>
|
||||
Indeterminate & Disabled
|
||||
</Checkbox>
|
||||
</Flex>
|
||||
),
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useStyles } from '../../hooks/useStyles';
|
||||
import { CheckboxDefinition } from './definition';
|
||||
import clsx from 'clsx';
|
||||
import styles from './Checkbox.module.css';
|
||||
import { RiCheckLine } from '@remixicon/react';
|
||||
import { RiCheckLine, RiSubtractLine } from '@remixicon/react';
|
||||
|
||||
/** @public */
|
||||
export const Checkbox = forwardRef<HTMLLabelElement, CheckboxProps>(
|
||||
@@ -35,12 +35,23 @@ export const Checkbox = forwardRef<HTMLLabelElement, CheckboxProps>(
|
||||
className={clsx(classNames.root, styles[classNames.root], className)}
|
||||
{...rest}
|
||||
>
|
||||
<div
|
||||
className={clsx(classNames.indicator, styles[classNames.indicator])}
|
||||
>
|
||||
<RiCheckLine size={12} />
|
||||
</div>
|
||||
{children}
|
||||
{({ isIndeterminate }) => (
|
||||
<>
|
||||
<div
|
||||
className={clsx(
|
||||
classNames.indicator,
|
||||
styles[classNames.indicator],
|
||||
)}
|
||||
>
|
||||
{isIndeterminate ? (
|
||||
<RiSubtractLine size={12} />
|
||||
) : (
|
||||
<RiCheckLine size={12} />
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</>
|
||||
)}
|
||||
</RACheckbox>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -27,5 +27,6 @@ export const CheckboxDefinition = {
|
||||
},
|
||||
dataAttributes: {
|
||||
selected: [true, false] as const,
|
||||
indeterminate: [true, false] as const,
|
||||
},
|
||||
} as const satisfies ComponentDefinition;
|
||||
|
||||
Reference in New Issue
Block a user