Skip to content

Commit c77fded

Browse files
Copilotericblade
andauthored
Fix getDerivedStateFromProps to handle simultaneous allowNegative and format prop changes (#46)
* Initial plan * Fix getDerivedStateFromProps to handle simultaneous allowNegative and format prop changes Co-authored-by: ericblade <1451847+ericblade@users.noreply.github.com> * Add clarifying comment for valueToFormat initialization Co-authored-by: ericblade <1451847+ericblade@users.noreply.github.com> * Fix whitespace for consistency with codebase style Co-authored-by: ericblade <1451847+ericblade@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ericblade <1451847+ericblade@users.noreply.github.com>
1 parent 701ebcf commit c77fded

2 files changed

Lines changed: 49 additions & 18 deletions

File tree

src/index.tsx

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -189,13 +189,17 @@ class CurrencyInput extends React.Component<CurrencyInputProps, CurrencyInputSta
189189
// Check if the VALUE prop itself changed (parent is controlling the input)
190190
const valueChanged = nextProps.value !== previousProps.value;
191191

192+
// Check if allowNegative changed (affects whether negative values are allowed)
193+
const allowNegativeChanged = nextProps.allowNegative !== previousProps.allowNegative;
194+
192195
// Check if separators or display formatting changed (these require reformatting the current value)
193196
const formatChanged =
194197
nextProps.decimalSeparator !== previousProps.decimalSeparator ||
195198
nextProps.thousandSeparator !== previousProps.thousandSeparator ||
196199
nextProps.precision !== previousProps.precision ||
197200
nextProps.prefix !== previousProps.prefix ||
198-
nextProps.suffix !== previousProps.suffix;
201+
nextProps.suffix !== previousProps.suffix ||
202+
allowNegativeChanged;
199203

200204
if (valueChanged) {
201205
// Parent changed the value prop - use the new value
@@ -204,33 +208,28 @@ class CurrencyInput extends React.Component<CurrencyInputProps, CurrencyInputSta
204208
}
205209

206210
if (formatChanged) {
207-
// Display formatting changed - reformat the current value with new formatting
208-
const propsWithCurrentValue = { ...nextProps, value: prevState.value };
209-
const newState = CurrencyInput.prepareProps(propsWithCurrentValue);
210-
return { ...newState, previousProps: nextProps };
211-
}
211+
// Display formatting or allowNegative changed - reformat the current value
212+
// First, determine the value to use. Start with the current state value,
213+
// which may be adjusted below if allowNegative was disabled and value is negative.
214+
let valueToFormat = prevState.value;
212215

213-
// Check if allowNegative changed
214-
const allowNegativeChanged = nextProps.allowNegative !== previousProps.allowNegative;
215-
216-
if (allowNegativeChanged) {
217-
if (!nextProps.allowNegative) {
218-
// allowNegative was disabled
219-
// If current value is negative, make it positive
216+
if (allowNegativeChanged && !nextProps.allowNegative) {
217+
// allowNegative was disabled - if current value is negative, make it positive
220218
const parsedValue = typeof prevState.value === 'number'
221219
? prevState.value
222220
: prevState.value === null
223221
? 0
224222
: CurrencyInput.stringValueToFloat(String(prevState.value), nextProps.thousandSeparator, nextProps.decimalSeparator);
225223

226224
if (parsedValue < 0) {
227-
const propsWithPositiveValue = { ...nextProps, value: Math.abs(parsedValue) };
228-
const newState = CurrencyInput.prepareProps(propsWithPositiveValue);
229-
return { ...newState, previousProps: nextProps };
225+
valueToFormat = Math.abs(parsedValue);
230226
}
231227
}
232-
// allowNegative toggled on or no sign change needed: still advance previousProps
233-
return { ...prevState, previousProps: nextProps };
228+
229+
// Reformat with new formatting and potentially adjusted value
230+
const propsWithCurrentValue = { ...nextProps, value: valueToFormat };
231+
const newState = CurrencyInput.prepareProps(propsWithCurrentValue);
232+
return { ...newState, previousProps: nextProps };
234233
}
235234

236235
// Other props changed but value and display formatting didn't

tests/base.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,38 @@ test.describe('component parameters', () => {
244244
value = await currencyInput.inputValue();
245245
expect(value).not.toContain('-');
246246
});
247+
248+
test('removes negative sign when allowNegative is disabled and format changes simultaneously', async ({ page }) => {
249+
// First enable allowNegative
250+
const allowNegativeCheckbox = page.locator('[name=allowNegative]');
251+
const prefixInput = page.locator('[name=prefix]');
252+
const applyBtn = page.locator('[name=apply]');
253+
const currencyInput = page.locator('#currency-input');
254+
255+
await allowNegativeCheckbox.check();
256+
await applyBtn.click();
257+
await expect(currencyInput).toHaveValue('$0.00 USD');
258+
await currencyInput.focus();
259+
await currencyInput.selectText();
260+
261+
// Input a negative number
262+
await currencyInput.pressSequentially('50');
263+
await currencyInput.press('Minus');
264+
265+
let value = await currencyInput.inputValue();
266+
expect(value).toContain('-');
267+
268+
// Now disable allowNegative AND change prefix at the same time
269+
await allowNegativeCheckbox.uncheck();
270+
await prefixInput.fill('€');
271+
await applyBtn.click();
272+
273+
// Value should now be positive AND have the new prefix
274+
value = await currencyInput.inputValue();
275+
expect(value).not.toContain('-');
276+
expect(value).toContain('€');
277+
expect(value).toContain('50');
278+
});
247279
});
248280

249281
test.describe('allowEmpty', () => {

0 commit comments

Comments
 (0)