Files
community-rule/app/components/controls/Chip/Chip.container.tsx
T
adilalloandCursor 20ea4a2f30 Give MultiSelect chips accessible names and start creation fields empty.
Catalog chips now announce Select or Deselect so they are named for assistive tech. Method and value modals open blank; Generate draft inserts the catalog copy that used to be prefilled, and Customize still keeps the section headings.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 15:59:00 -06:00

108 lines
3.0 KiB
TypeScript

"use client";
import { memo, useState, useEffect, useRef } from "react";
import { useTranslation } from "../../../contexts/MessagesContext";
import ChipView from "./Chip.view";
import type { ChipProps } from "./Chip.types";
/**
* Figma: "Control / Chip". Compact pill-shaped tag with
* selectable, removable, and inline-editable (custom) states.
*/
const ChipContainer = memo<ChipProps>(
({
label,
state: stateProp = "unselected",
palette: paletteProp = "default",
size: sizeProp = "s",
className = "",
disabled,
onClick,
onRemove,
onCheck,
onClose,
ariaLabel,
}) => {
const t = useTranslation("controlsChrome");
const state = stateProp;
const palette = paletteProp;
const size = sizeProp;
const isDisabled = disabled ?? state === "disabled";
const isCustom = state === "custom";
// Manage input value for custom state
const [inputValue, setInputValue] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
// Focus input when custom state is active
useEffect(() => {
if (isCustom && inputRef.current) {
inputRef.current.focus();
}
}, [isCustom]);
const handleCheck = (
value: string,
event: React.MouseEvent<HTMLButtonElement>,
) => {
if (onCheck && value.trim()) {
onCheck(value.trim(), event);
// Reset input after successful check
setInputValue("");
}
};
const handleClose = (event: React.MouseEvent<HTMLButtonElement>) => {
if (onClose) {
onClose(event);
} else if (onRemove) {
// Fallback to onRemove if onClose not provided
onRemove(event);
}
// Reset input value when closing
setInputValue("");
};
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === "Enter" && inputValue.trim() && onCheck) {
event.preventDefault();
handleCheck(
inputValue.trim(),
event as unknown as React.MouseEvent<HTMLButtonElement>,
);
} else if (event.key === "Escape" && onClose) {
event.preventDefault();
handleClose(event as unknown as React.MouseEvent<HTMLButtonElement>);
}
};
return (
<ChipView
label={label}
state={state}
palette={palette}
size={size}
className={className}
disabled={isDisabled}
onClick={onClick}
onRemove={onRemove}
onCheck={handleCheck}
onClose={handleClose}
inputValue={isCustom ? inputValue : undefined}
onInputChange={isCustom ? setInputValue : undefined}
onInputKeyDown={isCustom ? handleKeyDown : undefined}
inputRef={isCustom ? inputRef : undefined}
ariaLabel={ariaLabel ?? (isCustom ? undefined : label)}
confirmAriaLabel={t("chipConfirm")}
typeToAddPlaceholder={t("chipTypeToAdd")}
closeAriaLabel={t("chipClose")}
/>
);
},
);
ChipContainer.displayName = "Chip";
export default ChipContainer;