Skip to content

Conversation

@acrowthe
Copy link
Contributor

Add a chip that can be clicked to cycle between multiple different values and appearances

Add a chip that can be clicked to cycle between multiple different values and appearances
const [ currentStateIndex, setCurrentState ] = useState(0);

useMemo(() => {
if (currentStateIndex > states?.length && currentStateIndex > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused here with the reason for adding the second part of expression. Is there a case the currentStateIndex > states?.length but can be currentStateIndex <= 0?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed the second part seems unnecessary. Any value less than 1 will make the first part of the expression false regardless of what is in states.

// specific language governing permissions and limitations
// under the License.
//
import React, { useState, useMemo } from "react";
Copy link
Contributor

@veronikaslc veronikaslc Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No React import after CARDS-2794

}
}, [states])

return <Tooltip title={states[currentStateIndex]?.tooltip}>
Copy link
Contributor

@veronikaslc veronikaslc Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we heavily rely on states[currentStateIndex]?. What if there is no states[currentStateIndex] or no states? Should we still attempt to render anything in this case case or abort early?

Also I'd add just to avoid code duplication
const state = states[currentStateIndex];

Copy link
Contributor

@marta- marta- Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just make states required and ensure it's non-empty. There's no point in a multistate chip without having the states defined.

onClick={() => {
let newIndex = (currentStateIndex + 1 >= states?.length) ? 0 : (currentStateIndex + 1);
setCurrentState(newIndex);
onChange(states[newIndex].value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are not sure states exists here (from line 79 states?.length) states[newIndex] can thow error, also if we are generally not sure states[currentStateIndex] exists states[newIndex].value can also potentially throw error

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must be sure that states is well defined before we start rendering.

Comment on lines +74 to +77
label={states[currentStateIndex]?.label}
variant={states[currentStateIndex]?.variant}
color={states[currentStateIndex]?.color}
icon={states[currentStateIndex]?.icon}
Copy link
Contributor

@marta- marta- Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I'd add just to avoid code duplication
const state = states[currentStateIndex];

Or, a less verbose way of using the state props is to define the ChipState visual props as a plain object and expand it in the rendered Chip's props:

Suggested change
label={states[currentStateIndex]?.label}
variant={states[currentStateIndex]?.variant}
color={states[currentStateIndex]?.color}
icon={states[currentStateIndex]?.icon}
{...states[currentStateIndex]?.chipProps ?? {}} // this would contain label, variant, color, icon

Comment on lines +38 to +58
/**
* A 3 state chip supporting the following 3 values and states, each with a configurable tooltip.
* Expects a single label and size that will apply to all states.
* 0: A default, outlined, empty circle icon
* 1: A success color with a checkmark icon
* -1: An error color with an x icon
*/
export function TriStateChip(props) {
const { size, label, defaultTooltip, positiveTooltip, negativeTooltip, onChange } = props;
let states = [
new ChipState(label, "outlined", "primary", <RadioButtonUncheckedIcon/>, 0, defaultTooltip),
new ChipState(label, "outlined", "success", <CheckCircleIcon/>, 1, positiveTooltip),
new ChipState(label, "outlined", "error", <CancelIcon/>, -1, negativeTooltip),
]

return MultiStateChip({
"size": size,
"states": states,
"onChange": onChange,
});
}
Copy link
Contributor

@marta- marta- Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component should be in a separate file.

color={states[currentStateIndex]?.color}
icon={states[currentStateIndex]?.icon}
onClick={() => {
let newIndex = (currentStateIndex + 1 >= states?.length) ? 0 : (currentStateIndex + 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let newIndex = (currentStateIndex + 1 >= states?.length) ? 0 : (currentStateIndex + 1);
let newIndex = (currentStateIndex + 1) % states.length);

Must make sure that we don't get to this point with undefined or empty states.

color: PropTypes.string,
icon: PropTypes.node,
value: PropTypes.string,
}))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}))
})).isRequired

}
}, [states])

return <Tooltip title={states[currentStateIndex]?.tooltip}>
Copy link
Contributor

@marta- marta- Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only render the chip if we have states. Also there will be a warning if for any reason the tooltip is missing, are we making tooltips required, should we allow them to be absent and not render the tooltip in that case (tedious!) or should we us some sort of default?

Suggested change
return <Tooltip title={states[currentStateIndex]?.tooltip}>
return states?.length > 0 &&
<Tooltip title={states[currentStateIndex]?.tooltip ?? "Click to change"}>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants