Show the whole Rule on one review card, with quiet flags for missing cards and Continue once each question has one.

This commit is contained in:
adilallo committed 2026-11-06 08:36:34 -07:00
1 parent cc878e3c19
commit 6e2e1915ae
30 files changed
+571 -218

No files matched your search

+4
View File
@@ -6,6 +6,10 @@ export interface Category {
chipOptions: ChipOption[];
/** When `false`, hide the row’s + affordance. Default: show when the Rule allows adds. */
addButton?: boolean;
/** Label on the add control. Empty string keeps the icon-only circle. */
addButtonText?: string;
/** Figma Has Flag: short line after the add chip in the same row. */
flag?: string;
onChipClick?: (categoryName: string, chipId: string) => void;
onAddClick?: (categoryName: string) => void;
onCustomChipConfirm?: (
+2 -1
View File
@@ -472,7 +472,8 @@ export function RuleView({
addButton={
!hideCategoryAddButton && category.addButton !== false
}
addButtonText="" // Empty text for icon-only circular button
addButtonText={category.addButtonText ?? ""}
flag={category.flag}
className="w-full"
/>
))}
@@ -21,6 +21,7 @@ const ChipContainer = memo<ChipProps>(
onRemove,
onCheck,
onClose,
hasWarning = false,
ariaLabel,
}) => {
const t = useTranslation("controlsChrome");
@@ -89,11 +90,19 @@ const ChipContainer = memo<ChipProps>(
onRemove={onRemove}
onCheck={handleCheck}
onClose={handleClose}
hasWarning={hasWarning}
inputValue={isCustom ? inputValue : undefined}
onInputChange={isCustom ? setInputValue : undefined}
onInputKeyDown={isCustom ? handleKeyDown : undefined}
inputRef={isCustom ? inputRef : undefined}
ariaLabel={ariaLabel ?? (isCustom ? undefined : label)}
ariaLabel={
ariaLabel ??
(isCustom
? undefined
: hasWarning
? t("chipMissingWords").replace("{label}", label)
: label)
}
confirmAriaLabel={t("chipConfirm")}
typeToAddPlaceholder={t("chipTypeToAdd")}
closeAriaLabel={t("chipClose")}
@@ -48,6 +48,11 @@ export interface ChipProps {
* Optional callback when custom chip is closed/removed.
*/
onClose?: (event: React.MouseEvent<HTMLButtonElement>) => void;
/**
* Figma Has Warning: show a warning icon in place of the selected check.
* Used on final review when a card or value is missing its words.
*/
hasWarning?: boolean;
ariaLabel?: string;
}
@@ -62,6 +67,7 @@ export interface ChipViewProps {
onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void;
onCheck?: (value: string, event: React.MouseEvent<HTMLButtonElement>) => void;
onClose?: (event: React.MouseEvent<HTMLButtonElement>) => void;
hasWarning?: boolean;
inputValue?: string;
onInputChange?: (value: string) => void;
onInputKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
+9 -1
View File
@@ -1,6 +1,7 @@
"use client";
import { memo, type CSSProperties } from "react";
import Icon from "../../asset/icon/Icon";
import type { ChipViewProps } from "./Chip.types";
function chipSurfaceStyle(
@@ -87,6 +88,7 @@ function ChipView({
onRemove,
onCheck,
onClose,
hasWarning = false,
inputValue,
onInputChange,
onInputKeyDown,
@@ -280,7 +282,13 @@ function ChipView({
onClick={handleClick}
{...sharedA11y}
>
{isSelected ? (
{hasWarning ? (
<Icon
name="warning"
size={isSmall ? 12 : 16}
className="shrink-0 text-current"
/>
) : isSelected ? (
<svg
aria-hidden
viewBox="0 0 12 12"
@@ -20,6 +20,7 @@ const MultiSelectContainer = memo<MultiSelectProps>(
onAddClick,
addButton: addButtonProp = true,
addButtonText,
flag,
formHeader = true,
helperText,
errorMessage,
@@ -45,11 +46,13 @@ const MultiSelectContainer = memo<MultiSelectProps>(
onAddClick={onAddClick}
addButton={addButtonProp}
addButtonText={addButtonText}
flag={flag}
addButtonAriaLabel={
addButtonText || t("multiSelectAddFallback")
}
chipSelectAriaLabel={t("chipSelect")}
chipDeselectAriaLabel={t("chipDeselect")}
chipMissingWordsAriaLabel={t("chipMissingWords")}
formHeader={formHeader}
helperText={helperText}
errorMessage={errorMessage}
@@ -7,6 +7,8 @@ export interface ChipOption {
id: string;
label: string;
state?: ChipStateValue;
/** Figma Has Warning on Control / Chip. */
hasWarning?: boolean;
}
export type MultiSelectSizeValue = "s" | "m";
@@ -49,6 +51,11 @@ export interface MultiSelectProps {
* Text for the add button
*/
addButtonText?: string;
/**
* Figma Has Flag: short line after the add chip in the same row, with no
* fill and no extra height.
*/
flag?: string;
/**
* Whether to show form header (label and help icon) above multi-select (Figma prop).
* @default true
@@ -93,7 +100,9 @@ export interface MultiSelectViewProps {
onAddClick?: () => void;
addButton: boolean;
addButtonText?: string;
flag?: string;
addButtonAriaLabel: string;
chipMissingWordsAriaLabel: string;
chipSelectAriaLabel: string;
chipDeselectAriaLabel: string;
formHeader: boolean;
@@ -2,6 +2,7 @@
import { memo } from "react";
import Chip from "../Chip";
import Icon from "../../asset/icon/Icon";
import InputLabel from "../../type/InputLabel";
import type { MultiSelectViewProps } from "./MultiSelect.types";
@@ -15,9 +16,11 @@ function MultiSelectView({
onAddClick,
addButton,
addButtonText,
flag,
addButtonAriaLabel,
chipSelectAriaLabel,
chipDeselectAriaLabel,
chipMissingWordsAriaLabel,
formHeader = true,
helperText: helperTextProp,
errorMessage,
@@ -94,13 +97,19 @@ function MultiSelectView({
palette={palette}
size={chipSize}
disabled={chipDisabled}
hasWarning={option.hasWarning}
ariaLabel={
isCustom || !option.label
? undefined
: (isSelected
? chipDeselectAriaLabel
: chipSelectAriaLabel
).replace("{label}", option.label)
: option.hasWarning
? chipMissingWordsAriaLabel.replace(
"{label}",
option.label,
)
: (isSelected
? chipDeselectAriaLabel
: chipSelectAriaLabel
).replace("{label}", option.label)
}
onClick={() => {
if (!isCustom && !chipDisabled && onChipClick) {
@@ -180,6 +189,22 @@ function MultiSelectView({
)}
</button>
)}
{flag ? (
<span
className={`inline-flex items-center gap-[var(--space-100)] text-x-small-paragraph ${
isInverse
? "text-[color:var(--color-content-invert-primary)]"
: "text-[color:var(--color-content-default-primary)]"
}`}
>
<Icon
name="warning"
size={12}
className="shrink-0 text-current"
/>
{flag}
</span>
) : null}
</div>
{errorMessage ? (
<p