diff --git a/packages/core/src/components/segmented-control/_segmented-control.scss b/packages/core/src/components/segmented-control/_segmented-control.scss index 42887e342b..ed979a5444 100644 --- a/packages/core/src/components/segmented-control/_segmented-control.scss +++ b/packages/core/src/components/segmented-control/_segmented-control.scss @@ -8,6 +8,11 @@ gap: 3px; padding: 3px; + &.#{$ns}-compact { + gap: 0; + padding: 0; + } + &.#{$ns}-inline { display: inline-flex; } @@ -20,7 +25,7 @@ } } - > .#{$ns}-button:not(.#{$ns}-minimal) { + > .#{$ns}-button.#{$ns}-selected { &:not(.#{$ns}-intent-primary) { background-color: $white; diff --git a/packages/core/src/components/segmented-control/segmentedControl.tsx b/packages/core/src/components/segmented-control/segmentedControl.tsx index ff638ae56c..097402ff20 100644 --- a/packages/core/src/components/segmented-control/segmentedControl.tsx +++ b/packages/core/src/components/segmented-control/segmentedControl.tsx @@ -30,6 +30,8 @@ import { Button } from "../button/buttons"; export type SegmentedControlIntent = typeof Intent.NONE | typeof Intent.PRIMARY; +type SegmentedControlButtonProps = Pick; + /** * SegmentedControl component props. */ @@ -37,6 +39,13 @@ export interface SegmentedControlProps extends Props, ControlledValueProps, React.RefAttributes { + /** + * Whether the control should use compact styles. + * + * @default false + */ + compact?: boolean; + /** * Whether the control should take up the full width of its container. * @@ -66,6 +75,24 @@ export interface SegmentedControlProps */ options: Array>; + /** + * Style props for the button elements. + */ + buttonProps?: { + /** + * Props applied to selected button + * + * @default { className: 'bp5-selected' } + */ + selected?: SegmentedControlButtonProps; + /** + * Props applied to non-selected buttons + * + * @default { className: 'bp5-minimal' } + */ + nonSelected?: SegmentedControlButtonProps; + }; + /** * Aria role for the overall component. Child buttons get appropriate roles. * @@ -90,7 +117,9 @@ export interface SegmentedControlProps */ export const SegmentedControl: React.FC = React.forwardRef((props, ref) => { const { + buttonProps, className, + compact, defaultValue, fill, inline, @@ -148,10 +177,15 @@ export const SegmentedControl: React.FC = React.forwardRe ); const classes = classNames(Classes.SEGMENTED_CONTROL, className, { + [Classes.COMPACT]: compact, + [Classes.BUTTON_GROUP]: compact, [Classes.FILL]: fill, [Classes.INLINE]: inline, }); + const selectedButtonProps = buttonProps?.selected ?? { className: Classes.SELECTED }; + const nonSelectedButtonProps = buttonProps?.nonSelected ?? { className: Classes.MINIMAL }; + const isAnySelected = options.some(option => selectedValue === option.value); return ( @@ -166,9 +200,9 @@ export const SegmentedControl: React.FC = React.forwardRe const isSelected = selectedValue === option.value; return ( = React.forwardRe }); SegmentedControl.displayName = `${DISPLAYNAME_PREFIX}.SegmentedControl`; -interface SegmentedControlOptionProps - extends OptionProps, - Pick, - Pick, - React.AriaAttributes { - isSelected: boolean; +interface SegmentedControlOptionProps extends OptionProps, Omit { onClick: (value: string, targetElement: HTMLElement) => void; } -function SegmentedControlOption({ isSelected, label, onClick, value, ...buttonProps }: SegmentedControlOptionProps) { +function SegmentedControlOption({ label, onClick, value, ...buttonProps }: SegmentedControlOptionProps) { const handleClick = React.useCallback( (event: React.MouseEvent) => onClick?.(value, event.currentTarget), [onClick, value], ); - return