diff --git a/packages/@react-aria/numberfield/intl/ar-AE.json b/packages/@react-aria/numberfield/intl/ar-AE.json index 84998794627..f5a38677072 100644 --- a/packages/@react-aria/numberfield/intl/ar-AE.json +++ b/packages/@react-aria/numberfield/intl/ar-AE.json @@ -1,5 +1,7 @@ { "decrease": "خفض {fieldLabel}", "increase": "زيادة {fieldLabel}", - "numberField": "حقل رقمي" + "numberField": "حقل رقمي", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/bg-BG.json b/packages/@react-aria/numberfield/intl/bg-BG.json index 916c174865e..f45ecac75c6 100644 --- a/packages/@react-aria/numberfield/intl/bg-BG.json +++ b/packages/@react-aria/numberfield/intl/bg-BG.json @@ -1,5 +1,7 @@ { "decrease": "Намаляване {fieldLabel}", "increase": "Усилване {fieldLabel}", - "numberField": "Номер на полето" + "numberField": "Номер на полето", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/cs-CZ.json b/packages/@react-aria/numberfield/intl/cs-CZ.json index 63c73d72f57..a9aceeeb5c3 100644 --- a/packages/@react-aria/numberfield/intl/cs-CZ.json +++ b/packages/@react-aria/numberfield/intl/cs-CZ.json @@ -1,5 +1,7 @@ { "decrease": "Snížit {fieldLabel}", "increase": "Zvýšit {fieldLabel}", - "numberField": "Číselné pole" + "numberField": "Číselné pole", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/da-DK.json b/packages/@react-aria/numberfield/intl/da-DK.json index 505331be802..08c7793d4ff 100644 --- a/packages/@react-aria/numberfield/intl/da-DK.json +++ b/packages/@react-aria/numberfield/intl/da-DK.json @@ -1,5 +1,7 @@ { "decrease": "Reducer {fieldLabel}", "increase": "Øg {fieldLabel}", - "numberField": "Talfelt" + "numberField": "Talfelt", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/de-DE.json b/packages/@react-aria/numberfield/intl/de-DE.json index e4ff090ffbf..4ce8c555310 100644 --- a/packages/@react-aria/numberfield/intl/de-DE.json +++ b/packages/@react-aria/numberfield/intl/de-DE.json @@ -1,5 +1,7 @@ { "decrease": "{fieldLabel} verringern", "increase": "{fieldLabel} erhöhen", - "numberField": "Nummernfeld" + "numberField": "Nummernfeld", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/el-GR.json b/packages/@react-aria/numberfield/intl/el-GR.json index b60c669d851..103bc39a79d 100644 --- a/packages/@react-aria/numberfield/intl/el-GR.json +++ b/packages/@react-aria/numberfield/intl/el-GR.json @@ -1,5 +1,7 @@ { "decrease": "Μείωση {fieldLabel}", "increase": "Αύξηση {fieldLabel}", - "numberField": "Πεδίο αριθμού" + "numberField": "Πεδίο αριθμού", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/en-US.json b/packages/@react-aria/numberfield/intl/en-US.json index ff6eb41b105..ab2929165e6 100644 --- a/packages/@react-aria/numberfield/intl/en-US.json +++ b/packages/@react-aria/numberfield/intl/en-US.json @@ -1,5 +1,7 @@ { "decrease": "Decrease {fieldLabel}", "increase": "Increase {fieldLabel}", - "numberField": "Number field" + "numberField": "Number field", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/es-ES.json b/packages/@react-aria/numberfield/intl/es-ES.json index 8794c3f99ae..42c0b951ccd 100644 --- a/packages/@react-aria/numberfield/intl/es-ES.json +++ b/packages/@react-aria/numberfield/intl/es-ES.json @@ -1,5 +1,7 @@ { "decrease": "Reducir {fieldLabel}", "increase": "Aumentar {fieldLabel}", - "numberField": "Campo de número" + "numberField": "Campo de número", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/et-EE.json b/packages/@react-aria/numberfield/intl/et-EE.json index 2b077a46f04..837dc4be625 100644 --- a/packages/@react-aria/numberfield/intl/et-EE.json +++ b/packages/@react-aria/numberfield/intl/et-EE.json @@ -1,5 +1,7 @@ { "decrease": "Vähenda {fieldLabel}", "increase": "Suurenda {fieldLabel}", - "numberField": "Numbri väli" + "numberField": "Numbri väli", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/fi-FI.json b/packages/@react-aria/numberfield/intl/fi-FI.json index fac2d7f0fcc..ac981f9f5c7 100644 --- a/packages/@react-aria/numberfield/intl/fi-FI.json +++ b/packages/@react-aria/numberfield/intl/fi-FI.json @@ -1,5 +1,7 @@ { "decrease": "Vähennä {fieldLabel}", "increase": "Lisää {fieldLabel}", - "numberField": "Numerokenttä" + "numberField": "Numerokenttä", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/fr-FR.json b/packages/@react-aria/numberfield/intl/fr-FR.json index 6f0cf0f9773..e2488cdcd38 100644 --- a/packages/@react-aria/numberfield/intl/fr-FR.json +++ b/packages/@react-aria/numberfield/intl/fr-FR.json @@ -1,5 +1,7 @@ { "decrease": "Diminuer {fieldLabel}", "increase": "Augmenter {fieldLabel}", - "numberField": "Champ de nombre" + "numberField": "Champ de nombre", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/he-IL.json b/packages/@react-aria/numberfield/intl/he-IL.json index a6c5a90871b..af677c58221 100644 --- a/packages/@react-aria/numberfield/intl/he-IL.json +++ b/packages/@react-aria/numberfield/intl/he-IL.json @@ -1,5 +1,7 @@ { "decrease": "הקטן {fieldLabel}", "increase": "הגדל {fieldLabel}", - "numberField": "שדה מספר" + "numberField": "שדה מספר", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/hr-HR.json b/packages/@react-aria/numberfield/intl/hr-HR.json index 12a4eba7361..b11007bd444 100644 --- a/packages/@react-aria/numberfield/intl/hr-HR.json +++ b/packages/@react-aria/numberfield/intl/hr-HR.json @@ -1,5 +1,7 @@ { "decrease": "Smanji {fieldLabel}", "increase": "Povećaj {fieldLabel}", - "numberField": "Polje broja" + "numberField": "Polje broja", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/hu-HU.json b/packages/@react-aria/numberfield/intl/hu-HU.json index 67825897391..4764943668c 100644 --- a/packages/@react-aria/numberfield/intl/hu-HU.json +++ b/packages/@react-aria/numberfield/intl/hu-HU.json @@ -1,5 +1,7 @@ { "decrease": "{fieldLabel} csökkentése", "increase": "{fieldLabel} növelése", - "numberField": "Számmező" + "numberField": "Számmező", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/it-IT.json b/packages/@react-aria/numberfield/intl/it-IT.json index 481cd7ac2f5..fd9702af3ac 100644 --- a/packages/@react-aria/numberfield/intl/it-IT.json +++ b/packages/@react-aria/numberfield/intl/it-IT.json @@ -1,5 +1,7 @@ { "decrease": "Riduci {fieldLabel}", "increase": "Aumenta {fieldLabel}", - "numberField": "Campo numero" + "numberField": "Campo numero", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/ja-JP.json b/packages/@react-aria/numberfield/intl/ja-JP.json index 2e078e5aee2..ae3f76407d4 100644 --- a/packages/@react-aria/numberfield/intl/ja-JP.json +++ b/packages/@react-aria/numberfield/intl/ja-JP.json @@ -1,5 +1,7 @@ { "decrease": "{fieldLabel}を縮小", "increase": "{fieldLabel}を拡大", - "numberField": "数値フィールド" + "numberField": "数値フィールド", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/ko-KR.json b/packages/@react-aria/numberfield/intl/ko-KR.json index cc068bc78e4..2b8549d4160 100644 --- a/packages/@react-aria/numberfield/intl/ko-KR.json +++ b/packages/@react-aria/numberfield/intl/ko-KR.json @@ -1,5 +1,7 @@ { "decrease": "{fieldLabel} 감소", "increase": "{fieldLabel} 증가", - "numberField": "번호 필드" + "numberField": "번호 필드", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/lt-LT.json b/packages/@react-aria/numberfield/intl/lt-LT.json index 8e53e5cdea2..b5abaefafbf 100644 --- a/packages/@react-aria/numberfield/intl/lt-LT.json +++ b/packages/@react-aria/numberfield/intl/lt-LT.json @@ -1,5 +1,7 @@ { "decrease": "Sumažinti {fieldLabel}", "increase": "Padidinti {fieldLabel}", - "numberField": "Numerio laukas" + "numberField": "Numerio laukas", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/lv-LV.json b/packages/@react-aria/numberfield/intl/lv-LV.json index 4b9c2b8e5a3..fa1fd7c4e20 100644 --- a/packages/@react-aria/numberfield/intl/lv-LV.json +++ b/packages/@react-aria/numberfield/intl/lv-LV.json @@ -1,5 +1,7 @@ { "decrease": "Samazināšana {fieldLabel}", "increase": "Palielināšana {fieldLabel}", - "numberField": "Skaitļu lauks" + "numberField": "Skaitļu lauks", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/nb-NO.json b/packages/@react-aria/numberfield/intl/nb-NO.json index 276c7b649bc..3c2d464221c 100644 --- a/packages/@react-aria/numberfield/intl/nb-NO.json +++ b/packages/@react-aria/numberfield/intl/nb-NO.json @@ -1,5 +1,7 @@ { "decrease": "Reduser {fieldLabel}", "increase": "Øk {fieldLabel}", - "numberField": "Tallfelt" + "numberField": "Tallfelt", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/nl-NL.json b/packages/@react-aria/numberfield/intl/nl-NL.json index 5c57c2ff533..f21a09778df 100644 --- a/packages/@react-aria/numberfield/intl/nl-NL.json +++ b/packages/@react-aria/numberfield/intl/nl-NL.json @@ -1,5 +1,7 @@ { "decrease": "{fieldLabel} verlagen", "increase": "{fieldLabel} verhogen", - "numberField": "Getalveld" + "numberField": "Getalveld", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/pl-PL.json b/packages/@react-aria/numberfield/intl/pl-PL.json index 4cdf28fbf83..6fb797d6d66 100644 --- a/packages/@react-aria/numberfield/intl/pl-PL.json +++ b/packages/@react-aria/numberfield/intl/pl-PL.json @@ -1,5 +1,7 @@ { "decrease": "Zmniejsz {fieldLabel}", "increase": "Zwiększ {fieldLabel}", - "numberField": "Pole numeru" + "numberField": "Pole numeru", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/pt-BR.json b/packages/@react-aria/numberfield/intl/pt-BR.json index b0740b0fe44..1e18c3509f5 100644 --- a/packages/@react-aria/numberfield/intl/pt-BR.json +++ b/packages/@react-aria/numberfield/intl/pt-BR.json @@ -1,5 +1,7 @@ { "decrease": "Diminuir {fieldLabel}", "increase": "Aumentar {fieldLabel}", - "numberField": "Campo de número" + "numberField": "Campo de número", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/pt-PT.json b/packages/@react-aria/numberfield/intl/pt-PT.json index dbf5ae5146a..6a38d1ab15e 100644 --- a/packages/@react-aria/numberfield/intl/pt-PT.json +++ b/packages/@react-aria/numberfield/intl/pt-PT.json @@ -1,5 +1,7 @@ { "decrease": "Diminuir {fieldLabel}", "increase": "Aumentar {fieldLabel}", - "numberField": "Campo numérico" + "numberField": "Campo numérico", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/ro-RO.json b/packages/@react-aria/numberfield/intl/ro-RO.json index 5db51ed7581..a0d4de7dc2a 100644 --- a/packages/@react-aria/numberfield/intl/ro-RO.json +++ b/packages/@react-aria/numberfield/intl/ro-RO.json @@ -1,5 +1,7 @@ { "decrease": "Scădere {fieldLabel}", "increase": "Creștere {fieldLabel}", - "numberField": "Câmp numeric" + "numberField": "Câmp numeric", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/ru-RU.json b/packages/@react-aria/numberfield/intl/ru-RU.json index 836df8829ea..2c9e7059a15 100644 --- a/packages/@react-aria/numberfield/intl/ru-RU.json +++ b/packages/@react-aria/numberfield/intl/ru-RU.json @@ -1,5 +1,7 @@ { "decrease": "Уменьшение {fieldLabel}", "increase": "Увеличение {fieldLabel}", - "numberField": "Числовое поле" + "numberField": "Числовое поле", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/sk-SK.json b/packages/@react-aria/numberfield/intl/sk-SK.json index 3e54a2df7a4..a890089de76 100644 --- a/packages/@react-aria/numberfield/intl/sk-SK.json +++ b/packages/@react-aria/numberfield/intl/sk-SK.json @@ -1,5 +1,7 @@ { "decrease": "Znížiť {fieldLabel}", "increase": "Zvýšiť {fieldLabel}", - "numberField": "Číselné pole" + "numberField": "Číselné pole", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/sl-SI.json b/packages/@react-aria/numberfield/intl/sl-SI.json index f9fa0ccde3d..9e8f5db6957 100644 --- a/packages/@react-aria/numberfield/intl/sl-SI.json +++ b/packages/@react-aria/numberfield/intl/sl-SI.json @@ -1,5 +1,7 @@ { "decrease": "Upadati {fieldLabel}", "increase": "Povečajte {fieldLabel}", - "numberField": "Številčno polje" + "numberField": "Številčno polje", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/sr-SP.json b/packages/@react-aria/numberfield/intl/sr-SP.json index 12a4eba7361..b11007bd444 100644 --- a/packages/@react-aria/numberfield/intl/sr-SP.json +++ b/packages/@react-aria/numberfield/intl/sr-SP.json @@ -1,5 +1,7 @@ { "decrease": "Smanji {fieldLabel}", "increase": "Povećaj {fieldLabel}", - "numberField": "Polje broja" + "numberField": "Polje broja", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/sv-SE.json b/packages/@react-aria/numberfield/intl/sv-SE.json index 44366b63f61..c6e6493f41c 100644 --- a/packages/@react-aria/numberfield/intl/sv-SE.json +++ b/packages/@react-aria/numberfield/intl/sv-SE.json @@ -1,5 +1,7 @@ { "decrease": "Minska {fieldLabel}", "increase": "Öka {fieldLabel}", - "numberField": "Nummerfält" + "numberField": "Nummerfält", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/tr-TR.json b/packages/@react-aria/numberfield/intl/tr-TR.json index ea2b0ec80d8..4f18d22dfd8 100644 --- a/packages/@react-aria/numberfield/intl/tr-TR.json +++ b/packages/@react-aria/numberfield/intl/tr-TR.json @@ -1,5 +1,7 @@ { "decrease": "{fieldLabel} azalt", "increase": "{fieldLabel} arttır", - "numberField": "Sayı alanı" + "numberField": "Sayı alanı", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/uk-UA.json b/packages/@react-aria/numberfield/intl/uk-UA.json index 02edfbf3a68..60377d0fef3 100644 --- a/packages/@react-aria/numberfield/intl/uk-UA.json +++ b/packages/@react-aria/numberfield/intl/uk-UA.json @@ -1,5 +1,7 @@ { "decrease": "Зменшити {fieldLabel}", "increase": "Збільшити {fieldLabel}", - "numberField": "Поле номера" + "numberField": "Поле номера", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/zh-CN.json b/packages/@react-aria/numberfield/intl/zh-CN.json index a7a42ab37d4..a47416992d9 100644 --- a/packages/@react-aria/numberfield/intl/zh-CN.json +++ b/packages/@react-aria/numberfield/intl/zh-CN.json @@ -1,5 +1,7 @@ { "decrease": "降低 {fieldLabel}", "increase": "提高 {fieldLabel}", - "numberField": "数字字段" + "numberField": "数字字段", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/intl/zh-TW.json b/packages/@react-aria/numberfield/intl/zh-TW.json index a4661fcf92b..cfbb0fdf54b 100644 --- a/packages/@react-aria/numberfield/intl/zh-TW.json +++ b/packages/@react-aria/numberfield/intl/zh-TW.json @@ -1,5 +1,7 @@ { "decrease": "縮小 {fieldLabel}", "increase": "放大 {fieldLabel}", - "numberField": "數字欄位" + "numberField": "數字欄位", + "pastedValue": "Pasted value: {value}", + "couldNotParseValue": "Could not understand value: {value}, try another format perhaps" } diff --git a/packages/@react-aria/numberfield/package.json b/packages/@react-aria/numberfield/package.json index d04a2411fd3..dbd1bea32a9 100644 --- a/packages/@react-aria/numberfield/package.json +++ b/packages/@react-aria/numberfield/package.json @@ -28,6 +28,7 @@ "dependencies": { "@react-aria/i18n": "^3.12.11", "@react-aria/interactions": "^3.25.4", + "@react-aria/live-announcer": "^3.4.4", "@react-aria/spinbutton": "^3.6.17", "@react-aria/textfield": "^3.18.0", "@react-aria/utils": "^3.30.0", diff --git a/packages/@react-aria/numberfield/src/useNumberField.ts b/packages/@react-aria/numberfield/src/useNumberField.ts index 08da12b97a5..e590612cc91 100644 --- a/packages/@react-aria/numberfield/src/useNumberField.ts +++ b/packages/@react-aria/numberfield/src/useNumberField.ts @@ -10,11 +10,13 @@ * governing permissions and limitations under the License. */ +import {announce} from '@react-aria/live-announcer'; import {AriaButtonProps} from '@react-types/button'; import {AriaNumberFieldProps} from '@react-types/numberfield'; import {chain, filterDOMProps, isAndroid, isIOS, isIPhone, mergeProps, useFormReset, useId} from '@react-aria/utils'; -import {DOMAttributes, GroupDOMAttributes, TextInputDOMProps, ValidationResult} from '@react-types/shared'; import { + type ClipboardEvent, + type ClipboardEventHandler, InputHTMLAttributes, LabelHTMLAttributes, RefObject, @@ -22,6 +24,7 @@ import { useMemo, useState } from 'react'; +import {DOMAttributes, GroupDOMAttributes, TextInputDOMProps, ValidationResult} from '@react-types/shared'; // @ts-ignore import intlMessages from '../intl/*.json'; import {NumberFieldState} from '@react-stately/numberfield'; @@ -181,6 +184,33 @@ export function useNumberField(props: AriaNumberFieldProps, state: NumberFieldSt } }; + let onPaste: ClipboardEventHandler = (e: ClipboardEvent) => { + props.onPaste?.(e); + let inputElement = e.target as HTMLInputElement; + if ( + inputElement && + ( + ((inputElement.selectionEnd ?? -1) - (inputElement.selectionStart ?? 0)) === inputElement.value.length + ) + ) { + e.preventDefault(); + let pastedText = e.clipboardData?.getData?.('text/plain')?.trim() ?? ''; + let isValid = state.validate(pastedText); + if (isValid) { + let value = state.parser.parse(pastedText); + let reformattedValue = numberFormatter.format(value); + if (state.validate(reformattedValue)) { + state.setInputValue(reformattedValue); + if (reformattedValue !== pastedText) { + announce(stringFormatter.format('pastedValue', {value: reformattedValue}), 'polite'); + } + } + } else { + announce(stringFormatter.format('couldNotParseValue', {value: pastedText}), 'polite'); + } + } + }; + let domProps = filterDOMProps(props); let onKeyDownEnter = useCallback((e) => { if (e.nativeEvent.isComposing) { @@ -223,6 +253,7 @@ export function useNumberField(props: AriaNumberFieldProps, state: NumberFieldSt onFocusChange, onKeyDown: useMemo(() => chain(onKeyDownEnter, onKeyDown), [onKeyDownEnter, onKeyDown]), onKeyUp, + onPaste, description, errorMessage }, state, inputRef); diff --git a/packages/@react-stately/numberfield/src/useNumberFieldState.ts b/packages/@react-stately/numberfield/src/useNumberFieldState.ts index 9902a739c6a..8abee9598b1 100644 --- a/packages/@react-stately/numberfield/src/useNumberFieldState.ts +++ b/packages/@react-stately/numberfield/src/useNumberFieldState.ts @@ -61,7 +61,9 @@ export interface NumberFieldState extends FormValidationState { /** Sets the current value to the `maxValue` if any, and fires `onChange`. */ incrementToMax(): void, /** Sets the current value to the `minValue` if any, and fires `onChange`. */ - decrementToMin(): void + decrementToMin(): void, + /** Attempts to parse a value in the current locale. */ + parser: NumberParser } export interface NumberFieldStateOptions extends NumberFieldProps { @@ -281,7 +283,8 @@ export function useNumberFieldState( setNumberValue, setInputValue, inputValue, - commit + commit, + parser: numberParser }; } diff --git a/packages/react-aria-components/test/NumberField.test.js b/packages/react-aria-components/test/NumberField.test.js index 14c3e0db770..05a494d2680 100644 --- a/packages/react-aria-components/test/NumberField.test.js +++ b/packages/react-aria-components/test/NumberField.test.js @@ -10,9 +10,11 @@ * governing permissions and limitations under the License. */ +jest.mock('@react-aria/live-announcer'); import {act, pointerMap, render} from '@react-spectrum/test-utils-internal'; +import {announce} from '@react-aria/live-announcer'; import {Button, FieldError, Group, Input, Label, NumberField, NumberFieldContext, Text} from '../'; -import React from 'react'; +import React, {useState} from 'react'; import userEvent from '@testing-library/user-event'; let TestNumberField = (props) => ( @@ -183,4 +185,74 @@ describe('NumberField', () => { expect(input).not.toHaveAttribute('aria-describedby'); expect(numberfield).not.toHaveAttribute('data-invalid'); }); + + it('supports onChange', async () => { + let onChange = jest.fn(); + let {getByRole} = render(); + let input = getByRole('textbox'); + await user.tab(); + await user.clear(input); + await user.keyboard('1024'); + await user.keyboard('{Enter}'); + expect(onChange).toHaveBeenCalledWith(1024); + }); + + it('should support pasting', async () => { + let {getByRole} = render(); + let input = getByRole('textbox'); + await user.tab(); + await user.clear(input); + await user.paste('1024'); + expect(input).toHaveValue('1,024'); + expect(announce).toHaveBeenCalledWith('Pasted value: 1,024', 'polite'); + }); + + it('should support pasting into a format', async () => { + let onChange = jest.fn(); + let {getByRole} = render(); + let input = getByRole('textbox'); + await user.tab(); + await user.clear(input); + await user.paste('1,024'); + expect(input).toHaveValue('$1,024.00'); + expect(announce).toHaveBeenCalledWith('Pasted value: $1,024.00', 'polite'); + expect(onChange).not.toHaveBeenCalled(); + await user.keyboard('{Enter}'); + expect(onChange).toHaveBeenCalledWith(1024); + }); + + it('should tell users if their paste failed', async () => { + let {getByRole} = render(); + let input = getByRole('textbox'); + await user.tab(); + await user.clear(input); + await user.paste('$1.00 024 5.6'); + expect(input).toHaveValue(''); + expect(announce).toHaveBeenCalledWith('Could not understand value: $1.00 024 5.6, try another format perhaps', 'polite'); + }); + + it('should support paste announcements for a controlled numberfield', async () => { + function ControlledNumberField({value, ...props}) { + let [numberValue, setNumberValue] = useState(value); + return ; + } + let {getByRole} = render(); + let input = getByRole('textbox'); + await user.tab(); + await user.clear(input); + await user.paste('1024'); + expect(input).toHaveValue('1,024'); + expect(announce).toHaveBeenCalledWith('Pasted value: 1,024', 'polite'); + }); + + it('should not change the input value if the new value is not accepted', async () => { + let {getByRole} = render(); + let input = getByRole('textbox'); + await user.tab(); + await user.clear(input); + await user.paste('1024'); + expect(input).toHaveValue('1,024'); + await user.keyboard('{Enter}'); + expect(input).toHaveValue('200'); + }); }); diff --git a/yarn.lock b/yarn.lock index 806902c8e69..52a9a544245 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5879,6 +5879,7 @@ __metadata: dependencies: "@react-aria/i18n": "npm:^3.12.11" "@react-aria/interactions": "npm:^3.25.4" + "@react-aria/live-announcer": "npm:^3.4.4" "@react-aria/spinbutton": "npm:^3.6.17" "@react-aria/textfield": "npm:^3.18.0" "@react-aria/utils": "npm:^3.30.0"