@fluentui/react-spinbutton 9.0.8 → 9.0.10
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.json +81 -1
- package/CHANGELOG.md +27 -2
- package/lib/SpinButton.js.map +1 -1
- package/lib/SpinButtonField.js.map +1 -1
- package/lib/components/SpinButton/SpinButton.js.map +1 -1
- package/lib/components/SpinButton/SpinButton.types.js.map +1 -1
- package/lib/components/SpinButton/index.js.map +1 -1
- package/lib/components/SpinButton/renderSpinButton.js.map +1 -1
- package/lib/components/SpinButton/useSpinButton.js.map +1 -1
- package/lib/components/SpinButton/useSpinButtonStyles.js.map +1 -1
- package/lib/components/SpinButtonField/SpinButtonField.js.map +1 -1
- package/lib/components/SpinButtonField/index.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/utils/clamp.js.map +1 -1
- package/lib/utils/getBound.js.map +1 -1
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/precision.js.map +1 -1
- package/lib-amd/SpinButton.js +6 -0
- package/lib-amd/SpinButton.js.map +1 -0
- package/lib-amd/SpinButtonField.js +6 -0
- package/lib-amd/SpinButtonField.js.map +1 -0
- package/lib-amd/components/SpinButton/SpinButton.js +15 -0
- package/lib-amd/components/SpinButton/SpinButton.js.map +1 -0
- package/lib-amd/components/SpinButton/SpinButton.types.js +5 -0
- package/lib-amd/components/SpinButton/SpinButton.types.js.map +1 -0
- package/lib-amd/components/SpinButton/index.js +10 -0
- package/lib-amd/components/SpinButton/index.js.map +1 -0
- package/lib-amd/components/SpinButton/renderSpinButton.js +36 -0
- package/lib-amd/components/SpinButton/renderSpinButton.js.map +1 -0
- package/lib-amd/components/SpinButton/useSpinButton.js +252 -0
- package/lib-amd/components/SpinButton/useSpinButton.js.map +1 -0
- package/lib-amd/components/SpinButton/useSpinButtonStyles.js +312 -0
- package/lib-amd/components/SpinButton/useSpinButtonStyles.js.map +1 -0
- package/lib-amd/components/SpinButtonField/SpinButtonField.js +13 -0
- package/lib-amd/components/SpinButtonField/SpinButtonField.js.map +1 -0
- package/lib-amd/components/SpinButtonField/index.js +6 -0
- package/lib-amd/components/SpinButtonField/index.js.map +1 -0
- package/lib-amd/index.js +13 -0
- package/lib-amd/index.js.map +1 -0
- package/lib-amd/utils/clamp.js +30 -0
- package/lib-amd/utils/clamp.js.map +1 -0
- package/lib-amd/utils/getBound.js +19 -0
- package/lib-amd/utils/getBound.js.map +1 -0
- package/lib-amd/utils/index.js +8 -0
- package/lib-amd/utils/index.js.map +1 -0
- package/lib-amd/utils/precision.js +44 -0
- package/lib-amd/utils/precision.js.map +1 -0
- package/lib-commonjs/SpinButton.js.map +1 -1
- package/lib-commonjs/SpinButtonField.js.map +1 -1
- package/lib-commonjs/components/SpinButton/SpinButton.js.map +1 -1
- package/lib-commonjs/components/SpinButton/index.js.map +1 -1
- package/lib-commonjs/components/SpinButton/renderSpinButton.js.map +1 -1
- package/lib-commonjs/components/SpinButton/useSpinButton.js.map +1 -1
- package/lib-commonjs/components/SpinButton/useSpinButtonStyles.js.map +1 -1
- package/lib-commonjs/components/SpinButtonField/SpinButtonField.js.map +1 -1
- package/lib-commonjs/components/SpinButtonField/index.js.map +1 -1
- package/lib-commonjs/index.js.map +1 -1
- package/lib-commonjs/utils/clamp.js.map +1 -1
- package/lib-commonjs/utils/getBound.js.map +1 -1
- package/lib-commonjs/utils/index.js.map +1 -1
- package/lib-commonjs/utils/precision.js.map +1 -1
- package/package.json +8 -9
- package/Spec.md +0 -370
- package/spec-assets/spec-spinbutton-anatomy-alt-optional.png +0 -0
- package/spec-assets/spec-spinbutton-anatomy.png +0 -0
- package/spec-assets/spec-spinbutton-rtl.png +0 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@fluentui/react-spinbutton",
|
3
|
-
"version": "9.0.
|
3
|
+
"version": "9.0.10",
|
4
4
|
"description": "Fluent UI React SpinButton component.",
|
5
5
|
"main": "lib-commonjs/index.js",
|
6
6
|
"module": "lib/index.js",
|
@@ -20,26 +20,25 @@
|
|
20
20
|
"lint": "just-scripts lint",
|
21
21
|
"start": "yarn storybook",
|
22
22
|
"test": "jest --passWithNoTests",
|
23
|
-
"docs": "api-extractor run --config=config/api-extractor.local.json --local",
|
24
|
-
"build:local": "tsc -p ./tsconfig.lib.json --module esnext --emitDeclarationOnly && node ../../../scripts/typescript/normalize-import --output ./dist/types/packages/react-components/react-spinbutton/src && yarn docs",
|
25
23
|
"storybook": "start-storybook",
|
26
|
-
"type-check": "tsc -b tsconfig.json"
|
24
|
+
"type-check": "tsc -b tsconfig.json",
|
25
|
+
"generate-api": "tsc -p ./tsconfig.lib.json --emitDeclarationOnly && just-scripts api-extractor"
|
27
26
|
},
|
28
27
|
"devDependencies": {
|
29
28
|
"@fluentui/eslint-plugin": "*",
|
30
29
|
"@fluentui/react-conformance": "*",
|
31
30
|
"@fluentui/react-conformance-griffel": "9.0.0-beta.18",
|
32
|
-
"@fluentui/react-label": "^9.0.
|
31
|
+
"@fluentui/react-label": "^9.0.12",
|
33
32
|
"@fluentui/scripts": "^1.0.0"
|
34
33
|
},
|
35
34
|
"dependencies": {
|
36
35
|
"@griffel/react": "^1.4.2",
|
37
36
|
"@fluentui/keyboard-keys": "^9.0.1",
|
38
|
-
"@fluentui/react-field": "9.0.0-alpha.
|
37
|
+
"@fluentui/react-field": "9.0.0-alpha.10",
|
39
38
|
"@fluentui/react-icons": "^2.0.175",
|
40
|
-
"@fluentui/react-input": "^9.2.
|
41
|
-
"@fluentui/react-theme": "^9.1.
|
42
|
-
"@fluentui/react-utilities": "^9.2.
|
39
|
+
"@fluentui/react-input": "^9.2.7",
|
40
|
+
"@fluentui/react-theme": "^9.1.3",
|
41
|
+
"@fluentui/react-utilities": "^9.2.2",
|
43
42
|
"tslib": "^2.1.0"
|
44
43
|
},
|
45
44
|
"peerDependencies": {
|
package/Spec.md
DELETED
@@ -1,370 +0,0 @@
|
|
1
|
-
# @fluentui/react-spinbutton Spec
|
2
|
-
|
3
|
-
## Background
|
4
|
-
|
5
|
-
SpinButtons are used to allow numeric input bounded between minimum and maximum values with button controls to increment and decrement the input value by some step amount. Values can also be manipulated via the keyboard.
|
6
|
-
|
7
|
-
## Prior Art
|
8
|
-
|
9
|
-
- Open UI research: https://github.com/openui/open-ui/pull/431
|
10
|
-
- Github Epic: https://github.com/microsoft/fluentui/issues/20930
|
11
|
-
- WAI-ARIA Toolbar Example (font size selector): https://www.w3.org/TR/wai-aria-practices/examples/toolbar/toolbar.html
|
12
|
-
|
13
|
-
### Naming
|
14
|
-
|
15
|
-
There is little consensus for naming this type of component. Of the design systems surveyed in Open UI there are seven implementations with six different names:
|
16
|
-
|
17
|
-
1. InputNumber
|
18
|
-
2. NumberInput
|
19
|
-
3. SpinButton (x2)
|
20
|
-
4. NumberField
|
21
|
-
5. Counter
|
22
|
-
6. input-stepper
|
23
|
-
|
24
|
-
This specification recommends `SpinButton` as the name for this component. Given the lack of naming consensus in the surveryed design systems and that the ARIA role for this control is `spinbutton` this feels like the closest to a standard name. Additionally, Fluent UI v8 uses the name `SpinButton` so sticking with that is simpler for existing users making the upgrade to the new version.
|
25
|
-
|
26
|
-
### Anatomy
|
27
|
-
|
28
|
-
`SpinButton` consists of three mandatory parts:
|
29
|
-
|
30
|
-
1. **Input**: accepts users input and displays the current value.
|
31
|
-
2. **Increment Button**: a button that increases the current value by the step amount.
|
32
|
-
3. **Decrement Button**: a button that decreases the current value by the step amount.
|
33
|
-
|
34
|
-
`SpinButton` has several optional parts:
|
35
|
-
|
36
|
-
1. **Label**: any input must have a label but whether the label is included as part of the `SpinButton` control varies depending on the design system.
|
37
|
-
2. **Helper text**: extra text in addition to the label to provide "help", perhaps by offering an example. Typically appears below the input.
|
38
|
-
3. **Formatted value**: optional formatting applied to the input value. For example, turning "12" into "12 pt" for a font size picker.
|
39
|
-
|
40
|
-
Note that labels and helper text are included here for completeness but will be omitted from the converged `SpinButton` as there is an [open RFC discussing how to handle these elements for vNext](https://github.com/microsoft/fluentui/issues/19627#issuecomment-1022646775).
|
41
|
-
|
42
|
-
#### Base `SpinButton` Anatomy
|
43
|
-
|
44
|
-
![Base SpinButton Anatomy (annotated)](./spec-assets/spec-spinbutton-anatomy.png)
|
45
|
-
|
46
|
-
#### Alternate/Optional `SpinButton` Anatomy
|
47
|
-
|
48
|
-
![Alternate/Optional SpinButton Anatomy (annotated)](./spec-assets/spec-spinbutton-anatomy-alt-optional.png)
|
49
|
-
|
50
|
-
### Common Features
|
51
|
-
|
52
|
-
#### Attributes
|
53
|
-
|
54
|
-
1. **min**: the minimum valid value for the control
|
55
|
-
2. **max**: the maximum valid value for the control
|
56
|
-
3. **step**: the step size or amount the value is changed by one increment or decrement
|
57
|
-
4. **value**: the current value for the control
|
58
|
-
|
59
|
-
#### Direct Input
|
60
|
-
|
61
|
-
All `SpinButtons` surveyed can take input directly by typing into the control's input field. Many clamp this value in the range of `min`-`max` but, notably, the native HTML control does not. Rather, it allows values outside this range but puts the control into an invalid state. The [ARIA spec](https://www.w3.org/TR/wai-aria-practices/#wai-aria-roles-states-and-properties-18) allows for the native control behavior or for values to be restricted to only valid values as determined by users of the control.
|
62
|
-
|
63
|
-
#### Step Buttons
|
64
|
-
|
65
|
-
All `SpinButtons` have support for incrementing and decrementing the value via step buttons. Clicking a step button changes the current value of the control by a `step` size (e.g., `1`, `0.1`, `10`, etc.).
|
66
|
-
|
67
|
-
When using a keyboard step buttons are not focusable, rather the control uses the up and down keyboard arrows to modify the current value with the same rules as clicking a step button.
|
68
|
-
|
69
|
-
Unlike directly typing input into the control, step buttons do not allow input outside of the bounds of `min` and `max`.
|
70
|
-
|
71
|
-
### i18n
|
72
|
-
|
73
|
-
#### RTL (Right to Left Languages)
|
74
|
-
|
75
|
-
Most implementations flip the layout of the control for RTL. Using the base example, the step buttons appear on the left with the value on the right as opposed to the LTR version where the value is on the left and the steppers on the right.
|
76
|
-
|
77
|
-
![Example of an RTL SpinButton](./spec-assets/spec-spinbutton-rtl.png)
|
78
|
-
|
79
|
-
### a11y
|
80
|
-
|
81
|
-
The [WAI-ARIA spec for SpinButton](https://www.w3.org/TR/wai-aria-practices/#spinbutton) covers this well and provides examples.
|
82
|
-
|
83
|
-
### [SpinButton in v8/Fabric](https://developer.microsoft.com/en-us/fluentui#/controls/web/spinbutton)
|
84
|
-
|
85
|
-
Fluent UI v8 (Fabric) ships a `SpinButton` control. This control supports directly typing values into the input field, stepping via step buttons, clamping values in a min-max range and suffixes on the displayed value. The control also supports variants like including an icon in the label, label positioning and styling overrides. `SpinButton` has RTL support and implements the correct ARIA attributes for proper accessibility support.
|
86
|
-
|
87
|
-
One interesting aspect of `SpinButton` in v8 is that the `value` prop (the prop that dictates the actual current value of the control) is a string but `min`, `max` and `step` are all numbers. This is in keeping with `<input type="number">` where the `value` attribute is also a string but it feels odd for a React component that works with numeric values to take in a string `value` prop. As an aside, `<input type="number">` has an additional property called [`valueAsNumber`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement) that is meant for retrieving the value as a `Number`.
|
88
|
-
|
89
|
-
v8 supports an optional icon that appears before the label. As none of the other v8 input controls support adding an icon next to the label as part of their component APIs and how [labeling will work for vNext inputs is still an open question](https://github.com/microsoft/fluentui/issues/19627#issuecomment-1022646775) this feature will be omitted from this spec. Having an icon by the control can be achieved by aligning an icon with the control or perhaps by updating the vNext `Label` component to support icons.
|
90
|
-
|
91
|
-
#### Props
|
92
|
-
|
93
|
-
Props not directly related to `SpinButton` functionality omitted for brevity. [See the complete implementation list](https://developer.microsoft.com/en-us/fluentui#/controls/web/spinbutton#implementation) all props.
|
94
|
-
|
95
|
-
| Prop | Description |
|
96
|
-
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
97
|
-
| decrementButtonAriaLabel | Accessible label text for the decrement button (for screen reader users). |
|
98
|
-
| decrementButtonIcon | Custom props for the decrement button. |
|
99
|
-
| defaultValue | Initial value of the control (assumed to be valid). Updates to this prop will not be respected. Use this if you intend for the SpinButton to be an uncontrolled component which maintains its own value. For a controlled component, use value instead. (Mutually exclusive with value.) |
|
100
|
-
| disabled | Whether or not the control is disabled. |
|
101
|
-
| downArrowButtonStyles | Custom styles for the down arrow button. Note: The buttons are in a checked state when arrow keys are used to increment/decrement the SpinButton. Use rootChecked instead of rootPressed for styling when that is the case. |
|
102
|
-
| iconButtonProps | Additional props for the up and down arrow buttons. |
|
103
|
-
| iconProps | Props for an icon to display alongside the control's label. |
|
104
|
-
| incrementButtonAriaLabel | Accessible label text for the increment button (for screen reader users). |
|
105
|
-
| incrementButtonIcon | Custom props for the increment button. |
|
106
|
-
| inputProps | Additional props for the input field. |
|
107
|
-
| keytipProps | Keytip for the control. |
|
108
|
-
| label | Descriptive label for the control. |
|
109
|
-
| labelPosition | Where to position the control's label. |
|
110
|
-
| max | Max value of the control. If not provided, the control has no maximum value. |
|
111
|
-
| min | Min value of the control. If not provided, the control has no minimum value. |
|
112
|
-
| onBlur | Callback for when the control loses focus. |
|
113
|
-
| onChange | Callback for when the committed/validated value changes. This is called _after_ onIncrement, onDecrement, or onValidate, on the following events: - User presses the up/down buttons (on single press or every spin) - User presses the up/down arrow keys (on single press or every spin) - User _commits_ edits to the input text by focusing away (blurring) or pressing enter. Note that this is NOT called for every key press while the user is editing. |
|
114
|
-
| onDecrement | Callback for when the decrement button or down arrow key is pressed. |
|
115
|
-
| onFocus | Callback for when the user focuses the control. |
|
116
|
-
| onIncrement | Callback for when the increment button or up arrow key is pressed. |
|
117
|
-
| onValidate | Callback for when the entered value should be validated. |
|
118
|
-
| precision | How many decimal places the value should be rounded to. The default is calculated based on the precision of step: i.e. if step = 1, precision = 0. step = 0.0089, precision = 4. step = 300, precision = 2. step = 23.00, precision = 2. |
|
119
|
-
| step | Difference between two adjacent values of the control. This value is used to calculate the precision of the input if no precision is given. The precision calculated this way will always be >= 0. |
|
120
|
-
| title | A more descriptive title for the control, visible on its tooltip. |
|
121
|
-
| upArrowButtonStyles | Custom styles for the up arrow button. Note: The buttons are in a checked state when arrow keys are used to increment/decrement the SpinButton. Use rootChecked instead of rootPressed for styling when that is the case. |
|
122
|
-
| value | Current value of the control (assumed to be valid). Only provide this if the SpinButton is a controlled component where you are maintaining its current state and passing updates based on change events; otherwise, use the defaultValue property. (Mutually exclusive with defaultValue.) |
|
123
|
-
|
124
|
-
### [SpinButton in v0/Northstar](https://fluentsite.z22.web.core.windows.net/0.59.0/components/input/definition)
|
125
|
-
|
126
|
-
Northstar [lacks a dedicated `SpinButton` component](https://github.com/microsoft/fluentui/issues/16273), rather in has `Input` which takes a `type` prop that can be set to `"number"` making the component equivalent of [input type="number"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number).
|
127
|
-
|
128
|
-
Given that Northstar is only providing the native web platform number input without custom styling applied it will not be considered further. In its place the native number input will be considered as it has behavior similar to `SpinButton`.
|
129
|
-
|
130
|
-
### [input type="number"](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number)
|
131
|
-
|
132
|
-
This is a standard HTML control for entering numbers. It includes built-in validation to reject non-numeric values and optionally provides stepper arrows to increment or decrement the value.
|
133
|
-
|
134
|
-
#### Element Attributes
|
135
|
-
|
136
|
-
This is not an exhaustive list of attributes for this element but a curated list of relevant attributes. For a complete list [see the MDN page for `<input type="number">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#additional_attributes)
|
137
|
-
|
138
|
-
| Attribute | Description |
|
139
|
-
| --------- | ------------------------------------------------------------------------------- |
|
140
|
-
| list | Allows the input to be associated with a `datalist` to provide suggested values |
|
141
|
-
| max | Maximum acceptable value. Must be greater than or equal to `min` |
|
142
|
-
| min | Minimum acceptable value. Must be less than or equal to `max` |
|
143
|
-
| step | The granularity of the value when incrementing or decrementing |
|
144
|
-
|
145
|
-
Despite supporting both `min` and `max` attributes a native number input will allow users to enter values outside the specified bounds. This situation is resolved via a process called [constraint validation](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Constraint_validation) that adds CSS pseudo classes to the element for styling purposes and raises validation events.
|
146
|
-
|
147
|
-
There are very few options for cross-browser styling of native number inputs. The [::-webkit-inner-spin-button](https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-inner-spin-button) pseudo element allows for selecting the spin buttons of a number input but is only supported by Webkit and Blink based browsers.
|
148
|
-
|
149
|
-
Native number inputs are meant strictly for number input but what constitutes number input is inconsistent across browsers ([see this Bugzilla issue for details](https://bugzilla.mozilla.org/show_bug.cgi?id=1398528)). You can easily see this on [MDN's simple example](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#a_simple_number_input). In Edge 96 you can enter exponential numbers like "1e+343434" but not arbitrary strings like "cats". On the same example in Firefox 95 you can enter both "1e+343434" and "cats".
|
150
|
-
|
151
|
-
Inspecting a native number input with devtools shows that it implements the [spinbutton ARIA attributes as described by WAI-ARIA](https://www.w3.org/TR/wai-aria-practices/#spinbutton)
|
152
|
-
|
153
|
-
#### Examples
|
154
|
-
|
155
|
-
- [Controlling Step Size](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#controlling_step_size)
|
156
|
-
- [Specifying Minimum and Maximum Values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#specifying_minimum_and_maximum_values)
|
157
|
-
- [Allowing Decimal Values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#allowing_decimal_values)
|
158
|
-
- [Offering Suggested Values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#offering_suggested_values)
|
159
|
-
|
160
|
-
## Sample Code
|
161
|
-
|
162
|
-
### Uncontrolled Example
|
163
|
-
|
164
|
-
```tsx
|
165
|
-
<SpinButton defaultValue="1" />
|
166
|
-
```
|
167
|
-
|
168
|
-
### Controlled Example
|
169
|
-
|
170
|
-
```tsx
|
171
|
-
type SpinButtonChangeData = {
|
172
|
-
value?: number;
|
173
|
-
displayValue?: string;
|
174
|
-
};
|
175
|
-
|
176
|
-
const [value, setValue] = useState<number>(2);
|
177
|
-
const onControlledExampleChange = (_event, data: SpinButtonChangeData) => {
|
178
|
-
setValue(data.value);
|
179
|
-
};
|
180
|
-
|
181
|
-
<SpinButton value={value} onChange={onControlledExampleChange} />;
|
182
|
-
```
|
183
|
-
|
184
|
-
### Custom Display Format Example
|
185
|
-
|
186
|
-
```tsx
|
187
|
-
type SpinButtonChangeData = {
|
188
|
-
value: number;
|
189
|
-
};
|
190
|
-
|
191
|
-
type FormatterFn = (value: number) => string;
|
192
|
-
type ParserFn = (formattedValue: string) => number;
|
193
|
-
|
194
|
-
// Takes a number in and returns a formatted string
|
195
|
-
// Ex: 12 becomes "12 pt"
|
196
|
-
const fontFormatter: FormatterFn = value => {
|
197
|
-
return `${value} pt`;
|
198
|
-
};
|
199
|
-
|
200
|
-
// Takes a formatted string in and returns a number
|
201
|
-
// Ex: "12 pt" becomes 12
|
202
|
-
const fontParser: ParserFn = formattedValue => {
|
203
|
-
return parseFloat(formattedValue);
|
204
|
-
};
|
205
|
-
|
206
|
-
const [value, setValue] = useState<number>(3);
|
207
|
-
const [displayValue, setDisplayValue] = useState<string>(formatter(3));)
|
208
|
-
|
209
|
-
const onControlledExampleChange = (_event, data: SpinButtonChangeData) => {
|
210
|
-
if (data.value !== undefined) {
|
211
|
-
setValue(data.value);
|
212
|
-
setDisplayValue(fontFormatter(data.value));
|
213
|
-
} else if (data.displayValue !== undefined) {
|
214
|
-
const nextValue = fontParser(data.displayValue);
|
215
|
-
setValue(nextValue);
|
216
|
-
setDisplayValue(fontFormatter(nextValue));
|
217
|
-
}
|
218
|
-
};
|
219
|
-
|
220
|
-
<SpinButton
|
221
|
-
value={value}
|
222
|
-
displayValue={displayValue}
|
223
|
-
onChange={onControlledExampleChange}
|
224
|
-
/>
|
225
|
-
```
|
226
|
-
|
227
|
-
### Basic Example Implementation
|
228
|
-
|
229
|
-
A very basic example to demonstrate how formatting will work in practice.
|
230
|
-
|
231
|
-
[Link to example on Codesandbox](https://codesandbox.io/s/spinbutton-example-formatted-values-66pou?file=/src/SpinButton/SpinButton.js)
|
232
|
-
|
233
|
-
## API
|
234
|
-
|
235
|
-
[See the types](./components/SpinButton/SpinButton.types.ts)
|
236
|
-
|
237
|
-
## Structure
|
238
|
-
|
239
|
-
- _**Public**_
|
240
|
-
|
241
|
-
```tsx
|
242
|
-
<SpinButton value={10} displayValue="$10.00" min={1} max={100} step={5} />
|
243
|
-
```
|
244
|
-
|
245
|
-
- _**Internal**_
|
246
|
-
|
247
|
-
```tsx
|
248
|
-
<slots.root {...slotProps.root}>
|
249
|
-
<slots.input {...slotProps.input} />
|
250
|
-
<slots.incrementButton {...slots.incrementButton} />
|
251
|
-
<slots.decrementButton {...slots.decrementButton} />
|
252
|
-
</slots.root>
|
253
|
-
```
|
254
|
-
|
255
|
-
- _**DOM** - how the component will be rendered as HTML elements_
|
256
|
-
|
257
|
-
Note that `aria-valuetext` is conditionally rendered. In this case it is rendered because formatting is applied in this example by the `displayValue` prop in JSX.
|
258
|
-
|
259
|
-
```html
|
260
|
-
<!-- root slot -->
|
261
|
-
<div class="fui-SpinButton">
|
262
|
-
<!-- input slot -->
|
263
|
-
<input
|
264
|
-
type="text"
|
265
|
-
role="spinbutton"
|
266
|
-
class="fui-SpinButton-input"
|
267
|
-
value="$10.00"
|
268
|
-
aria-valuenow="10"
|
269
|
-
aria-valuemin="1"
|
270
|
-
aria-valuemax="100"
|
271
|
-
aria-valuetext="$10.00"
|
272
|
-
/>
|
273
|
-
<!-- increment button slot -->
|
274
|
-
<!-- note we'll probably using icons rather than "+" and "-" inside the buttons -->
|
275
|
-
<button tabindex="-1" type="button" class="fui-SpinButton-button fui-SpinButton-increment-button">+</button>
|
276
|
-
<!-- decrement button slot -->
|
277
|
-
<button tabindex="-1" type="button" class="fui-SpinButton-button fui-SpinButton-decrement-button">-</button>
|
278
|
-
</div>
|
279
|
-
```
|
280
|
-
|
281
|
-
## Migration
|
282
|
-
|
283
|
-
_Describe what will need to be done to upgrade from the existing implementations:_
|
284
|
-
|
285
|
-
- _Migration from v8_
|
286
|
-
|
287
|
-
1. Ensure `value` prop is a number, not a string
|
288
|
-
2. Replace `onIncrement` and `onDecrement` callbacks with `onChange`.
|
289
|
-
1. Increment/decrement logic can be handled by comparing `data.value` and the current React/Redux/etc state value in the `onChange` callback.
|
290
|
-
3. Update `onChange` callback to handle new signature.
|
291
|
-
4. Remove `onValidate` callback.
|
292
|
-
5. Change ARIA props.
|
293
|
-
1. Change non-standard props to standard ones (e.g., `ariaLabel` to `aria-label`).
|
294
|
-
2. Remove `ariaPositionInSet`, `ariaSetSize`, `ariaValueNow`, `ariaValueText`. The first two are not relevant for a spinbutton and the latter two are internal implementation details managed by the component.
|
295
|
-
|
296
|
-
- _Migration from v0_
|
297
|
-
|
298
|
-
Not applicable as v0 does not implement this component or one like it.
|
299
|
-
|
300
|
-
## Behaviors
|
301
|
-
|
302
|
-
`SpinButton`'s `value` prop is always a number, in contrast to the v8 implementation that gave `value` a string type. `SpinButton`s manipulate numeric values and making `value` a number aligns it with the other related props: `min`, `max` and `step`. `SpinButton`'s `value` is always displayed as a string which is determined by the `displayValue` prop or by stringifying `value` when `displayValue` is not provided (for uncontrolled `SpinButton`s `defaultValue` is stringified rather than `value`).
|
303
|
-
|
304
|
-
`SpinButton` users may apply custom formatting to the component by providing a value to the `displayValue` prop.
|
305
|
-
|
306
|
-
Values outside of the min/max bounds can be provided to `SpinButton` and they will be displayed. When stepping the value with the step buttons or hotkeys the value will not be stepped outside of the min/max bounds. If the value starts outside of the min/max bounds and is stepped it will update to a value outside of the bounds. Once the value is stepped inside the min/max bounds it will be clamped to this range.
|
307
|
-
|
308
|
-
For example, assume a `SpinButton` with min=5, max=10, value=1 and step=1. Incrementing `value` with the stepper will increase it to 2.
|
309
|
-
|
310
|
-
Any value may be typing into the `<input>` element of `SpinButton`. When typing into the input `SpinButton` enters an intermediate state where changes to the input are not applied to `value`. Instead the user must "commit" their edits to trigger a `value` update. This can be done two ways:
|
311
|
-
|
312
|
-
1. Blur the input field (i.e., tab or click away)
|
313
|
-
2. Use one of `SpinButton`'s hotkeys to modify the value.
|
314
|
-
|
315
|
-
Aside from min/max range clamping behavior described above `SpinButton` does not currently implement any input validation.
|
316
|
-
|
317
|
-
No error states are currently implemented.
|
318
|
-
|
319
|
-
`SpinButton`'s `onChange` callback is invoked every time a change is committed. A change is committed when:
|
320
|
-
|
321
|
-
1. A step button is activated (e.g., clicked with a mouse or activated with a screen reader)
|
322
|
-
2. When a user presses the `Arrow Up`, `Arrow Down`, `Home` or `End` keys while focused on the component.
|
323
|
-
3. When the `blur` event is fired from the `<input>`
|
324
|
-
|
325
|
-
The `onChange` callback is not invoked while a user is focused on the `<input>` and editing the value of the `SpinButton` directly.
|
326
|
-
|
327
|
-
### Component States
|
328
|
-
|
329
|
-
- Rest (no value or valid value, not focused)
|
330
|
-
- Focused
|
331
|
-
- Disabled
|
332
|
-
- Error/Warning (value is invalid in some way). NB: error and validation are not currently supported.
|
333
|
-
|
334
|
-
### Interaction
|
335
|
-
|
336
|
-
#### Keyboard
|
337
|
-
|
338
|
-
- Tab focuses the `<input>` element
|
339
|
-
- Up arrow key increments the value by `step` until `max`, if specified.
|
340
|
-
- Down arrow key decrements the value by `step` until `min`, if specified.
|
341
|
-
- Home key sets the value to `min`, if specified.
|
342
|
-
- End key sets the value to `max`, if specified.
|
343
|
-
- Tab never focuses the increment or decrement buttons as their functionality is fully available via the keyboard
|
344
|
-
|
345
|
-
#### Cursor
|
346
|
-
|
347
|
-
- Clicking on the `<input>` focuses it.
|
348
|
-
- Input supports all device/platform mouse interactions (i.e., text selection)
|
349
|
-
- Clicking the increment button increases the value by `step` until `max`, if specified.
|
350
|
-
- Clicking the decrement button decreases the value by `step` until `min`, if specified.
|
351
|
-
|
352
|
-
#### Touch
|
353
|
-
|
354
|
-
Same as cursor.
|
355
|
-
|
356
|
-
#### Screen Readers
|
357
|
-
|
358
|
-
- `<input>` is focusable and editable using standard device/platform interactions.
|
359
|
-
- increment and decrement buttons are both focusable and usable with standard device/platform interactions.
|
360
|
-
- If formatting is applied to values `aria-valuetext` is applied to the `spinbutton` and read by the screen reader.
|
361
|
-
|
362
|
-
## Accessibility
|
363
|
-
|
364
|
-
The converged `SpinButton` component will not use the native HTML spin button (`input type="number"`) as this control has inconsistent cross-browser behavior and lacks styling options. Rather ARIA will be applied to achieve an accessible component that behaves consistently on all support platforms with robust styling options.
|
365
|
-
|
366
|
-
Only the `<input>` element of `SpinButton` can be focused via the keyboard. The ARIA `spinbutton` design pattern calls for keyboard shortcuts (up/down arrow) to fulfill the value step functionality, making focus for the increment and decrement buttons redundant.
|
367
|
-
|
368
|
-
- [ARIA design pattern: SpinButton](https://www.w3.org/TR/wai-aria-practices/#spinbutton)
|
369
|
-
- [Date Picker Example](https://www.w3.org/TR/wai-aria-practices/examples/spinbutton/datepicker-spinbuttons.html)
|
370
|
-
- [Toolbar (Font Picker) Example](https://www.w3.org/TR/wai-aria-practices/examples/toolbar/toolbar.html)
|
Binary file
|
Binary file
|
Binary file
|