@react-ui-org/react-ui 0.63.0 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/code-reviewer.md +122 -0
- package/.claude/rules/code.md +22 -0
- package/.claude/rules/docs.md +35 -0
- package/.claude/rules/frontend.md +72 -0
- package/.claude/rules/git.md +13 -0
- package/.claude/rules/safety-guards.md +9 -0
- package/.claude/rules/styling.md +32 -0
- package/.claude/rules/testing.md +59 -0
- package/.claude/settings.json +32 -0
- package/.claude/skills/commit/SKILL.md +54 -0
- package/.devcontainer/devcontainer.json +23 -0
- package/.mcp.json +8 -0
- package/CLAUDE.md +82 -0
- package/dist/react-ui.css +4 -4
- package/dist/react-ui.development.css +600 -590
- package/dist/react-ui.development.js +20 -10
- package/dist/react-ui.js +1 -1
- package/docker-compose.base.yml +93 -0
- package/docker-compose.yml.dist +41 -0
- package/opencode.json +10 -0
- package/package.json +3 -2
- package/scripts/auto-start-mkdocs.sh +5 -0
- package/scripts/auto-start-node.sh +33 -0
- package/scripts/mcps/chrome-host/README.md +118 -0
- package/scripts/mcps/chrome-host/cdp_proxy.py +90 -0
- package/scripts/mcps/chrome-host/mcp-entry.sh +33 -0
- package/scripts/mcps/chrome-host/mcp-launch.sh +36 -0
- package/scripts/mcps/chrome-host/mcp-setup.sh +70 -0
- package/scripts/mcps/chrome-host/start-host-chrome.sh +267 -0
- package/scripts/write-lockfile-hash.sh +15 -0
- package/setup.sh +107 -0
- package/src/components/Button/Button.jsx +4 -0
- package/src/components/Button/Button.module.scss +11 -0
- package/src/components/FileInputField/FileInputField.jsx +9 -2
- package/src/components/FormLayout/FormLayoutCustomField.jsx +4 -1
- package/src/components/FormLayout/FormLayoutCustomFieldContext.js +3 -0
- package/src/components/FormLayout/README.md +168 -161
- package/src/components/FormLayout/index.js +1 -0
- package/src/components/Popover/Popover.jsx +1 -0
- package/src/components/Popover/Popover.module.scss +1 -0
- package/src/components/Popover/README.md +29 -0
- package/src/components/Popover/_helpers/cleanPlacementStyle.js +1 -0
- package/src/components/Popover/_theme.scss +1 -0
- package/src/components/SelectField/SelectField.jsx +8 -3
- package/src/components/TextArea/TextArea.jsx +9 -2
- package/src/components/TextField/TextField.jsx +8 -3
- package/src/styles/_utilities.scss +5 -1
- package/src/styles/tools/_collections.scss +34 -22
- package/src/styles/tools/_utilities.scss +4 -2
- package/src/theme.scss +1 -0
- package/.env.playwright +0 -9
- package/.env.playwright.dist +0 -9
|
@@ -14,7 +14,8 @@ And use it:
|
|
|
14
14
|
|
|
15
15
|
```docoff-react-preview
|
|
16
16
|
<FormLayout>
|
|
17
|
-
<TextField label="A
|
|
17
|
+
<TextField label="A text field" />
|
|
18
|
+
<Button label="Submit" />
|
|
18
19
|
</FormLayout>
|
|
19
20
|
```
|
|
20
21
|
|
|
@@ -27,18 +28,14 @@ one after another in a row by default.** The FormLayout component is there to
|
|
|
27
28
|
make building **vertical and horizontal forms** easy. It uses the right tool for
|
|
28
29
|
the job: the [CSS grid layout][grid].
|
|
29
30
|
|
|
30
|
-
- Put **only form field components** from React UI inside the
|
|
31
|
-
make sure they are **direct descendants** of it (React
|
|
32
|
-
supported!). All React UI form components are
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
[
|
|
38
|
-
and [Toggle](/components/Toggle).
|
|
39
|
-
|
|
40
|
-
- Use the [FormLayoutCustomField](#custom-fields) component when you need to
|
|
41
|
-
place any **custom content** inside the FormLayout. This layout helper ensures
|
|
31
|
+
- Put **only form field components or buttons** from React UI inside the
|
|
32
|
+
FormLayout and make sure they are **direct descendants** of it (React
|
|
33
|
+
[fragments][fragments] are supported!). All React UI form components are
|
|
34
|
+
[ready for this use case](#supported-form-fields), no wrapping `<div>`s are
|
|
35
|
+
needed.
|
|
36
|
+
|
|
37
|
+
- To **place any custom content** inside the FormLayout, use the
|
|
38
|
+
[FormLayoutCustomField](#custom-fields) component. This layout helper ensures
|
|
42
39
|
your content is properly spaced and aligned with other FormLayout elements.
|
|
43
40
|
Do **not** try to put any custom HTML or React components directly into
|
|
44
41
|
FormLayout without wrapping it with the FormLayoutCustomField first.
|
|
@@ -48,6 +45,132 @@ for your FormLayout. This prevents FormLayout from unexpectedly growing in
|
|
|
48
45
|
browsers that [don't support][rui-232] [CSS subgrid][subgrid] in cases when
|
|
49
46
|
there are longer validation messages or help texts.
|
|
50
47
|
|
|
48
|
+
## Supported Form Fields
|
|
49
|
+
|
|
50
|
+
The FormLayout supports buttons and all React UI form fields:
|
|
51
|
+
[Button](/components/Button), [CheckboxField](/components/CheckboxField),
|
|
52
|
+
[FileInputField](/components/FileInputField), [Radio](/components/Radio),
|
|
53
|
+
[SelectField](/components/SelectField), [TextArea](/components/TextArea),
|
|
54
|
+
[TextField](/components/TextField), and [Toggle](/components/Toggle).
|
|
55
|
+
|
|
56
|
+
```docoff-react-preview
|
|
57
|
+
React.createElement(() => {
|
|
58
|
+
const [fieldLayout, setFieldLayout] = React.useState('horizontal');
|
|
59
|
+
const [fruit, setFruit] = React.useState('apple');
|
|
60
|
+
const [isDeliveryAddress, setIsDeliveryAddress] = React.useState(true);
|
|
61
|
+
const [receiveNewsletter, setReceiveNewsletter] = React.useState(true);
|
|
62
|
+
const options = [
|
|
63
|
+
{
|
|
64
|
+
label: 'Apple',
|
|
65
|
+
value: 'apple',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
label: 'Banana',
|
|
69
|
+
value: 'banana',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
label: 'Grapefruit',
|
|
73
|
+
value: 'grapefruit',
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
return (
|
|
77
|
+
<div>
|
|
78
|
+
<Toolbar>
|
|
79
|
+
<ToolbarItem>
|
|
80
|
+
<ButtonGroup>
|
|
81
|
+
<Button
|
|
82
|
+
color={fieldLayout === 'horizontal' ? 'selected' : 'secondary'}
|
|
83
|
+
label="Horizontal layout"
|
|
84
|
+
onClick={() => setFieldLayout('horizontal')}
|
|
85
|
+
/>
|
|
86
|
+
<Button
|
|
87
|
+
color={fieldLayout === 'vertical' ? 'selected' : 'secondary'}
|
|
88
|
+
label="Vertical layout"
|
|
89
|
+
onClick={() => setFieldLayout('vertical')}
|
|
90
|
+
/>
|
|
91
|
+
</ButtonGroup>
|
|
92
|
+
</ToolbarItem>
|
|
93
|
+
</Toolbar>
|
|
94
|
+
<FormLayout fieldLayout={fieldLayout} labelWidth="auto">
|
|
95
|
+
<>
|
|
96
|
+
<TextField
|
|
97
|
+
label="First Name"
|
|
98
|
+
/>
|
|
99
|
+
<TextField
|
|
100
|
+
label="Last Name"
|
|
101
|
+
/>
|
|
102
|
+
</>
|
|
103
|
+
<TextField
|
|
104
|
+
helpText="Optional"
|
|
105
|
+
label="Email address"
|
|
106
|
+
type="email"
|
|
107
|
+
/>
|
|
108
|
+
<>
|
|
109
|
+
<TextField
|
|
110
|
+
label="Address"
|
|
111
|
+
placeholder="Address line 1"
|
|
112
|
+
/>
|
|
113
|
+
<TextField
|
|
114
|
+
isLabelVisible={false}
|
|
115
|
+
label="Address 2"
|
|
116
|
+
placeholder="Address line 2"
|
|
117
|
+
/>
|
|
118
|
+
<TextField
|
|
119
|
+
inputSize={6}
|
|
120
|
+
label="ZIP"
|
|
121
|
+
validationState="invalid"
|
|
122
|
+
validationText="ZIP should be 5 to 6 digits long code."
|
|
123
|
+
/>
|
|
124
|
+
<FormLayoutCustomField label="Country">
|
|
125
|
+
<span>Czech Republic</span>
|
|
126
|
+
</FormLayoutCustomField>
|
|
127
|
+
<CheckboxField
|
|
128
|
+
checked={isDeliveryAddress}
|
|
129
|
+
helpText="Uncheck if you wish to deliver to a different address."
|
|
130
|
+
label="This is my delivery address"
|
|
131
|
+
onChange={() => setIsDeliveryAddress(!isDeliveryAddress)}
|
|
132
|
+
/>
|
|
133
|
+
</>
|
|
134
|
+
<SelectField
|
|
135
|
+
label="Your favourite fruit"
|
|
136
|
+
onChange={(e) => setFruit(e.target.value)}
|
|
137
|
+
options={options}
|
|
138
|
+
value={fruit}
|
|
139
|
+
/>
|
|
140
|
+
<TextArea
|
|
141
|
+
fullWidth
|
|
142
|
+
label="Message"
|
|
143
|
+
rows={3}
|
|
144
|
+
/>
|
|
145
|
+
<FileInputField
|
|
146
|
+
id="my-file"
|
|
147
|
+
label="Attachment"
|
|
148
|
+
onFilesChanged={() => {}}
|
|
149
|
+
/>
|
|
150
|
+
<Toggle
|
|
151
|
+
checked={receiveNewsletter}
|
|
152
|
+
helpText="Only once per week!"
|
|
153
|
+
label="Receive weekly newsletter"
|
|
154
|
+
onChange={() => setReceiveNewsletter(!receiveNewsletter)}
|
|
155
|
+
required
|
|
156
|
+
/>
|
|
157
|
+
<Radio
|
|
158
|
+
label="And fruit again!"
|
|
159
|
+
onChange={(e) => setFruit(e.target.value)}
|
|
160
|
+
options={options}
|
|
161
|
+
value={fruit}
|
|
162
|
+
/>
|
|
163
|
+
<InputGroup label="Promo code">
|
|
164
|
+
<TextField label="Code" />
|
|
165
|
+
<Button label="Apply" color="secondary" priority="outline" />
|
|
166
|
+
</InputGroup>
|
|
167
|
+
<Button label="Submit" />
|
|
168
|
+
</FormLayout>
|
|
169
|
+
</div>
|
|
170
|
+
)
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
51
174
|
## Vertical Layout
|
|
52
175
|
|
|
53
176
|
Vertical FormLayout works similar to single-column [Grid](/components/Grid)
|
|
@@ -59,6 +182,7 @@ layout, simply wrap your form fields with the FormLayout component:
|
|
|
59
182
|
<TextField label="A form element" />
|
|
60
183
|
<TextField label="Another form element" />
|
|
61
184
|
<TextField label="Yet another one" />
|
|
185
|
+
<Button label="Submit" />
|
|
62
186
|
</FormLayout>
|
|
63
187
|
```
|
|
64
188
|
|
|
@@ -73,6 +197,7 @@ viewport size onward and it forces the horizontal layout on the fields.
|
|
|
73
197
|
<TextField label="A form element" />
|
|
74
198
|
<TextField label="Another form element" />
|
|
75
199
|
<TextField label="Yet another one" />
|
|
200
|
+
<Button label="Submit" />
|
|
76
201
|
</FormLayout>
|
|
77
202
|
```
|
|
78
203
|
|
|
@@ -194,11 +319,9 @@ the FormLayout component.
|
|
|
194
319
|
|
|
195
320
|
```docoff-react-preview
|
|
196
321
|
<FormLayout fieldLayout="horizontal" labelWidth="auto">
|
|
197
|
-
<TextField label="A form element" />
|
|
198
322
|
<FormLayoutCustomField label="Optional custom field label">
|
|
199
323
|
<docoff-placeholder bordered>Custom field content</docoff-placeholder>
|
|
200
324
|
</FormLayoutCustomField>
|
|
201
|
-
<TextField label="Another form element" />
|
|
202
325
|
</FormLayout>
|
|
203
326
|
```
|
|
204
327
|
|
|
@@ -207,6 +330,29 @@ and its styles may affect contained form fields through CSS cascade, don't
|
|
|
207
330
|
forget to mirror the aforementioned properties to the contained form fields too
|
|
208
331
|
as API options as such are **not** inherited.
|
|
209
332
|
|
|
333
|
+
### Nested Fields Labels
|
|
334
|
+
|
|
335
|
+
When placing box form fields — TextField, TextArea, SelectField, or
|
|
336
|
+
FileInputField — inside a FormLayoutCustomField, their labels are hidden
|
|
337
|
+
automatically.
|
|
338
|
+
|
|
339
|
+
```docoff-react-preview
|
|
340
|
+
<FormLayout fieldLayout="horizontal" labelWidth="auto">
|
|
341
|
+
<FormLayoutCustomField
|
|
342
|
+
innerFieldSize="medium"
|
|
343
|
+
label="Custom field with invisible label"
|
|
344
|
+
>
|
|
345
|
+
<TextField
|
|
346
|
+
label="This field's label is hidden"
|
|
347
|
+
/>
|
|
348
|
+
</FormLayoutCustomField>
|
|
349
|
+
</FormLayout>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
ℹ️ Labels are hidden regardless of `fieldLayout`. In a horizontal FormLayout,
|
|
353
|
+
the nested field's own label would conflict with the FormLayout grid and
|
|
354
|
+
produce incorrect alignment, so it is always hidden for consistency.
|
|
355
|
+
|
|
210
356
|
### Label Alignment
|
|
211
357
|
|
|
212
358
|
If you are in a situation with one or more box form fields inside your
|
|
@@ -218,18 +364,15 @@ this task.
|
|
|
218
364
|
|
|
219
365
|
```docoff-react-preview
|
|
220
366
|
<FormLayout fieldLayout="horizontal" labelWidth="auto">
|
|
221
|
-
<TextField label="A form element" />
|
|
222
367
|
<FormLayoutCustomField
|
|
223
368
|
innerFieldSize="medium"
|
|
224
369
|
label="Custom field label aligned to inner text input"
|
|
225
370
|
>
|
|
226
371
|
<TextField
|
|
227
|
-
isLabelVisible={false}
|
|
228
372
|
label="A form element"
|
|
229
373
|
placeholder="Text field with invisible label"
|
|
230
374
|
/>
|
|
231
375
|
</FormLayoutCustomField>
|
|
232
|
-
<TextField label="Another form element" />
|
|
233
376
|
</FormLayout>
|
|
234
377
|
```
|
|
235
378
|
|
|
@@ -240,14 +383,12 @@ provide labels with optional feedback style.
|
|
|
240
383
|
|
|
241
384
|
```docoff-react-preview
|
|
242
385
|
<FormLayout fieldLayout="horizontal" labelWidth="auto">
|
|
243
|
-
<TextField label="A form element" />
|
|
244
386
|
<FormLayoutCustomField
|
|
245
387
|
label="Custom field label in valid state"
|
|
246
388
|
validationState="valid"
|
|
247
389
|
>
|
|
248
390
|
<docoff-placeholder bordered>Custom field content</docoff-placeholder>
|
|
249
391
|
</FormLayoutCustomField>
|
|
250
|
-
<TextField label="Another form element" />
|
|
251
392
|
</FormLayout>
|
|
252
393
|
```
|
|
253
394
|
|
|
@@ -264,153 +405,19 @@ React.createElement(() => {
|
|
|
264
405
|
const [isChecked, setIsChecked] = React.useState(false);
|
|
265
406
|
return (
|
|
266
407
|
<FormLayout fieldLayout="horizontal" labelWidth="auto">
|
|
267
|
-
<TextField label="A form element" />
|
|
268
408
|
<FormLayoutCustomField
|
|
269
409
|
fullWidth
|
|
270
|
-
label="Custom field label
|
|
271
|
-
labelForId="my-text-field-custom-accessibility
|
|
410
|
+
label="Custom field label associated with a text field"
|
|
411
|
+
labelForId="my-text-field-custom-accessibility"
|
|
272
412
|
innerFieldSize="medium"
|
|
273
413
|
>
|
|
274
|
-
<Toolbar align="middle" dense>
|
|
275
|
-
<ToolbarItem>
|
|
276
|
-
<TextField
|
|
277
|
-
isLabelVisible={false}
|
|
278
|
-
label="A form element"
|
|
279
|
-
placeholder="Text field with invisible label"
|
|
280
|
-
/>
|
|
281
|
-
</ToolbarItem>
|
|
282
|
-
<ToolbarItem>
|
|
283
|
-
<CheckboxField
|
|
284
|
-
checked={isChecked}
|
|
285
|
-
label="Another form field"
|
|
286
|
-
onChange={() => setIsChecked(!isChecked)}
|
|
287
|
-
/>
|
|
288
|
-
</ToolbarItem>
|
|
289
|
-
</Toolbar>
|
|
290
|
-
</FormLayoutCustomField>
|
|
291
|
-
<TextField label="Another form element" />
|
|
292
|
-
</FormLayout>
|
|
293
|
-
)
|
|
294
|
-
});
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
## Full Example
|
|
298
|
-
|
|
299
|
-
This is a demo of all components supported by FormLayout.
|
|
300
|
-
|
|
301
|
-
```docoff-react-preview
|
|
302
|
-
React.createElement(() => {
|
|
303
|
-
const [fieldLayout, setFieldLayout] = React.useState('horizontal');
|
|
304
|
-
const [fruit, setFruit] = React.useState('apple');
|
|
305
|
-
const [isDeliveryAddress, setIsDeliveryAddress] = React.useState(true);
|
|
306
|
-
const [receiveNewsletter, setReceiveNewsletter] = React.useState(true);
|
|
307
|
-
const options = [
|
|
308
|
-
{
|
|
309
|
-
label: 'Apple',
|
|
310
|
-
value: 'apple',
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
label: 'Banana',
|
|
314
|
-
value: 'banana',
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
label: 'Grapefruit',
|
|
318
|
-
value: 'grapefruit',
|
|
319
|
-
},
|
|
320
|
-
];
|
|
321
|
-
return (
|
|
322
|
-
<div>
|
|
323
|
-
<Toolbar>
|
|
324
|
-
<ToolbarItem>
|
|
325
|
-
<ButtonGroup>
|
|
326
|
-
<Button
|
|
327
|
-
color={fieldLayout === 'horizontal' ? 'selected' : 'secondary'}
|
|
328
|
-
label="Horizontal layout"
|
|
329
|
-
onClick={() => setFieldLayout('horizontal')}
|
|
330
|
-
/>
|
|
331
|
-
<Button
|
|
332
|
-
color={fieldLayout === 'vertical' ? 'selected' : 'secondary'}
|
|
333
|
-
label="Vertical layout"
|
|
334
|
-
onClick={() => setFieldLayout('vertical')}
|
|
335
|
-
/>
|
|
336
|
-
</ButtonGroup>
|
|
337
|
-
</ToolbarItem>
|
|
338
|
-
</Toolbar>
|
|
339
|
-
<FormLayout fieldLayout={fieldLayout} labelWidth="auto">
|
|
340
|
-
<>
|
|
341
|
-
<TextField
|
|
342
|
-
label="First Name"
|
|
343
|
-
/>
|
|
344
|
-
<TextField
|
|
345
|
-
label="Last Name"
|
|
346
|
-
/>
|
|
347
|
-
</>
|
|
348
414
|
<TextField
|
|
349
|
-
|
|
350
|
-
label="
|
|
351
|
-
|
|
415
|
+
id="my-text-field-custom-accessibility"
|
|
416
|
+
label="A form element"
|
|
417
|
+
placeholder="Text field with invisible label"
|
|
352
418
|
/>
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
label="Address"
|
|
356
|
-
placeholder="Address line 1"
|
|
357
|
-
/>
|
|
358
|
-
<TextField
|
|
359
|
-
isLabelVisible={false}
|
|
360
|
-
label="Address 2"
|
|
361
|
-
placeholder="Address line 2"
|
|
362
|
-
/>
|
|
363
|
-
<TextField
|
|
364
|
-
inputSize={6}
|
|
365
|
-
label="ZIP"
|
|
366
|
-
validationState="invalid"
|
|
367
|
-
validationText="ZIP should be 5 to 6 digits long code."
|
|
368
|
-
/>
|
|
369
|
-
<FormLayoutCustomField label="Country">
|
|
370
|
-
<span>Czech Republic</span>
|
|
371
|
-
</FormLayoutCustomField>
|
|
372
|
-
<CheckboxField
|
|
373
|
-
checked={isDeliveryAddress}
|
|
374
|
-
helpText="Uncheck if you wish to deliver to a different address."
|
|
375
|
-
label="This is my delivery address"
|
|
376
|
-
onChange={() => setIsDeliveryAddress(!isDeliveryAddress)}
|
|
377
|
-
/>
|
|
378
|
-
</>
|
|
379
|
-
<SelectField
|
|
380
|
-
label="Your favourite fruit"
|
|
381
|
-
onChange={(e) => setFruit(e.target.value)}
|
|
382
|
-
options={options}
|
|
383
|
-
value={fruit}
|
|
384
|
-
/>
|
|
385
|
-
<TextArea
|
|
386
|
-
fullWidth
|
|
387
|
-
label="Message"
|
|
388
|
-
rows={3}
|
|
389
|
-
/>
|
|
390
|
-
<FileInputField
|
|
391
|
-
id="my-file"
|
|
392
|
-
label="Attachment"
|
|
393
|
-
onFilesChanged={() => {}}
|
|
394
|
-
/>
|
|
395
|
-
<Toggle
|
|
396
|
-
checked={receiveNewsletter}
|
|
397
|
-
helpText="Only once per week!"
|
|
398
|
-
label="Receive weekly newsletter"
|
|
399
|
-
onChange={() => setReceiveNewsletter(!receiveNewsletter)}
|
|
400
|
-
required
|
|
401
|
-
/>
|
|
402
|
-
<Radio
|
|
403
|
-
label="And fruit again!"
|
|
404
|
-
onChange={(e) => setFruit(e.target.value)}
|
|
405
|
-
options={options}
|
|
406
|
-
value={fruit}
|
|
407
|
-
/>
|
|
408
|
-
<InputGroup label="Promo code">
|
|
409
|
-
<TextField label="Code" />
|
|
410
|
-
<Button label="Apply" color="secondary" priority="outline" />
|
|
411
|
-
</InputGroup>
|
|
412
|
-
</FormLayout>
|
|
413
|
-
</div>
|
|
419
|
+
</FormLayoutCustomField>
|
|
420
|
+
</FormLayout>
|
|
414
421
|
)
|
|
415
422
|
});
|
|
416
423
|
```
|
|
@@ -105,6 +105,7 @@ Popover.propTypes = {
|
|
|
105
105
|
top: PropTypes.string,
|
|
106
106
|
'transform-origin': PropTypes.string,
|
|
107
107
|
translate: PropTypes.string,
|
|
108
|
+
visibility: PropTypes.string,
|
|
108
109
|
}),
|
|
109
110
|
/**
|
|
110
111
|
* If set, the popover will become controlled, meaning it will be hidden by default and will need a trigger to open.
|
|
@@ -178,10 +178,15 @@ position the popover. The allowed props are:
|
|
|
178
178
|
- `left`
|
|
179
179
|
- `translate`
|
|
180
180
|
- `transform-origin`
|
|
181
|
+
- `visibility`
|
|
181
182
|
|
|
182
183
|
⚠️ [`inset`][mdn-inset] is a shorthand for `top right bottom left`, not for
|
|
183
184
|
`inset-*` properties.
|
|
184
185
|
|
|
186
|
+
ℹ️ `visibility` can be used to hide the Popover before its initial position is
|
|
187
|
+
computed, preventing a flash of the Popover in a wrong position. Set it to
|
|
188
|
+
`hidden` initially, then remove or update it once the position is ready.
|
|
189
|
+
|
|
185
190
|
As opposed to `top right bottom left` and the `inset` shorthand, `inset-*`
|
|
186
191
|
properties are writing-direction aware.
|
|
187
192
|
|
|
@@ -307,6 +312,29 @@ React.createElement(() => {
|
|
|
307
312
|
});
|
|
308
313
|
```
|
|
309
314
|
|
|
315
|
+
## z-index
|
|
316
|
+
|
|
317
|
+
By default, the Popover's `z-index` is `auto`, which means it participates in
|
|
318
|
+
the stacking context of its nearest positioned ancestor. This works well in most
|
|
319
|
+
cases, but can cause the Popover to appear behind other positioned elements such
|
|
320
|
+
as sticky headers, fixed toolbars, or modals.
|
|
321
|
+
|
|
322
|
+
When that happens, set `--rui-Popover__z-index` to a numeric value high enough
|
|
323
|
+
to place the Popover above the conflicting layer. The override can be applied
|
|
324
|
+
globally or scoped to a specific context:
|
|
325
|
+
|
|
326
|
+
```css
|
|
327
|
+
/* Global override */
|
|
328
|
+
:root {
|
|
329
|
+
--rui-Popover__z-index: 1000;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* Scoped override */
|
|
333
|
+
.my-context {
|
|
334
|
+
--rui-Popover__z-index: 1000;
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
310
338
|
## Controlled Popover
|
|
311
339
|
|
|
312
340
|
Popover API can be used to control visibility of Popover component. You need to
|
|
@@ -379,6 +407,7 @@ which enables [Advanced Positioning](#advanced-positioning).
|
|
|
379
407
|
| `--rui-Popover__color` | Text color |
|
|
380
408
|
| `--rui-Popover__background-color` | Background color |
|
|
381
409
|
| `--rui-Popover__box-shadow` | Popover box shadow |
|
|
410
|
+
| `--rui-Popover__z-index` | Popover z-index (default: `auto`) |
|
|
382
411
|
|
|
383
412
|
[div-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
|
|
384
413
|
[Floating UI]: https://floating-ui.com/docs/react-dom
|
|
@@ -6,7 +6,10 @@ import { transferProps } from '../../helpers/transferProps';
|
|
|
6
6
|
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
|
7
7
|
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
|
8
8
|
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
FormLayoutContext,
|
|
11
|
+
FormLayoutCustomFieldContext,
|
|
12
|
+
} from '../FormLayout';
|
|
10
13
|
import { InputGroupContext } from '../InputGroup/InputGroupContext';
|
|
11
14
|
import { Option } from './_components/Option';
|
|
12
15
|
import styles from './SelectField.module.scss';
|
|
@@ -31,6 +34,7 @@ export const SelectField = React.forwardRef((props, ref) => {
|
|
|
31
34
|
} = props;
|
|
32
35
|
|
|
33
36
|
const formLayoutContext = useContext(FormLayoutContext);
|
|
37
|
+
const formLayoutCustomFieldContext = useContext(FormLayoutCustomFieldContext);
|
|
34
38
|
const inputGroupContext = useContext(InputGroupContext);
|
|
35
39
|
|
|
36
40
|
return (
|
|
@@ -58,7 +62,7 @@ export const SelectField = React.forwardRef((props, ref) => {
|
|
|
58
62
|
<div
|
|
59
63
|
className={classNames(
|
|
60
64
|
styles.label,
|
|
61
|
-
(!isLabelVisible || inputGroupContext) && styles.isLabelHidden,
|
|
65
|
+
(!isLabelVisible || inputGroupContext || formLayoutCustomFieldContext) && styles.isLabelHidden,
|
|
62
66
|
)}
|
|
63
67
|
id={id && `${id}__labelText`}
|
|
64
68
|
>
|
|
@@ -181,7 +185,8 @@ SelectField.propTypes = {
|
|
|
181
185
|
* If `false`, the label will be visually hidden (but remains accessible by assistive
|
|
182
186
|
* technologies).
|
|
183
187
|
*
|
|
184
|
-
* Automatically set to `false` when the component is rendered within `InputGroup`
|
|
188
|
+
* Automatically set to `false` when the component is rendered within `InputGroup` or
|
|
189
|
+
* `FormLayoutCustomField` component.
|
|
185
190
|
*/
|
|
186
191
|
isLabelVisible: PropTypes.bool,
|
|
187
192
|
/**
|
|
@@ -6,7 +6,10 @@ import { transferProps } from '../../helpers/transferProps';
|
|
|
6
6
|
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
|
7
7
|
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
|
8
8
|
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
FormLayoutContext,
|
|
11
|
+
FormLayoutCustomFieldContext,
|
|
12
|
+
} from '../FormLayout';
|
|
10
13
|
import styles from './TextArea.module.scss';
|
|
11
14
|
|
|
12
15
|
export const TextArea = React.forwardRef((props, ref) => {
|
|
@@ -27,6 +30,7 @@ export const TextArea = React.forwardRef((props, ref) => {
|
|
|
27
30
|
} = props;
|
|
28
31
|
|
|
29
32
|
const context = useContext(FormLayoutContext);
|
|
33
|
+
const formLayoutCustomFieldContext = useContext(FormLayoutCustomFieldContext);
|
|
30
34
|
|
|
31
35
|
return (
|
|
32
36
|
<label
|
|
@@ -49,7 +53,7 @@ export const TextArea = React.forwardRef((props, ref) => {
|
|
|
49
53
|
<div
|
|
50
54
|
className={classNames(
|
|
51
55
|
styles.label,
|
|
52
|
-
!isLabelVisible && styles.isLabelHidden,
|
|
56
|
+
(!isLabelVisible || formLayoutCustomFieldContext) && styles.isLabelHidden,
|
|
53
57
|
)}
|
|
54
58
|
id={id && `${id}__labelText`}
|
|
55
59
|
>
|
|
@@ -127,6 +131,9 @@ TextArea.propTypes = {
|
|
|
127
131
|
/**
|
|
128
132
|
* If `false`, the label will be visually hidden (but remains accessible by assistive
|
|
129
133
|
* technologies).
|
|
134
|
+
*
|
|
135
|
+
* Automatically set to `false` when the component is rendered within `FormLayoutCustomField`
|
|
136
|
+
* component.
|
|
130
137
|
*/
|
|
131
138
|
isLabelVisible: PropTypes.bool,
|
|
132
139
|
/**
|
|
@@ -6,7 +6,10 @@ import { transferProps } from '../../helpers/transferProps';
|
|
|
6
6
|
import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
|
|
7
7
|
import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName';
|
|
8
8
|
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
FormLayoutContext,
|
|
11
|
+
FormLayoutCustomFieldContext,
|
|
12
|
+
} from '../FormLayout';
|
|
10
13
|
import { InputGroupContext } from '../InputGroup/InputGroupContext';
|
|
11
14
|
import styles from './TextField.module.scss';
|
|
12
15
|
|
|
@@ -31,6 +34,7 @@ export const TextField = React.forwardRef((props, ref) => {
|
|
|
31
34
|
...restProps
|
|
32
35
|
} = props;
|
|
33
36
|
const formLayoutContext = useContext(FormLayoutContext);
|
|
37
|
+
const formLayoutCustomFieldContext = useContext(FormLayoutCustomFieldContext);
|
|
34
38
|
const inputGroupContext = useContext(InputGroupContext);
|
|
35
39
|
const hasSmallInput = (inputSize !== undefined) && (inputSize <= SMALL_INPUT_SIZE);
|
|
36
40
|
|
|
@@ -62,7 +66,7 @@ export const TextField = React.forwardRef((props, ref) => {
|
|
|
62
66
|
<div
|
|
63
67
|
className={classNames(
|
|
64
68
|
styles.label,
|
|
65
|
-
(!isLabelVisible || inputGroupContext) && styles.isLabelHidden,
|
|
69
|
+
(!isLabelVisible || inputGroupContext || formLayoutCustomFieldContext) && styles.isLabelHidden,
|
|
66
70
|
)}
|
|
67
71
|
id={id && `${id}__labelText`}
|
|
68
72
|
>
|
|
@@ -153,7 +157,8 @@ TextField.propTypes = {
|
|
|
153
157
|
* If `false`, the label will be visually hidden (but remains accessible by assistive
|
|
154
158
|
* technologies).
|
|
155
159
|
*
|
|
156
|
-
* Automatically set to `false` when the component is rendered within `InputGroup`
|
|
160
|
+
* Automatically set to `false` when the component is rendered within `InputGroup` or
|
|
161
|
+
* `FormLayoutCustomField` component.
|
|
157
162
|
*/
|
|
158
163
|
isLabelVisible: PropTypes.bool,
|
|
159
164
|
/**
|
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
@each $breakpoint in map.keys(breakpoint-settings.$values) {
|
|
9
9
|
@include breakpoint.up($breakpoint) {
|
|
10
|
-
$infix:
|
|
10
|
+
$infix: "";
|
|
11
|
+
|
|
12
|
+
@if map.get(breakpoint-settings.$values, $breakpoint) != 0 {
|
|
13
|
+
$infix: "-#{$breakpoint}";
|
|
14
|
+
}
|
|
11
15
|
|
|
12
16
|
@each $key, $utility in utility-settings.$map {
|
|
13
17
|
@if meta.type-of($utility) == "map" and (map.get($utility, responsive) == true or $infix == "") {
|