Skip to content

Commit e0d4f96

Browse files
issue-2216: setting null to value should reset NumberField to blank (#3709)
* issue-2216: setting null to value should reset NumberField to blank
1 parent d56c9ea commit e0d4f96

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

packages/@react-spectrum/numberfield/stories/NumberField.stories.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212

1313
import {action} from '@storybook/addon-actions';
14+
import {Button} from '@react-spectrum/button';
1415
import {chain} from '@react-aria/utils';
1516
import {Content} from '@react-spectrum/view';
1617
import {ContextualHelp} from '@react-spectrum/contextualhelp';
@@ -247,6 +248,10 @@ storiesOf('NumberField', module)
247248
onCopy: action('onCopy'), onCut: action('onCut'), onPaste: action('onPaste'), onCompositionStart: action('onCompositionStart'), onCompositionEnd: action('onCompositionEnd'),
248249
onCompositionUpdate: action('onCompositionUpdate'), onSelect: action('onSelect'), onBeforeInput: action('onBeforeInput'), onInput: action('onInput')
249250
})
251+
)
252+
.add(
253+
'reset controlled state to blank with null',
254+
() => <NumberFieldControlledStateReset />
250255
);
251256

252257
function render(props: any = {}) {
@@ -310,6 +315,22 @@ function NumberFieldWithCurrencySelect(props) {
310315
);
311316
}
312317

318+
function NumberFieldControlledStateReset() {
319+
const [controlledValue, setControlledValue] = useState(12);
320+
return (
321+
<>
322+
<NumberField
323+
value={controlledValue}
324+
onChange={(value) => setControlledValue(value)} />
325+
<Button
326+
variant={'primary'}
327+
onPress={() => setControlledValue(null)}>
328+
Reset
329+
</Button>
330+
</>
331+
);
332+
}
333+
313334
class ErrorBoundary extends React.Component<{}, {hasError: boolean}> {
314335
constructor(props) {
315336
super(props);

packages/@react-spectrum/numberfield/test/NumberField.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212

1313
import {act, fireEvent, render, triggerPress, typeText, within} from '@react-spectrum/test-utils';
14+
import {Button} from '@react-spectrum/button';
1415
import {chain} from '@react-aria/utils';
1516
import messages from '../../../@react-aria/numberfield/intl/*';
1617
import {NumberField} from '../';
@@ -2156,4 +2157,32 @@ describe('NumberField', function () {
21562157
});
21572158
});
21582159
});
2160+
2161+
it('can be reset to blank using null', () => {
2162+
function NumberFieldControlled(props) {
2163+
let {onChange} = props;
2164+
let [value, setValue] = useState(10);
2165+
return (
2166+
<Provider theme={theme} scale="medium" locale="en-US">
2167+
<NumberField {...props} label="reset to blank using null" value={value} onChange={value => setValue(value)} />
2168+
<Button
2169+
variant={'primary'}
2170+
onPress={() => chain(setValue(null), onChange())}>
2171+
Reset
2172+
</Button>
2173+
</Provider>
2174+
);
2175+
}
2176+
let resetSpy = jest.fn();
2177+
let {container, getByText} = render(<NumberFieldControlled onChange={resetSpy} />);
2178+
container = within(container).queryByRole('group');
2179+
let textField = container.firstChild;
2180+
let resetButton = getByText('Reset');
2181+
2182+
textField = textField.firstChild;
2183+
expect(textField).toHaveAttribute('value', '10');
2184+
triggerPress(resetButton);
2185+
expect(resetSpy).toHaveBeenCalledTimes(1);
2186+
expect(textField).toHaveAttribute('value', '');
2187+
});
21592188
});

packages/@react-stately/numberfield/src/useNumberFieldState.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export function useNumberFieldState(
9494
let numberingSystem = useMemo(() => numberParser.getNumberingSystem(inputValue), [numberParser, inputValue]);
9595
let formatter = useMemo(() => new NumberFormatter(locale, {...formatOptions, numberingSystem}), [locale, formatOptions, numberingSystem]);
9696
let intlOptions = useMemo(() => formatter.resolvedOptions(), [formatter]);
97-
let format = useCallback((value: number) => isNaN(value) ? '' : formatter.format(value), [formatter]);
97+
let format = useCallback((value: number) => (isNaN(value) || value === null) ? '' : formatter.format(value), [formatter]);
9898

9999
let clampStep = !isNaN(step) ? step : 1;
100100
if (intlOptions.style === 'percent' && isNaN(step)) {

0 commit comments

Comments
 (0)