Resolve errors and pass tests
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { memo, useCallback, useId, useState, useEffect } from "react";
|
import { memo, useCallback, useId, useState } from "react";
|
||||||
import { CheckboxGroupView } from "./CheckboxGroup.view";
|
import { CheckboxGroupView } from "./CheckboxGroup.view";
|
||||||
import type { CheckboxGroupProps } from "./CheckboxGroup.types";
|
import type { CheckboxGroupProps } from "./CheckboxGroup.types";
|
||||||
|
|
||||||
@@ -18,15 +18,11 @@ const CheckboxGroupContainer = ({
|
|||||||
const generatedId = useId();
|
const generatedId = useId();
|
||||||
const groupId = name || `checkbox-group-${generatedId}`;
|
const groupId = name || `checkbox-group-${generatedId}`;
|
||||||
|
|
||||||
// Internal state to track checked values
|
// Internal state to track checked values (only used if value prop is not provided)
|
||||||
const [checkedValues, setCheckedValues] = useState<string[]>(value || []);
|
const [internalCheckedValues, setInternalCheckedValues] = useState<string[]>([]);
|
||||||
|
|
||||||
// Sync internal state with external value prop
|
// Use controlled value if provided, otherwise use internal state
|
||||||
useEffect(() => {
|
const checkedValues = value !== undefined ? value : internalCheckedValues;
|
||||||
if (value !== undefined) {
|
|
||||||
setCheckedValues(value);
|
|
||||||
}
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
const handleOptionChange = useCallback(
|
const handleOptionChange = useCallback(
|
||||||
(optionValue: string, checked: boolean) => {
|
(optionValue: string, checked: boolean) => {
|
||||||
@@ -36,13 +32,16 @@ const CheckboxGroupContainer = ({
|
|||||||
? [...checkedValues, optionValue]
|
? [...checkedValues, optionValue]
|
||||||
: checkedValues.filter((v) => v !== optionValue);
|
: checkedValues.filter((v) => v !== optionValue);
|
||||||
|
|
||||||
setCheckedValues(newCheckedValues);
|
// Only update internal state if uncontrolled
|
||||||
|
if (value === undefined) {
|
||||||
|
setInternalCheckedValues(newCheckedValues);
|
||||||
|
}
|
||||||
|
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange({ value: newCheckedValues });
|
onChange({ value: newCheckedValues });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[disabled, checkedValues, onChange],
|
[disabled, checkedValues, onChange, value],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const RadioButtonContainer = ({
|
|||||||
value,
|
value,
|
||||||
ariaLabel,
|
ariaLabel,
|
||||||
className = "",
|
className = "",
|
||||||
...props
|
|
||||||
}: RadioButtonProps) => {
|
}: RadioButtonProps) => {
|
||||||
const isInverse = mode === "inverse";
|
const isInverse = mode === "inverse";
|
||||||
const isStandard = mode === "standard";
|
const isStandard = mode === "standard";
|
||||||
@@ -82,23 +81,6 @@ const RadioButtonContainer = ({
|
|||||||
|
|
||||||
const combinedBoxStyles = getBoxStyles();
|
const combinedBoxStyles = getBoxStyles();
|
||||||
|
|
||||||
// Dot color per Figma
|
|
||||||
// Selected state: light cream/yellow (#fefcc9)
|
|
||||||
// Selected hover state: darker yellow/brown (#333000 or rgba(51, 48, 0, 1))
|
|
||||||
const getDotColor = (): string => {
|
|
||||||
if (!checked) return "transparent";
|
|
||||||
|
|
||||||
if (isStandard) {
|
|
||||||
// Use CSS to handle hover state - default is light cream, hover is darker
|
|
||||||
return "var(--color-content-default-brand-primary, #fefcc9)";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inverse mode: black dot
|
|
||||||
return "var(--color-content-default-primary, #000000)";
|
|
||||||
};
|
|
||||||
|
|
||||||
const dotColor = getDotColor();
|
|
||||||
|
|
||||||
// Label color
|
// Label color
|
||||||
const labelColor = isInverse
|
const labelColor = isInverse
|
||||||
? "var(--color-content-inverse-primary)"
|
? "var(--color-content-inverse-primary)"
|
||||||
@@ -139,7 +121,6 @@ const RadioButtonContainer = ({
|
|||||||
ariaLabel={ariaLabel}
|
ariaLabel={ariaLabel}
|
||||||
className={className}
|
className={className}
|
||||||
combinedBoxStyles={combinedBoxStyles}
|
combinedBoxStyles={combinedBoxStyles}
|
||||||
dotColor={dotColor}
|
|
||||||
labelColor={labelColor}
|
labelColor={labelColor}
|
||||||
onToggle={handleToggle}
|
onToggle={handleToggle}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export interface RadioButtonViewProps {
|
|||||||
ariaLabel?: string;
|
ariaLabel?: string;
|
||||||
className: string;
|
className: string;
|
||||||
combinedBoxStyles: string;
|
combinedBoxStyles: string;
|
||||||
dotColor: string;
|
|
||||||
labelColor: string;
|
labelColor: string;
|
||||||
onToggle: (_e: React.MouseEvent | React.KeyboardEvent) => void;
|
onToggle: (_e: React.MouseEvent | React.KeyboardEvent) => void;
|
||||||
onKeyDown: (_e: React.KeyboardEvent<HTMLSpanElement>) => void;
|
onKeyDown: (_e: React.KeyboardEvent<HTMLSpanElement>) => void;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ export function RadioButtonView({
|
|||||||
ariaLabel,
|
ariaLabel,
|
||||||
className,
|
className,
|
||||||
combinedBoxStyles,
|
combinedBoxStyles,
|
||||||
dotColor,
|
|
||||||
labelColor,
|
labelColor,
|
||||||
onToggle,
|
onToggle,
|
||||||
onKeyDown,
|
onKeyDown,
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ export function SelectInputView({
|
|||||||
menuRef,
|
menuRef,
|
||||||
ariaLabelledby,
|
ariaLabelledby,
|
||||||
ariaInvalid,
|
ariaInvalid,
|
||||||
...props
|
|
||||||
}: SelectInputViewProps) {
|
}: SelectInputViewProps) {
|
||||||
// Styles based on Figma design
|
// Styles based on Figma design
|
||||||
const containerClasses = "flex flex-col gap-[8px]";
|
const containerClasses = "flex flex-col gap-[8px]";
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ Step2.args = {
|
|||||||
description: "You can also combine or add new approaches to the list",
|
description: "You can also combine or add new approaches to the list",
|
||||||
children: (
|
children: (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Input label="Label" placeholder="Enter text" value="" />
|
<TextInput label="Label" placeholder="Enter text" value="" />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
|
|||||||
@@ -188,9 +188,10 @@ describe("NumberCard Component", () => {
|
|||||||
it("applies Small size variant correctly", () => {
|
it("applies Small size variant correctly", () => {
|
||||||
render(<NumberCard {...defaultProps} size="Small" />);
|
render(<NumberCard {...defaultProps} size="Small" />);
|
||||||
|
|
||||||
|
// For Small size, text is directly in card div (no wrapper), so use closest("div")
|
||||||
const card = screen
|
const card = screen
|
||||||
.getByText("Test Card Text")
|
.getByText("Test Card Text")
|
||||||
.closest("div").parentElement;
|
.closest("div");
|
||||||
expect(card).toHaveClass(
|
expect(card).toHaveClass(
|
||||||
"flex",
|
"flex",
|
||||||
"flex-col",
|
"flex-col",
|
||||||
@@ -198,6 +199,7 @@ describe("NumberCard Component", () => {
|
|||||||
"justify-center",
|
"justify-center",
|
||||||
"gap-4",
|
"gap-4",
|
||||||
"p-5",
|
"p-5",
|
||||||
|
"relative",
|
||||||
);
|
);
|
||||||
|
|
||||||
const textElement = screen.getByText("Test Card Text");
|
const textElement = screen.getByText("Test Card Text");
|
||||||
|
|||||||
Reference in New Issue
Block a user