@instructure/quiz-number-input
v21.0.1
Published
Number input with i18n support
Downloads
7,267
Keywords
Readme
category: packages
An internationalized, controlled number input:
---
example: true
render: false
---
class Example extends React.Component {
state = {
number: 0.1
}
handleChange = (event, number) => this.setState({ number })
render () {
return (
<div>
<NumberInput
{...this.props}
value={this.state.number}
onChange={this.handleChange}
/>
<br />
<Button onClick={() => this.handleChange({}, '5')}>
Go with 5
</Button>
</div>
)
}
}
render(<Example label="Battery capacity in Amp-hrs" step={0.1} min={0.1} />)
With precision:
---
example: true
render: false
---
class Example extends React.Component {
state = {
number: 9.99,
precisionType: 'decimalPrecision',
precisionValue: 2,
precision: 2
}
handleNumberChange = (event, number) => this.setState({ number })
handlePrecisionChange = (event, precisionValue, precision) => {
this.setState({
precisionValue,
precision: precision ? Number(precision) : null
})
}
render () {
return (
<div>
<SimpleSelect label="Precision type" onChange={(e, o) => this.setState({ precisionType: o.value })}>
<SimpleSelect.Option id="decimal" value="decimalPrecision">Decimal</SimpleSelect.Option>
<SimpleSelect.Option id="significant-digit" value="significantDigits">Significant digits</SimpleSelect.Option>
</SimpleSelect>
<br />
<NumberInput
label={this.state.precisionType}
min={0}
max={10}
decimalPrecision={0}
value={this.state.precisionValue}
onChange={this.handlePrecisionChange}
/>
<br />
<NumberInput
label="Value"
decimalPrecision={this.state.precisionType === 'decimalPrecision' ? this.state.precision : null}
significantDigits={this.state.precisionType === 'significantDigits' ? this.state.precision : null}
value={this.state.number}
onChange={this.handleNumberChange}
/>
</div>
)
}
}
render(<Example />)
The number input accepts and displays values according to the specified locale, which can be supplied either as a property or with ApplyLocale. If a locale is not specified, it will be inferred from the browser.
If the min
, max
, or step
props are given as strings, they will be parsed
according to the rules of the en-US
locale (with .
decimal separator). This
is for backward-compatibility only; it is recommended to pass numbers, not
strings, for these props.
The onChange
prop receives the content of the input as a second argument, and
a normalized string parsed according to the current locale as the third
argument. For example, if the locale is fr
and the input value is set to
1,5
, the third argument to onChange
will be "1.5"
. Note that this third
argument will be null
if the input string cannot be parsed.
If the value
prop is a number, it will be formatted according to the locale on
render; if a string is given, make sure it is already in the correct format for
the locale.
The number input will attempt to format the string on blur. The onChange
handler will be called before the onBlur
handler.
---
example: true
render: false
---
class Example extends React.Component {
state = {
locale: 'de',
messages: [],
normalizedValue: '2.4',
value: 2.4
}
handleChange = (event, value, normalizedValue) => {
this.setState({ value, normalizedValue, messages: [] })
}
handleBlur = () => {
if (this.state.value && !this.state.normalizedValue) {
this.setState({ messages: [{ text: 'Invalid number', type: 'error' }] })
} else {
this.setState({ messages: [] })
}
}
render () {
const label = this.state.locale === 'de' ? "Comma separator" : "Period separator"
return (
<div>
<SimpleSelect
renderLabel="Choose locale"
onChange={(e, o) => this.setState({ locale: o.value })}
>
<SimpleSelect.Option id="de" key="de" value="de">de</SimpleSelect.Option>
<SimpleSelect.Option id="en" key="en" value="en">en</SimpleSelect.Option>
</SimpleSelect>
<View padding="small">
<NumberInput
renderLabel={label}
locale={this.state.locale}
messages={this.state.messages}
onBlur={this.handleBlur}
onChange={this.handleChange}
step={0.1}
value={this.state.value}
/>
<p>Normalized value: <code>{JSON.stringify(this.state.normalizedValue)}</code></p>
</View>
</div>
)
}
}
render(<Example />)
Using a text input
By default, NumberInput
will use a numeric input field. This causes mobile
Chrome to use a numeric keypad input instead of a regular keyboard input. This
may not be the desired behavior, for example if you don't want to indicate to
the user that a number is expected, or you want to allow users to type in
numbers in scientific notation (see below), but you still need the
internationalization features described above.
In this case, pass inputType="text"
to the component to use a plain text input
instead of a numeric input field:
---
example: true
render: false
---
class Example extends React.Component {
state = {
value: '1.23',
normalizedValue: '1.23'
}
handleChange = (event, value, normalizedValue) => this.setState({ value, normalizedValue })
render () {
return (
<View padding="small">
<NumberInput
inputType="text"
label="Text input"
value={this.state.value}
onChange={this.handleChange}
/>
<p>Normalized value: <code>{JSON.stringify(this.state.normalizedValue)}</code></p>
</View>
)
}
}
render(<Example />)
Scientific Notation
The ScientificNumberInput
component wraps NumberInput
, passing numbers given
in scientific notation as the third argument to the onChange
handler. The
scientific notation format is mantissa * 10 ^ exponent
(whitespace-insensitive), e.g. 1.25*10^-3
.
Note that numbers in scientific notation are not localized. If you are in a
locale that uses commas as the decimal separator, you will still need to use a
decimal point .
for scientific notation. Thousands separators are not allowed,
and the exponent must be an integer.
If the significantDigits
or decimalPrecision
props are given, they apply to
the mantissa. The min
, max
and step
props are ignored (for now).
---
example: true
render: false
---
class Example extends React.Component {
state = {
messages: [],
normalizedValue: '1.175*10^-3',
value: '1.175*10^-3'
}
handleChange = (event, value, normalizedValue) => {
this.setState({ value, normalizedValue, messages: [] })
}
handleBlur = () => {
if (this.state.value && !this.state.normalizedValue) {
this.setState({ messages: [{ text: 'Invalid number', type: 'error' }] })
} else {
this.setState({ messages: [] })
}
}
render () {
return (
<View padding="small">
<ScientificNumberInput
inputType="text"
renderLabel="Scientific notation allowed"
messages={this.state.messages}
onBlur={this.handleBlur}
onChange={this.handleChange}
value={this.state.value}
/>
<p>Normalized value: <code>{JSON.stringify(this.state.normalizedValue)}</code></p>
</View>
)
}
}
render(<Example />)
When precision is specified for ScientificNumberInput
, it applies to the
mantissa only. The exponent must be an integer.
---
example: true
render: false
---
class Example extends React.Component {
state = {
value: '1.23*10^2',
normalizedValue: '1.23*10^2',
precisionType: 'decimalPrecision',
precisionValue: 2,
precision: 2
}
handleNumberChange = (event, value, normalizedValue) => this.setState({ value, normalizedValue })
handlePrecisionChange = (event, precisionValue, precision) => {
this.setState({
precisionValue,
precision: precision ? Number(precision) : null
})
}
render () {
return (
<div>
<SimpleSelect renderLabel="Precision type" onChange={(e, o) => this.setState({ precisionType: o.value })}>
<SimpleSelect.Option id="decimal-precision" value="decimalPrecision">Decimal</SimpleSelect.Option>
<SimpleSelect.Option id="significant-digits" value="significantDigits">Significant digits</SimpleSelect.Option>
</SimpleSelect>
<br />
<NumberInput
label={this.state.precisionType}
min={0}
max={10}
decimalPrecision={0}
value={this.state.precisionValue}
onChange={this.handlePrecisionChange}
/>
<br />
<ScientificNumberInput
label="Value"
inputType="text"
decimalPrecision={this.state.precisionType === 'decimalPrecision' ? this.state.precision : null}
significantDigits={this.state.precisionType === 'significantDigits' ? this.state.precision : null}
value={this.state.value}
onChange={this.handleNumberChange}
/>
<p>Normalized value: <code>{JSON.stringify(this.state.normalizedValue)}</code></p>
</div>
)
}
}
render(<Example />)