Skip to content

Commit

Permalink
update controlled input to reflect changes in controlled value (#1292)
Browse files Browse the repository at this point in the history
* update to checkbox field and stepper field so that controlled components update visual input when controlled values are updated

* update dependency arrays

* Create violet-hornets-change.md

* removed reset to controlled value when stepperfield input changes

Co-authored-by: Jacob Logan <lognjc@amazon.com>
  • Loading branch information
jacoblogan and Jacob Logan authored Feb 14, 2022
1 parent b4bc4d5 commit aa051a0
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-hornets-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@aws-amplify/ui-react": patch
---

update StepperField and CheckboxField to update the visual display when a controlled value is changed
13 changes: 9 additions & 4 deletions packages/react/src/primitives/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@ const CheckboxPrimitive: Primitive<CheckboxProps, 'input'> = (
// controlled way should always override uncontrolled way
const initialChecked = checked !== undefined ? checked : defaultChecked;

const { dataChecked, dataFocus, onBlur, onChange, onFocus } = useCheckbox(
initialChecked,
onChangeProp
);
const { dataChecked, dataFocus, onBlur, onChange, onFocus, setDataChecked } =
useCheckbox(initialChecked, onChangeProp);

React.useEffect(() => {
const isControlled = checked !== undefined;
if (isControlled && checked !== dataChecked) {
setDataChecked(checked);
}
}, [checked, dataChecked, setDataChecked]);

const buttonTestId = useTestId(testId, ComponentClassNames.CheckboxButton);
const iconTestId = useTestId(testId, ComponentClassNames.CheckboxIcon);
Expand Down
32 changes: 32 additions & 0 deletions packages/react/src/primitives/Checkbox/__tests__/Checkbox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ describe('Checkbox test suite', () => {
});

describe('Button test suite', () => {
let updateCheckedFunction;
const ControlledCheckbox = () => {
const [checked, setChecked] = React.useState(false);
updateCheckedFunction = setChecked;
return (
<Checkbox
{...basicProps}
onChange={(event) => {
setChecked(event.target.checked);
}}
checked={checked}
/>
);
};

it('should render basic props correctly', async () => {
render(getCheckbox({ ...basicProps }));

Expand All @@ -127,6 +142,23 @@ describe('Checkbox test suite', () => {
expect(button).toHaveAttribute('data-focus', 'false');
expect(button).toHaveClass(ComponentClassNames.CheckboxButton);
});

it('should update the checked button with a change to the controlled value', async () => {
render(<ControlledCheckbox />);

let button = await screen.findByTestId(
`${basicProps.testId}-${ComponentClassNames.CheckboxButton}`
);
expect(button).toHaveAttribute('data-checked', 'false');
expect(button).not.toHaveAttribute('data-disabled');
expect(button).toHaveAttribute('data-focus', 'false');
expect(button).toHaveClass(ComponentClassNames.CheckboxButton);
updateCheckedFunction(true);
button = await screen.findByTestId(
`${basicProps.testId}-${ComponentClassNames.CheckboxButton}`
);
expect(button).toHaveAttribute('data-checked', 'true');
});
});

describe('Icon test suite', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/primitives/Checkbox/useCheckbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ export const useCheckbox = (
setDataFocus(false);
};

return { dataChecked, dataFocus, onBlur, onChange, onFocus };
return { dataChecked, dataFocus, onBlur, onChange, onFocus, setDataChecked };
};
8 changes: 8 additions & 0 deletions packages/react/src/primitives/StepperField/StepperField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,18 @@ const StepperFieldPrimitive: Primitive<StepperFieldProps, 'input'> = (
handleOnBlur,
handleOnChange,
handleOnWheel,
setInputValue,
shouldDisableDecreaseButton,
shouldDisableIncreaseButton,
} = useStepper(props);

React.useEffect(() => {
const isControlled = controlledValue !== undefined;
if (isControlled) {
setInputValue(controlledValue);
}
}, [controlledValue, setInputValue]);

return (
<Flex
className={classNames(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@ describe('StepperField: ', () => {

describe('Input field', () => {
const label = 'stepper';
let updateValueFunction;

const ControlledStepper = () => {
const [value, setValue] = React.useState(0);
updateValueFunction = setValue;
return (
<StepperField
label={label}
Expand Down Expand Up @@ -202,6 +204,15 @@ describe('StepperField: ', () => {
expect(onBlur).toHaveBeenCalled();
expect(onWheel).toHaveBeenCalled();
});

it('should update the value correctly(controlled)', async () => {
render(<ControlledStepper />);
let stepperInput = await screen.findByLabelText(label);
expect(stepperInput).toHaveValue(0);
updateValueFunction(8);
stepperInput = await screen.findByLabelText(label);
expect(stepperInput).toHaveValue(8);
});
});

describe('Increase/Decrease button', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/primitives/StepperField/useStepper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export const useStepper = ({
handleOnBlur,
handleOnChange,
handleOnWheel,
setInputValue,
shouldDisableDecreaseButton,
shouldDisableIncreaseButton,
};
Expand Down

0 comments on commit aa051a0

Please sign in to comment.