feat: tooltips for tool settings (#5586)

This commit is contained in:
Pedro Köhler 2025-11-25 11:13:01 -03:00 committed by GitHub
parent e0d74a6674
commit 411553ee91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 130 additions and 42 deletions

View File

@ -36,6 +36,7 @@ export type ButtonOptions = {
id: string; id: string;
type: 'range' | 'radio' | 'double-range' | 'custom' | 'checkbox' | 'select' | 'button'; type: 'range' | 'radio' | 'double-range' | 'custom' | 'checkbox' | 'select' | 'button';
name?: string; name?: string;
tooltip?: string;
min?: number; min?: number;
max?: number; max?: number;
step?: number; step?: number;

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import Numeric from '../Numeric'; import Numeric from '../Numeric';
import { cn } from '../../lib/utils'; import { cn } from '../../lib/utils';
import { Tooltip, TooltipContent, TooltipTrigger } from '../Tooltip';
interface RowDoubleRangeProps { interface RowDoubleRangeProps {
values: [number, number]; values: [number, number];
@ -10,6 +11,7 @@ interface RowDoubleRangeProps {
step: number; step: number;
showLabel?: boolean; showLabel?: boolean;
label?: string; label?: string;
tooltip?: string;
className?: string; className?: string;
} }
@ -21,8 +23,28 @@ const RowDoubleRange: React.FC<RowDoubleRangeProps> = ({
step, step,
showLabel = false, showLabel = false,
label = '', label = '',
tooltip,
className, className,
}) => { }) => {
const renderLabel = () => {
if (!showLabel || !label) {
return null;
}
const labelNode = <Numeric.Label showValue>{label}</Numeric.Label>;
if (!tooltip) {
return labelNode;
}
return (
<Tooltip>
<TooltipTrigger asChild>{labelNode}</TooltipTrigger>
<TooltipContent side="top">{tooltip}</TooltipContent>
</Tooltip>
);
};
return ( return (
<Numeric.Container <Numeric.Container
mode="doubleRange" mode="doubleRange"
@ -33,7 +55,7 @@ const RowDoubleRange: React.FC<RowDoubleRangeProps> = ({
step={step} step={step}
className={cn('flex flex-col space-y-2', className)} className={cn('flex flex-col space-y-2', className)}
> >
{showLabel && <Numeric.Label showValue>{label}</Numeric.Label>} {renderLabel()}
<Numeric.DoubleRange showNumberInputs /> <Numeric.DoubleRange showNumberInputs />
</Numeric.Container> </Numeric.Container>
); );

View File

@ -2,6 +2,7 @@ import React from 'react';
import { Label } from '../Label'; import { Label } from '../Label';
import { Tabs, TabsList, TabsTrigger } from '../Tabs'; import { Tabs, TabsList, TabsTrigger } from '../Tabs';
import { cn } from '../../lib/utils'; import { cn } from '../../lib/utils';
import { Tooltip, TooltipContent, TooltipTrigger } from '../Tooltip';
interface RadioValue { interface RadioValue {
value: string; value: string;
@ -14,6 +15,7 @@ interface RadioOption {
value: string; value: string;
values: RadioValue[]; values: RadioValue[];
onChange?: (val: string) => void; onChange?: (val: string) => void;
tooltip?: string;
} }
interface RowSegmentedControlProps { interface RowSegmentedControlProps {
@ -38,7 +40,18 @@ export const RowSegmentedControl: React.FC<RowSegmentedControlProps> = ({
className={cn('flex items-center justify-between text-[13px]', className)} className={cn('flex items-center justify-between text-[13px]', className)}
key={option.id} key={option.id}
> >
<Label className="mr-2">{option.name}</Label> <Label className="mr-2">
{option.tooltip ? (
<Tooltip>
<TooltipTrigger asChild>
<span className="cursor-help">{option.name}</span>
</TooltipTrigger>
<TooltipContent side="top">{option.tooltip}</TooltipContent>
</Tooltip>
) : (
option.name
)}
</Label>
<div className="max-w-1/2"> <div className="max-w-1/2">
<Tabs <Tabs
value={option.value} value={option.value}

View File

@ -7,6 +7,7 @@ import { Checkbox } from '../Checkbox/Checkbox';
import { Label } from '../Label'; import { Label } from '../Label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select';
import { Switch } from '../Switch'; import { Switch } from '../Switch';
import { Tooltip, TooltipContent, TooltipTrigger } from '../Tooltip';
const SETTING_TYPES = { const SETTING_TYPES = {
RANGE: 'range', RANGE: 'range',
@ -61,13 +62,32 @@ function ToolSettings({ options }) {
); );
} }
const renderLabelWithTooltip = (label: React.ReactNode, tooltip?: string) => {
if (!label) {
return null;
}
if (!tooltip) {
return <span>{label}</span>;
}
return (
<Tooltip>
<TooltipTrigger asChild>
<span className="cursor-help">{label}</span>
</TooltipTrigger>
<TooltipContent side="top">{tooltip}</TooltipContent>
</Tooltip>
);
};
const renderRangeSetting = option => { const renderRangeSetting = option => {
return ( return (
<div <div
className="flex items-center" className="flex items-center"
key={option.id} key={option.id}
> >
<div className="w-1/3 text-[13px]">{option.name}</div> <div className="w-1/3 text-[13px]">{renderLabelWithTooltip(option.name, option.tooltip)}</div>
<div <div
className="w-2/3" className="w-2/3"
data-cy={option.id} data-cy={option.id}
@ -98,15 +118,25 @@ const renderRadioSetting = option => {
function renderDoubleRangeSetting(option) { function renderDoubleRangeSetting(option) {
return ( return (
<RowDoubleRange <div
className="flex items-center"
key={option.id} key={option.id}
>
<div className="w-1/3 text-[13px]">
{renderLabelWithTooltip(option.name, option.tooltip)}
</div>
<div className="w-2/3">
<RowDoubleRange
values={option.value} values={option.value}
onChange={option.onChange} onChange={option.onChange}
minValue={option.min} minValue={option.min}
maxValue={option.max} maxValue={option.max}
step={option.step} step={option.step}
showLabel={false} showLabel={false}
tooltip={option.tooltip}
/> />
</div>
</div>
); );
} }
@ -119,15 +149,38 @@ const renderCustomSetting = option => {
}; };
const renderButtonSetting = option => { const renderButtonSetting = option => {
return ( const button = (
<Button <Button
key={option.id} key={option.id}
variant="ghost" variant={option.variant || 'ghost'}
className={option.className || ''}
onClick={() => option.onChange()} onClick={() => option.onChange()}
> >
{option.name} {option.name}
</Button> </Button>
); );
if (option.tooltip) {
return (
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent side="top">{option.tooltip}</TooltipContent>
</Tooltip>
);
}
return button;
};
const renderCheckboxLabel = option => {
return (
<Label
htmlFor={option.id}
className="cursor-pointer"
>
{renderLabelWithTooltip(option.name, option.tooltip)}
</Label>
);
}; };
const renderCheckboxSetting = option => { const renderCheckboxSetting = option => {
@ -143,12 +196,7 @@ const renderCheckboxSetting = option => {
option.onChange?.(checked); option.onChange?.(checked);
}} }}
/> />
<Label {renderCheckboxLabel(option)}
htmlFor={option.id}
className="cursor-pointer"
>
{option.name}
</Label>
</div> </div>
); );
}; };
@ -166,20 +214,22 @@ const renderSwitchSetting = option => {
option.onChange?.(checked); option.onChange?.(checked);
}} }}
/> />
<Label {renderCheckboxLabel(option)}
htmlFor={option.id}
className="cursor-pointer"
>
{option.name}
</Label>
</div> </div>
); );
}; };
const renderSelectSetting = option => { const renderSelectSetting = option => {
return ( return (
<Select <div
className="flex items-center"
key={option.id} key={option.id}
>
<div className="w-1/3 text-[13px]">
{renderLabelWithTooltip(option.name, option.tooltip)}
</div>
<div className="w-2/3">
<Select
onValueChange={value => option.onChange?.(value)} onValueChange={value => option.onChange?.(value)}
value={option.value} value={option.value}
> >
@ -197,6 +247,8 @@ const renderSelectSetting = option => {
))} ))}
</SelectContent> </SelectContent>
</Select> </Select>
</div>
</div>
); );
}; };