@fluentui/react-field 0.0.0-nightly-20221007-1237.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. package/CHANGELOG.json +362 -0
  2. package/CHANGELOG.md +96 -0
  3. package/LICENSE +15 -0
  4. package/README.md +5 -0
  5. package/Spec.md +354 -0
  6. package/dist/index.d.ts +243 -0
  7. package/lib/CheckboxField.js +2 -0
  8. package/lib/CheckboxField.js.map +1 -0
  9. package/lib/ComboboxField.js +2 -0
  10. package/lib/ComboboxField.js.map +1 -0
  11. package/lib/Field.js +2 -0
  12. package/lib/Field.js.map +1 -0
  13. package/lib/InputField.js +2 -0
  14. package/lib/InputField.js.map +1 -0
  15. package/lib/ProgressField.js +2 -0
  16. package/lib/ProgressField.js.map +1 -0
  17. package/lib/RadioGroupField.js +2 -0
  18. package/lib/RadioGroupField.js.map +1 -0
  19. package/lib/SelectField.js +2 -0
  20. package/lib/SelectField.js.map +1 -0
  21. package/lib/SliderField.js +2 -0
  22. package/lib/SliderField.js.map +1 -0
  23. package/lib/SpinButtonField.js +2 -0
  24. package/lib/SpinButtonField.js.map +1 -0
  25. package/lib/SwitchField.js +2 -0
  26. package/lib/SwitchField.js.map +1 -0
  27. package/lib/TextareaField.js +2 -0
  28. package/lib/TextareaField.js.map +1 -0
  29. package/lib/components/CheckboxField/CheckboxField.js +32 -0
  30. package/lib/components/CheckboxField/CheckboxField.js.map +1 -0
  31. package/lib/components/CheckboxField/index.js +2 -0
  32. package/lib/components/CheckboxField/index.js.map +1 -0
  33. package/lib/components/ComboboxField/ComboboxField.js +14 -0
  34. package/lib/components/ComboboxField/ComboboxField.js.map +1 -0
  35. package/lib/components/ComboboxField/index.js +2 -0
  36. package/lib/components/ComboboxField/index.js.map +1 -0
  37. package/lib/components/Field/Field.types.js +2 -0
  38. package/lib/components/Field/Field.types.js.map +1 -0
  39. package/lib/components/Field/SlotComponent.types.js +2 -0
  40. package/lib/components/Field/SlotComponent.types.js.map +1 -0
  41. package/lib/components/Field/index.js +5 -0
  42. package/lib/components/Field/index.js.map +1 -0
  43. package/lib/components/Field/renderField.js +20 -0
  44. package/lib/components/Field/renderField.js.map +1 -0
  45. package/lib/components/Field/useField.js +139 -0
  46. package/lib/components/Field/useField.js.map +1 -0
  47. package/lib/components/Field/useFieldStyles.js +121 -0
  48. package/lib/components/Field/useFieldStyles.js.map +1 -0
  49. package/lib/components/InputField/InputField.js +14 -0
  50. package/lib/components/InputField/InputField.js.map +1 -0
  51. package/lib/components/InputField/index.js +2 -0
  52. package/lib/components/InputField/index.js.map +1 -0
  53. package/lib/components/ProgressField/ProgressField.js +15 -0
  54. package/lib/components/ProgressField/ProgressField.js.map +1 -0
  55. package/lib/components/ProgressField/index.js +2 -0
  56. package/lib/components/ProgressField/index.js.map +1 -0
  57. package/lib/components/RadioGroupField/RadioGroupField.js +15 -0
  58. package/lib/components/RadioGroupField/RadioGroupField.js.map +1 -0
  59. package/lib/components/RadioGroupField/index.js +2 -0
  60. package/lib/components/RadioGroupField/index.js.map +1 -0
  61. package/lib/components/SelectField/SelectField.js +14 -0
  62. package/lib/components/SelectField/SelectField.js.map +1 -0
  63. package/lib/components/SelectField/index.js +2 -0
  64. package/lib/components/SelectField/index.js.map +1 -0
  65. package/lib/components/SliderField/SliderField.js +14 -0
  66. package/lib/components/SliderField/SliderField.js.map +1 -0
  67. package/lib/components/SliderField/index.js +2 -0
  68. package/lib/components/SliderField/index.js.map +1 -0
  69. package/lib/components/SpinButtonField/SpinButtonField.js +14 -0
  70. package/lib/components/SpinButtonField/SpinButtonField.js.map +1 -0
  71. package/lib/components/SpinButtonField/index.js +2 -0
  72. package/lib/components/SpinButtonField/index.js.map +1 -0
  73. package/lib/components/SwitchField/SwitchField.js +14 -0
  74. package/lib/components/SwitchField/SwitchField.js.map +1 -0
  75. package/lib/components/SwitchField/index.js +2 -0
  76. package/lib/components/SwitchField/index.js.map +1 -0
  77. package/lib/components/TextareaField/TextareaField.js +14 -0
  78. package/lib/components/TextareaField/TextareaField.js.map +1 -0
  79. package/lib/components/TextareaField/index.js +2 -0
  80. package/lib/components/TextareaField/index.js.map +1 -0
  81. package/lib/index.js +12 -0
  82. package/lib/index.js.map +1 -0
  83. package/lib-commonjs/CheckboxField.js +10 -0
  84. package/lib-commonjs/CheckboxField.js.map +1 -0
  85. package/lib-commonjs/ComboboxField.js +10 -0
  86. package/lib-commonjs/ComboboxField.js.map +1 -0
  87. package/lib-commonjs/Field.js +10 -0
  88. package/lib-commonjs/Field.js.map +1 -0
  89. package/lib-commonjs/InputField.js +10 -0
  90. package/lib-commonjs/InputField.js.map +1 -0
  91. package/lib-commonjs/ProgressField.js +10 -0
  92. package/lib-commonjs/ProgressField.js.map +1 -0
  93. package/lib-commonjs/RadioGroupField.js +10 -0
  94. package/lib-commonjs/RadioGroupField.js.map +1 -0
  95. package/lib-commonjs/SelectField.js +10 -0
  96. package/lib-commonjs/SelectField.js.map +1 -0
  97. package/lib-commonjs/SliderField.js +10 -0
  98. package/lib-commonjs/SliderField.js.map +1 -0
  99. package/lib-commonjs/SpinButtonField.js +10 -0
  100. package/lib-commonjs/SpinButtonField.js.map +1 -0
  101. package/lib-commonjs/SwitchField.js +10 -0
  102. package/lib-commonjs/SwitchField.js.map +1 -0
  103. package/lib-commonjs/TextareaField.js +10 -0
  104. package/lib-commonjs/TextareaField.js.map +1 -0
  105. package/lib-commonjs/components/CheckboxField/CheckboxField.js +42 -0
  106. package/lib-commonjs/components/CheckboxField/CheckboxField.js.map +1 -0
  107. package/lib-commonjs/components/CheckboxField/index.js +10 -0
  108. package/lib-commonjs/components/CheckboxField/index.js.map +1 -0
  109. package/lib-commonjs/components/ComboboxField/ComboboxField.js +24 -0
  110. package/lib-commonjs/components/ComboboxField/ComboboxField.js.map +1 -0
  111. package/lib-commonjs/components/ComboboxField/index.js +10 -0
  112. package/lib-commonjs/components/ComboboxField/index.js.map +1 -0
  113. package/lib-commonjs/components/Field/Field.types.js +6 -0
  114. package/lib-commonjs/components/Field/Field.types.js.map +1 -0
  115. package/lib-commonjs/components/Field/SlotComponent.types.js +6 -0
  116. package/lib-commonjs/components/Field/SlotComponent.types.js.map +1 -0
  117. package/lib-commonjs/components/Field/index.js +16 -0
  118. package/lib-commonjs/components/Field/index.js.map +1 -0
  119. package/lib-commonjs/components/Field/renderField.js +31 -0
  120. package/lib-commonjs/components/Field/renderField.js.map +1 -0
  121. package/lib-commonjs/components/Field/useField.js +154 -0
  122. package/lib-commonjs/components/Field/useField.js.map +1 -0
  123. package/lib-commonjs/components/Field/useFieldStyles.js +134 -0
  124. package/lib-commonjs/components/Field/useFieldStyles.js.map +1 -0
  125. package/lib-commonjs/components/InputField/InputField.js +24 -0
  126. package/lib-commonjs/components/InputField/InputField.js.map +1 -0
  127. package/lib-commonjs/components/InputField/index.js +10 -0
  128. package/lib-commonjs/components/InputField/index.js.map +1 -0
  129. package/lib-commonjs/components/ProgressField/ProgressField.js +25 -0
  130. package/lib-commonjs/components/ProgressField/ProgressField.js.map +1 -0
  131. package/lib-commonjs/components/ProgressField/index.js +10 -0
  132. package/lib-commonjs/components/ProgressField/index.js.map +1 -0
  133. package/lib-commonjs/components/RadioGroupField/RadioGroupField.js +25 -0
  134. package/lib-commonjs/components/RadioGroupField/RadioGroupField.js.map +1 -0
  135. package/lib-commonjs/components/RadioGroupField/index.js +10 -0
  136. package/lib-commonjs/components/RadioGroupField/index.js.map +1 -0
  137. package/lib-commonjs/components/SelectField/SelectField.js +24 -0
  138. package/lib-commonjs/components/SelectField/SelectField.js.map +1 -0
  139. package/lib-commonjs/components/SelectField/index.js +10 -0
  140. package/lib-commonjs/components/SelectField/index.js.map +1 -0
  141. package/lib-commonjs/components/SliderField/SliderField.js +24 -0
  142. package/lib-commonjs/components/SliderField/SliderField.js.map +1 -0
  143. package/lib-commonjs/components/SliderField/index.js +10 -0
  144. package/lib-commonjs/components/SliderField/index.js.map +1 -0
  145. package/lib-commonjs/components/SpinButtonField/SpinButtonField.js +24 -0
  146. package/lib-commonjs/components/SpinButtonField/SpinButtonField.js.map +1 -0
  147. package/lib-commonjs/components/SpinButtonField/index.js +10 -0
  148. package/lib-commonjs/components/SpinButtonField/index.js.map +1 -0
  149. package/lib-commonjs/components/SwitchField/SwitchField.js +24 -0
  150. package/lib-commonjs/components/SwitchField/SwitchField.js.map +1 -0
  151. package/lib-commonjs/components/SwitchField/index.js +10 -0
  152. package/lib-commonjs/components/SwitchField/index.js.map +1 -0
  153. package/lib-commonjs/components/TextareaField/TextareaField.js +24 -0
  154. package/lib-commonjs/components/TextareaField/TextareaField.js.map +1 -0
  155. package/lib-commonjs/components/TextareaField/index.js +10 -0
  156. package/lib-commonjs/components/TextareaField/index.js.map +1 -0
  157. package/lib-commonjs/index.js +184 -0
  158. package/lib-commonjs/index.js.map +1 -0
  159. package/package.json +59 -0
package/Spec.md ADDED
@@ -0,0 +1,354 @@
1
+ # @fluentui/react-field Spec
2
+
3
+ ## Background
4
+
5
+ Field adds a label, validation text, and hint text to form input components. The existing input components (such as `Input` and `Combobox`) are wrapped to create field versions of them (such as `InputField` and `ComboboxField`).
6
+
7
+ Epic issue tracking implementation: https://github.com/microsoft/fluentui/issues/19627
8
+
9
+ ## Prior Art
10
+
11
+ Existing libraries tend to take one of the following approaches to field.
12
+
13
+ 1. Include support for label, error text, etc. in the base input component. Libraries using this approach include:
14
+ - **FluentUI v8** - [`TextField`](https://developer.microsoft.com/en-us/fluentui#/controls/web/textfield), [`Dropdown`](https://developer.microsoft.com/en-us/fluentui#/controls/web/dropdown), [`ChoiceGroup`](https://developer.microsoft.com/en-us/fluentui#/controls/web/choicegroup), etc.
15
+ - **Spectrum** - [`TextField`](https://react-spectrum.adobe.com/react-spectrum/TextField.html), [`Slider`](https://react-spectrum.adobe.com/react-spectrum/Slider.html), [`RadioGroup`](https://react-spectrum.adobe.com/react-spectrum/RadioGroup.html), etc.
16
+ 2. Provide a set of components that are manually constructed into a field. This requires manually hooking up the components using props like `htmlFor` and `aria-describedby`. Libraries using this approach include:
17
+ - **FluentUI v0** - [`FormField`](https://fluentsite.z22.web.core.windows.net/0.64.0/components/form/props#form-field), [`FormLabel`](https://fluentsite.z22.web.core.windows.net/0.64.0/components/form/props#form-label), [`FormMessage`](https://fluentsite.z22.web.core.windows.net/0.64.0/components/form/props#form-message)
18
+ - **Ant** - [`Form.Item`](https://ant.design/components/form/#Form.Item) (uses context to do some of the hooking up between the item and the field component).
19
+ 3. Provide base components without a label or descriptive text, and then Field versions of those controls. Libraries using this approach include:
20
+ - **FluentUI v0** - [`Input`](https://fluentsite.z22.web.core.windows.net/0.64.0/components/input/props) and [`FormInput`](https://fluentsite.z22.web.core.windows.net/0.64.0/components/form/props#form-input), for example.
21
+ - **Evergreen UI** - [`TextInput`](https://evergreen.segment.com/components/text-input) and [`TextInputField`](https://evergreen.segment.com/components/text-input#textinputfield), for example.
22
+
23
+ The Field implementation in this spec follows pattern (3). There are Field versions of all components that can be used as form inputs. There are several reasons, including:
24
+
25
+ - **Accessibility**: By combining a base component with the field props into a single component, all of the accessibility props like `htmlFor` and `aria-describedby` are set correctly for "free".
26
+ - **Simplicity**: All props related to the component (such as `label`, `id`, `validationState="error"`, etc.) are on the same component, rather than split between multiple components (like separate `Field` and `Input` components).
27
+ - **Consistency**: All of the Field components share a common set of props for the label, validationState, hint, etc.
28
+ - **Bundle size**: When the label and other field functionality is not needed, it is still possible to use the base components without pulling in unnecessary dependencies (like `Label` and the field styling).
29
+
30
+ ## Sample Code
31
+
32
+ Each input component has a field version (such as `InputField`, `ComboboxField`, etc.) that includes the features of Field added to that component.
33
+
34
+ ```jsx
35
+ <>
36
+ <InputField
37
+ // Field-specific props
38
+ label="This is the field label"
39
+ orientation="horizontal"
40
+ validationState="error"
41
+ validationMessage="This is error text"
42
+ // All props and slots of the underlying Input component are supported
43
+ required
44
+ size="small"
45
+ contentBefore="$"
46
+ contentAfter=".00"
47
+ />
48
+ <RadioGroupField label="Radio group field">
49
+ <Radio value="one" label="Option one" />
50
+ <Radio value="two" label="Option two" />
51
+ <Radio value="three" label="Option three" />
52
+ </RadioGroupField>
53
+ <ComboboxField label="Combobox field" validationState="success" validationMessage="Success text">
54
+ <Option value="one">Option one</Option>
55
+ <Option value="two">Option two</Option>
56
+ <Option value="three">Option three</Option>
57
+ </ComboboxField>
58
+ <SliderField label="Slider field" validationState="warning" validationMessage="Warning text" />
59
+ <SpinButtonField label="Spin button field" hint="Hint text" />
60
+ </>
61
+ ```
62
+
63
+ These field versions of the components use a common set of Field hooks, and can be defined using very little code.
64
+
65
+ ```ts
66
+ export type InputFieldProps = FieldProps<typeof Input>;
67
+
68
+ export const InputField: ForwardRefComponent<InputFieldProps> = React.forwardRef((props, ref) => {
69
+ const state = useField_unstable(props, ref, Input);
70
+ useFieldStyles_unstable(state);
71
+ return renderField_unstable(state);
72
+ });
73
+
74
+ InputField.displayName = 'InputField';
75
+ ```
76
+
77
+ ## Components
78
+
79
+ The following field components will be defined. If more form components are added in the future, they should also include a Field version.
80
+
81
+ - `CheckboxField`
82
+ - `ComboboxField`
83
+ - `DropdownField`
84
+ - `InputField`
85
+ - `RadioGroupField`
86
+ - `SelectField`
87
+ - `SliderField`
88
+ - `SpinButtonField`
89
+ - `SwitchField`
90
+ - `TextareaField`
91
+
92
+ ## Variants
93
+
94
+ - **Orientation**: The `orientation` prop affects the layout of the label and field component:
95
+ - `'vertical'` (default) - label is above the field component
96
+ - `'horizontal'` - label is to the left of the field component, and is 33% the width of the field (this allows multiple stacked fields to all align their labels)
97
+ - **Validation state**: The `validationState` prop affects the icon and color used by the `validationMessage`:
98
+ - `'error'` - Red x icon, red text color
99
+ - `'warning'` - Yellow exclamation icon, neutral color text
100
+ - `'success'` - Green check icon, neutral color text
101
+ - `undefined` (default): No validation message icon, neutral color text
102
+ - **Error**: Some control types (like `Input` and `Combobox`) have a prop that makes the border red. This prop will be set `validationState="error"`.
103
+
104
+ Field also forwards some props from the wrapped component to the label as well:
105
+
106
+ - **Size**: If the wrapped component supports a `size` prop, it will also be applied to the field's label.
107
+ - **Required**: If set, the Label will get a required asterisk: `*`
108
+
109
+ ## API
110
+
111
+ ### FieldComponent
112
+
113
+ The `FieldComponent` type defines the minimum set of props that the wrapped component must support. This is used for the generic types as the requirement for the type parameter: `FieldProps<T extends FieldComponent>`
114
+
115
+ ```ts
116
+ /**
117
+ * The minimum requirement for a component used by Field.
118
+ *
119
+ * Note: the use of VoidFunctionComponent means that component is not *required* to have a children prop,
120
+ * but it is still allowed to have a children prop.
121
+ */
122
+ export type FieldComponent = React.VoidFunctionComponent<
123
+ Pick<
124
+ React.HTMLAttributes<HTMLElement>,
125
+ 'id' | 'className' | 'style' | 'aria-labelledby' | 'aria-describedby' | 'aria-invalid' | 'aria-errormessage'
126
+ >
127
+ >;
128
+ ```
129
+
130
+ ### Slots
131
+
132
+ _Note: TypeScript crashes if the `Slot` type is used with a template type parameter. The `SlotComponent` type is a simplified version of that type, which only supports `React.ComponentType`/`React.VoidFunctionComponent`._
133
+
134
+ ```ts
135
+ export type FieldSlots<T extends FieldComponent> = {
136
+ root: NonNullable<Slot<'div'>>;
137
+
138
+ /**
139
+ * The underlying component wrapped by this field.
140
+ *
141
+ * This is the PRIMARY slot: all intrinsic HTML properties will be applied to this slot,
142
+ * except `className` and `style`, which remain on the root slot.
143
+ */
144
+ control: SlotComponent<T>;
145
+
146
+ /**
147
+ * The label associated with the field.
148
+ */
149
+ label?: Slot<typeof Label>;
150
+
151
+ /**
152
+ * A message about the validation state. The appearance of the `validationMessage` depends on `validationState`.
153
+ */
154
+ validationMessage?: Slot<'span'>;
155
+
156
+ /**
157
+ * The icon associated with the `validationMessage`. If the `validationState` prop is set, this will default to an
158
+ * icon corresponding to that state.
159
+ *
160
+ * This will only be displayed if `validationMessage` is set.
161
+ */
162
+ validationMessageIcon?: Slot<'span'>;
163
+
164
+ /**
165
+ * Additional hint text below the field.
166
+ */
167
+ hint?: Slot<'span'>;
168
+ };
169
+ ```
170
+
171
+ ### Props
172
+
173
+ ```ts
174
+ export type FieldProps<T extends FieldComponent> = ComponentProps<Partial<FieldSlots<T>>, 'control'> & {
175
+ /**
176
+ * The orientation of the label relative to the field component.
177
+ * This only affects the label, and not the validationMessage or hint (which always appear below the field component).
178
+ *
179
+ * @default vertical
180
+ */
181
+ orientation?: 'vertical' | 'horizontal';
182
+
183
+ /**
184
+ * The `validationState` affects the color of the `validationMessage`, the `validationMessageIcon`, and for some
185
+ * field components, an `validationState="error"` causes the border to become red.
186
+ *
187
+ * @default undefined
188
+ */
189
+ validationState?: 'error' | 'warning' | 'success';
190
+ };
191
+ ```
192
+
193
+ Field also reads some props from the underlying component. These are not part of `FieldProps` because they are not added to the components that don't support them. However, they are accepted by `useField`:
194
+
195
+ ```ts
196
+ /**
197
+ * Props that are supported by Field, but not required to be supported by the component that implements field.
198
+ */
199
+ export type OptionalFieldComponentProps = {
200
+ /**
201
+ * Whether the field label should be marked as required.
202
+ */
203
+ required?: boolean;
204
+
205
+ /**
206
+ * Size of the field label.
207
+ *
208
+ * Number sizes will be ignored, but are allowed because the HTML <input> element has a `size` prop of type `number`.
209
+ */
210
+ size?: 'small' | 'medium' | 'large' | number;
211
+ };
212
+ ```
213
+
214
+ ### State
215
+
216
+ ```ts
217
+ export type FieldState<T extends FieldComponent> = ComponentState<Required<FieldSlots<T>>> &
218
+ Pick<FieldProps<T>, 'orientation' | 'validationState'> & {
219
+ classNames: SlotClassNames<FieldSlots<T>>;
220
+ };
221
+ ```
222
+
223
+ ### Label for Checkbox and Switch
224
+
225
+ The Checkbox and Switch components already have a `label` prop, which conflicts with the Field's `label`.
226
+
227
+ #### `CheckboxField`
228
+
229
+ - The `label` prop will go to the Checkbox and NOT the Field
230
+ - New `fieldLabel` prop for the label of the Field
231
+
232
+ #### `SwitchField`
233
+
234
+ - The `label` prop will go to the Field and NOT the Switch
235
+ - The Switch's `labelPosition` prop is therefore not supported, and is omitted from SwitchField.
236
+
237
+ ## Structure
238
+
239
+ ### Public API
240
+
241
+ ```jsx
242
+ <InputField
243
+ label="This is the field label"
244
+ orientation="horizontal"
245
+ validationState="error"
246
+ validationMessage="This is a validation message"
247
+ hint="This is a hint message"
248
+ />
249
+ ```
250
+
251
+ (similar API for other Field components)
252
+
253
+ ### Slot structure
254
+
255
+ ```jsx
256
+ <slots.root>
257
+ <slots.label {...slotProps.label} />
258
+ <slots.control {...slotProps.control} />
259
+ <slots.validationMessage {...slotProps.validationMessage}>
260
+ <slots.validationMessageIcon {...slotProps.validationMessageIcon} />
261
+ {slotProps.validationMessage.children}
262
+ </slots.validationMessage>
263
+ <slots.hint {...slotProps.hint} />
264
+ </slots.root>
265
+ ```
266
+
267
+ ### DOM structure
268
+
269
+ ```html
270
+ <div className="fui-Field">
271
+ <label className="fui-Field__label fui-Label">This is the field label</label>
272
+ <!-- wrapped field component goes here -->
273
+ <span className="fui-Field__validationMessage">
274
+ <span className="fui-Field__validationMessageIcon"><svg>...</svg></span>
275
+ This is a validation message
276
+ </span>
277
+ <span className="fui-Field__hint">This is a hint message</span>
278
+ </div>
279
+ ```
280
+
281
+ ## Migration
282
+
283
+ ### Migration from v8
284
+
285
+ Migration from v8 will require picking between the normal and `Field` version of an input control, depending on whether the field-specific features are required: (`label`, `validationState="error"`, `validationMessage`, `hint`)
286
+
287
+ See individual input components for more detailed migration guides.
288
+
289
+ | v8 Control | v9 Base control | v9 Field control | Notes |
290
+ | ------------- | --------------------- | ------------------------------- | -------------------------------------------------------------------------------------------- |
291
+ | `Checkbox` | `Checkbox` | `CheckboxField` | Only use `CheckboxField` if an error message is needed, or if required for layout in a form. |
292
+ | `ChoiceGroup` | `RadioGroup` | `RadioGroupField` | |
293
+ | `ComboBox` | `Combobox` | `ComboboxField` | `errorMessage="..."` is replaced by `validationState="error" validationMessage="..."` |
294
+ | `Dropdown` | `Dropdown` | `DropdownField` | `errorMessage="..."` is replaced by `validationState="error" validationMessage="..."` |
295
+ | `Slider` | `Slider` | `SliderField` | |
296
+ | `SpinButton` | `SpinButton` | `SpinButtonField` | |
297
+ | `TextField` | `Input` OR `Textarea` | `InputField` OR `TextareaField` | `errorMessage="..."` is replaced by `validationState="error" validationMessage="..."` |
298
+ | `Toggle` | `Switch` | `SwitchField` | |
299
+
300
+ ### Migration from v0
301
+
302
+ Many components in v0 have `Form___` versions (such as `FormInput`). Those are replaced by the `___Field` equivalent. See the underlying component's migration guides for more detailed migration information.
303
+
304
+ Component mapping:
305
+
306
+ - `FormButton` => Not supported
307
+ - `FormCheckbox` => `CheckboxField` OR `SwitchField`
308
+ - `FormDatepicker` => _(Not yet implemented)_
309
+ - `FormDropdown` => `DropdownField`
310
+ - `FormField` => Not supported
311
+ - `FormFieldCustom` => Not supported
312
+ - `FormLabel` => The `label` prop of the field component
313
+ - `FormMessage` => Either the `validationMessage` or `hint` prop of the field component
314
+ - `FormRadioGroup` => `RadioGroupField`
315
+ - `FormSlider` => `SliderField`
316
+ - `FormTextArea` => `TextareaField`
317
+
318
+ The following props are common to each of the `Form___` components:
319
+
320
+ - `label` => `label`
321
+ - `message` => either `validationMessage` or `hint`
322
+ - `errorMessage` => `validationMessage` with `validationState="error"`
323
+
324
+ ## Behaviors
325
+
326
+ ### Form validation
327
+
328
+ Field has no logic to perform input validation. It is expected that the validation will be done externally (possibly using a third party form validation library like Formik).
329
+
330
+ ### Interaction
331
+
332
+ The Field itself is not interactive. The wrapped component has the same interactions as it does outside of a field.
333
+
334
+ ## Accessibility
335
+
336
+ - **ARIA pattern**
337
+ - Field itself does not implement a defined ARIA pattern. It has no role applied to the root element.
338
+ - **Attributes**
339
+ - The following are applied on the wrapped component:
340
+ - `aria-labelledby={label.id}`, if the label is present.
341
+ - `aria-describedby` is set to one of:
342
+ - `aria-describedby={validationMessage.id}`, if validationMessage is present, and _only if_ `validationState !== 'error'`
343
+ - `aria-describedby={hint.id}`, if hint is present
344
+ - `aria-describedby={validationMessage.id + ' ' + hint.id}`, if both conditions above apply
345
+ - `aria-errormessage={validationMessage.id}`, if validationMessage is present, and _only if_ `validationState === 'error'`
346
+ - `aria-invalid={true}`, _only if_ `validationState === 'error'`
347
+ - On the `label` slot:
348
+ - `htmlFor={control.id}` - the wrapped component's `id` (an ID is generated if not supplied via props).
349
+ - **Live regions** (state change announcements)
350
+ - TBD: Need to determine if the validation message should be an aria live region.
351
+ - **UI parts appearing on hover or focus**
352
+ - None.
353
+ - **Focus behavior**
354
+ - No special focus behavior: no focus trapping or programmatic focus moving.
@@ -0,0 +1,243 @@
1
+ /// <reference types="react" />
2
+
3
+ import { Checkbox } from '@fluentui/react-checkbox';
4
+ import type { CheckboxProps } from '@fluentui/react-checkbox';
5
+ import { Combobox } from '@fluentui/react-combobox';
6
+ import type { ComponentProps } from '@fluentui/react-utilities';
7
+ import type { ComponentState } from '@fluentui/react-utilities';
8
+ import { ForwardRefComponent } from '@fluentui/react-utilities';
9
+ import { Input } from '@fluentui/react-input';
10
+ import { Label } from '@fluentui/react-label';
11
+ import { Progress } from '@fluentui/react-progress';
12
+ import { RadioGroup } from '@fluentui/react-radio';
13
+ import * as React_2 from 'react';
14
+ import { Select } from '@fluentui/react-select';
15
+ import { Slider } from '@fluentui/react-slider';
16
+ import type { Slot } from '@fluentui/react-utilities';
17
+ import { SlotClassNames } from '@fluentui/react-utilities';
18
+ import type { SlotRenderFunction } from '@fluentui/react-utilities';
19
+ import type { SlotShorthandValue } from '@fluentui/react-utilities';
20
+ import { SpinButton } from '@fluentui/react-spinbutton';
21
+ import { Switch } from '@fluentui/react-switch';
22
+ import { Textarea } from '@fluentui/react-textarea';
23
+
24
+ export declare const CheckboxField: ForwardRefComponent<CheckboxFieldProps>;
25
+
26
+ export declare const checkboxFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
27
+
28
+ export declare type CheckboxFieldProps = Omit<FieldProps<typeof Checkbox>, 'label'> & {
29
+ /**
30
+ * The Checkbox's label.
31
+ */
32
+ label?: CheckboxProps['label'];
33
+ /**
34
+ * The label for the CheckboxField, which appears above or before the Checkbox, depending on the `orientation` prop.
35
+ * It is recommended to only set the `label` prop, and not `fieldLabel`.
36
+ */
37
+ fieldLabel?: FieldProps<typeof Checkbox>['label'];
38
+ };
39
+
40
+ export declare const ComboboxField: ForwardRefComponent<ComboboxFieldProps>;
41
+
42
+ export declare const comboboxFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
43
+
44
+ export declare type ComboboxFieldProps = FieldProps<typeof Combobox>;
45
+
46
+ /**
47
+ * The minimum requirement for a component used by Field.
48
+ *
49
+ * Note: the use of VoidFunctionComponent means that component is not *required* to have a children prop,
50
+ * but it is still allowed to have a children prop.
51
+ */
52
+ declare type FieldComponent = React_2.VoidFunctionComponent<Pick<React_2.HTMLAttributes<HTMLElement>, 'id' | 'className' | 'style' | 'aria-labelledby' | 'aria-describedby' | 'aria-invalid' | 'aria-errormessage'>>;
53
+
54
+ /**
55
+ * Configuration parameters for a Field class, passed to useField_unstable
56
+ */
57
+ export declare type FieldConfig<T extends FieldComponent> = {
58
+ /**
59
+ * The underlying input component that this field is wrapping.
60
+ */
61
+ component: T;
62
+ /**
63
+ * Class names for this component, created by `getFieldClassNames`.
64
+ */
65
+ classNames: SlotClassNames<FieldSlots<T>>;
66
+ /**
67
+ * How the label be connected to the control.
68
+ * * htmlFor - Set the Label's htmlFor prop to the component's ID (and generate an ID if not provided).
69
+ * This is the preferred method for components that use the underlying <input> tag.
70
+ * * aria-labelledby - Set the component's aria-labelledby prop to the Label's ID. Use this for components
71
+ * that are not directly <input> elements (such as RadioGroup).
72
+ *
73
+ * @default htmlFor
74
+ */
75
+ labelConnection?: 'htmlFor' | 'aria-labelledby';
76
+ };
77
+
78
+ /**
79
+ * Field Props
80
+ */
81
+ export declare type FieldProps<T extends FieldComponent> = ComponentProps<Partial<FieldSlots<T>>, 'control'> & {
82
+ /**
83
+ * The orientation of the label relative to the field component.
84
+ * This only affects the label, and not the validationMessage or hint (which always appear below the field component).
85
+ *
86
+ * @default vertical
87
+ */
88
+ orientation?: 'vertical' | 'horizontal';
89
+ /**
90
+ * The `validationState` affects the color of the `validationMessage`, the `validationMessageIcon`, and for some
91
+ * field components, an `validationState="error"` causes the border to become red.
92
+ *
93
+ * @default undefined
94
+ */
95
+ validationState?: 'error' | 'warning' | 'success';
96
+ };
97
+
98
+ /**
99
+ * FieldProps plus extra optional props that are supported by useField_unstable, but not required to be part of the
100
+ * API of every Field component.
101
+ *
102
+ * This allows Field to forward the required and size props to the label if the underlying component supports them,
103
+ * but doesn't add them to the public API of fields that don't support them.
104
+ */
105
+ declare type FieldPropsWithOptionalComponentProps<T extends FieldComponent> = FieldProps<T> & {
106
+ /**
107
+ * Whether the field label should be marked as required.
108
+ */
109
+ required?: boolean;
110
+ /**
111
+ * Size of the field label.
112
+ *
113
+ * Number sizes will be ignored, but are allowed because the HTML `<input>` element has a prop `size?: number`.
114
+ */
115
+ size?: 'small' | 'medium' | 'large' | number;
116
+ };
117
+
118
+ /**
119
+ * Slots added by Field
120
+ */
121
+ export declare type FieldSlots<T extends FieldComponent> = {
122
+ root: NonNullable<Slot<'div'>>;
123
+ /**
124
+ * The underlying component wrapped by this field.
125
+ */
126
+ control: SlotComponent<T>;
127
+ /**
128
+ * The label associated with the field.
129
+ */
130
+ label?: Slot<typeof Label>;
131
+ /**
132
+ * A message about the validation state. The appearance of the `validationMessage` depends on `validationState`.
133
+ */
134
+ validationMessage?: Slot<'span'>;
135
+ /**
136
+ * The icon associated with the `validationMessage`. If the `validationState` prop is set, this will default to an
137
+ * icon corresponding to that state.
138
+ *
139
+ * This will only be displayed if `validationMessage` is set.
140
+ */
141
+ validationMessageIcon?: Slot<'span'>;
142
+ /**
143
+ * Additional hint text below the field.
144
+ */
145
+ hint?: Slot<'span'>;
146
+ };
147
+
148
+ /**
149
+ * State used in rendering Field
150
+ */
151
+ export declare type FieldState<T extends FieldComponent> = ComponentState<Required<FieldSlots<T>>> & Pick<FieldProps<T>, 'orientation' | 'validationState'> & {
152
+ classNames: SlotClassNames<FieldSlots<T>>;
153
+ };
154
+
155
+ export declare const getFieldClassNames: (name: string) => SlotClassNames<FieldSlots<FieldComponent>>;
156
+
157
+ export declare const InputField: ForwardRefComponent<InputFieldProps>;
158
+
159
+ export declare const inputFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
160
+
161
+ export declare type InputFieldProps = FieldProps<typeof Input>;
162
+
163
+ export declare const ProgressField: ForwardRefComponent<ProgressFieldProps>;
164
+
165
+ export declare const progressFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
166
+
167
+ export declare type ProgressFieldProps = FieldProps<typeof Progress>;
168
+
169
+ export declare const RadioGroupField: ForwardRefComponent<RadioGroupFieldProps>;
170
+
171
+ export declare const radioGroupFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
172
+
173
+ export declare type RadioGroupFieldProps = FieldProps<typeof RadioGroup>;
174
+
175
+ /**
176
+ * Render the final JSX of Field
177
+ */
178
+ export declare const renderField_unstable: <T extends FieldComponent>(state: FieldState<T>) => JSX.Element;
179
+
180
+ export declare const SelectField: ForwardRefComponent<SelectFieldProps>;
181
+
182
+ export declare const selectFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
183
+
184
+ export declare type SelectFieldProps = FieldProps<typeof Select>;
185
+
186
+ export declare const SliderField: ForwardRefComponent<SliderFieldProps>;
187
+
188
+ export declare const sliderFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
189
+
190
+ export declare type SliderFieldProps = FieldProps<typeof Slider>;
191
+
192
+ declare type SlotComponent<Type extends React_2.ComponentType | React_2.VoidFunctionComponent> = WithSlotShorthandValue<Type extends React_2.ComponentType<infer Props> ? WithSlotRenderFunction<Props extends {
193
+ children?: unknown;
194
+ } ? Props : Props & {
195
+ children?: never;
196
+ }> : never>;
197
+
198
+ export declare const SpinButtonField: ForwardRefComponent<SpinButtonFieldProps>;
199
+
200
+ export declare const spinButtonFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
201
+
202
+ export declare type SpinButtonFieldProps = FieldProps<typeof SpinButton>;
203
+
204
+ export declare const SwitchField: ForwardRefComponent<SwitchFieldProps>;
205
+
206
+ export declare const switchFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
207
+
208
+ export declare type SwitchFieldProps = Omit<FieldProps<typeof Switch>, 'labelPosition'>;
209
+
210
+ export declare const TextareaField: ForwardRefComponent<TextareaFieldProps>;
211
+
212
+ export declare const textareaFieldClassNames: SlotClassNames<FieldSlots<FieldComponent>>;
213
+
214
+ export declare type TextareaFieldProps = FieldProps<typeof Textarea>;
215
+
216
+ /**
217
+ * Create the state required to render Field.
218
+ *
219
+ * The returned state can be modified with hooks such as useFieldStyles_unstable,
220
+ * before being passed to renderField_unstable.
221
+ *
222
+ * @param props - Props passed to this field
223
+ * @param ref - Ref to the control slot (primary slot)
224
+ * @param params - Configuration parameters for this Field
225
+ */
226
+ export declare const useField_unstable: <T extends FieldComponent>(props: FieldPropsWithOptionalComponentProps<T>, ref: React_2.Ref<HTMLElement>, params: FieldConfig<T>) => FieldState<T>;
227
+
228
+ /**
229
+ * Apply styling to the Field slots based on the state
230
+ */
231
+ export declare const useFieldStyles_unstable: <T extends FieldComponent>(state: FieldState<T>) => void;
232
+
233
+ declare type WithSlotRenderFunction<Props extends {
234
+ children?: unknown;
235
+ }> = Props & {
236
+ children?: Props['children'] | SlotRenderFunction<Props>;
237
+ };
238
+
239
+ declare type WithSlotShorthandValue<Props extends {
240
+ children?: unknown;
241
+ }> = Props | Extract<SlotShorthandValue, Props['children']>;
242
+
243
+ export { }
@@ -0,0 +1,2 @@
1
+ export * from './components/CheckboxField/index';
2
+ //# sourceMappingURL=CheckboxField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckboxField.js","sourceRoot":"","sources":["../src/CheckboxField.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC","sourcesContent":["export * from './components/CheckboxField/index';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './components/ComboboxField/index';
2
+ //# sourceMappingURL=ComboboxField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ComboboxField.js","sourceRoot":"","sources":["../src/ComboboxField.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC","sourcesContent":["export * from './components/ComboboxField/index';\n"]}
package/lib/Field.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './components/Field/index';
2
+ //# sourceMappingURL=Field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Field.js","sourceRoot":"","sources":["../src/Field.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC","sourcesContent":["export * from './components/Field/index';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './components/InputField/index';
2
+ //# sourceMappingURL=InputField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InputField.js","sourceRoot":"","sources":["../src/InputField.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC","sourcesContent":["export * from './components/InputField/index';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './components/ProgressField/index';
2
+ //# sourceMappingURL=ProgressField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressField.js","sourceRoot":"","sources":["../src/ProgressField.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC","sourcesContent":["export * from './components/ProgressField/index';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './components/RadioGroupField/index';
2
+ //# sourceMappingURL=RadioGroupField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroupField.js","sourceRoot":"","sources":["../src/RadioGroupField.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAC","sourcesContent":["export * from './components/RadioGroupField/index';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './components/SelectField/index';
2
+ //# sourceMappingURL=SelectField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectField.js","sourceRoot":"","sources":["../src/SelectField.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC","sourcesContent":["export * from './components/SelectField/index';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './components/SliderField/index';
2
+ //# sourceMappingURL=SliderField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SliderField.js","sourceRoot":"","sources":["../src/SliderField.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC","sourcesContent":["export * from './components/SliderField/index';\n"]}
@@ -0,0 +1,2 @@
1
+ export * from './components/SpinButtonField/index';
2
+ //# sourceMappingURL=SpinButtonField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpinButtonField.js","sourceRoot":"","sources":["../src/SpinButtonField.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAC","sourcesContent":["export * from './components/SpinButtonField/index';\n"]}