Skip to content

Commit a02fe15

Browse files
jluyaudevongovett
andauthored
Conditionally render field label only if label is provided (adobe#6833)
* do not render field label if no children (string) provided * add label-less story for testing * add more examples to form story * add story with form with labeled and non-labeled components * hide value label when label is hidden for meter and progress bar Will need warning in eventual docs that this is not accessible unless the value is displayed visually externally * Improve labeling in example --------- Co-authored-by: Devon Govett <[email protected]>
1 parent 665ba22 commit a02fe15

File tree

4 files changed

+167
-5
lines changed

4 files changed

+167
-5
lines changed

packages/@react-spectrum/s2/src/Field.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ function FieldLabel(props: FieldLabelProps, ref: DOMRef<HTMLLabelElement>) {
6363
labelProps.id = fallbackLabelPropsId;
6464
}
6565

66+
if (!props.children) {
67+
return null;
68+
}
69+
6670
return (
6771
<div
6872
className={style({

packages/@react-spectrum/s2/src/Meter.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ function Meter(props: MeterProps, ref: DOMRef<HTMLDivElement>) {
125125
}, styles)}>
126126
{({percentage, valueText}) => (
127127
<>
128-
<FieldLabel size={size} labelAlign="start" labelPosition="top" staticColor={staticColor}>{label}</FieldLabel>
129-
<span className={valueStyles({size, labelAlign: 'end', staticColor})}>{valueText}</span>
128+
{label && <FieldLabel size={size} labelAlign="start" labelPosition="top" staticColor={staticColor}>{label}</FieldLabel>}
129+
{label && <span className={valueStyles({size, labelAlign: 'end', staticColor})}>{valueText}</span>}
130130
<div className={trackStyles({staticColor, size})}>
131131
<div className={fillStyles({staticColor, variant})} style={{width: percentage + '%'}} />
132132
</div>

packages/@react-spectrum/s2/src/ProgressBar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ function ProgressBar(props: ProgressBarProps, ref: DOMRef<HTMLDivElement>) {
127127
className={UNSAFE_className + wrapper({...props, size}, props.styles)}>
128128
{({percentage, valueText}) => (
129129
<>
130-
<FieldLabel size={size} labelAlign="start" labelPosition="top" staticColor={staticColor}>{label}</FieldLabel>
131-
<span className={valueStyles({size, labelAlign: 'end', staticColor})}>{valueText}</span>
130+
{label && <FieldLabel size={size} labelAlign="start" labelPosition="top" staticColor={staticColor}>{label}</FieldLabel>}
131+
{label && <span className={valueStyles({size, labelAlign: 'end', staticColor})}>{valueText}</span>}
132132
<div className={trackStyles({...props})}>
133133
<div
134134
className={mergeStyles(fill({...props, staticColor}), (isIndeterminate ? indeterminateAnimation : null))}

packages/@react-spectrum/s2/stories/Form.stories.tsx

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,43 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {Button, Checkbox, CheckboxGroup, Form, Radio, RadioGroup, RangeSlider, SearchField, Slider, Switch, TextArea, TextField} from '../src';
13+
import {
14+
ActionButton,
15+
Button,
16+
Checkbox,
17+
CheckboxGroup,
18+
ColorField,
19+
ColorSlider,
20+
ComboBox,
21+
ComboBoxItem,
22+
Content,
23+
ContextualHelp,
24+
Divider,
25+
Form,
26+
Heading,
27+
Meter,
28+
NumberField,
29+
Picker,
30+
PickerItem,
31+
ProgressBar,
32+
Radio,
33+
RadioGroup,
34+
RangeSlider,
35+
SearchField,
36+
Slider,
37+
Switch,
38+
Tag,
39+
TagGroup,
40+
TextArea,
41+
TextField,
42+
ToggleButton
43+
} from '../src';
1444
import {categorizeArgTypes} from './utils';
1545
import type {Meta} from '@storybook/react';
46+
import SortDown from '../s2wf-icons/S2_Icon_SortDown_20_N.svg';
47+
import SortUp from '../s2wf-icons/S2_Icon_SortUp_20_N.svg';
1648
import {style} from '../style/spectrum-theme' with {type: 'macro'};
49+
import {useState} from 'react';
1750

1851
const meta: Meta<typeof Form> = {
1952
component: Form,
@@ -54,3 +87,128 @@ export const Example = (args: any) => (
5487
<Button type="submit" variant="primary" styles={style({gridColumnStart: 'field', width: 'fit'})}>Submit</Button>
5588
</Form>
5689
);
90+
91+
export const MixedForm = (args: any) => (
92+
<Form {...args}>
93+
<TextField label="First Name" name="firstName" />
94+
<TextField label="Last Name" name="firstName" />
95+
<TextField label="Email" name="email" type="email" description="Enter an email" />
96+
<CheckboxGroup aria-label="Favorite sports">
97+
<Checkbox value="soccer">Soccer</Checkbox>
98+
<Checkbox value="baseball">Baseball</Checkbox>
99+
<Checkbox value="basketball">Basketball</Checkbox>
100+
</CheckboxGroup>
101+
<RadioGroup aria-label="Favorite pet">
102+
<Radio value="cat">Cat</Radio>
103+
<Radio value="dog">Dog</Radio>
104+
<Radio value="plant" isDisabled>Plant</Radio>
105+
</RadioGroup>
106+
<SearchField label="Search" name="search" />
107+
</Form>
108+
);
109+
110+
MixedForm.parameters = {
111+
docs: {
112+
disable: true
113+
}
114+
};
115+
116+
117+
export const CustomLabelsExample = (args: any) => {
118+
const [isSortAscending, setIsSortAscending] = useState(true);
119+
return (
120+
<Form {...args}>
121+
<div role="group" aria-labelledby="sortOrder" className={style({display: 'flex', alignItems: 'center', gap: 8, font: 'ui'})}>
122+
<span id="sortOrder">Sort order</span>
123+
<ActionButton aria-label="Sort direction" onPress={() => setIsSortAscending(!isSortAscending)}>
124+
{
125+
isSortAscending ? <SortUp /> : <SortDown />
126+
}
127+
</ActionButton>
128+
<Picker aria-label="Sort by" styles={style({width: 208})}>
129+
<PickerItem id="name">Name</PickerItem>
130+
<PickerItem id="created">Created</PickerItem>
131+
</Picker>
132+
</div>
133+
<div role="group" aria-labelledby="filterTerms" className={style({display: 'flex', alignItems: 'center', gap: 8, font: 'ui'})}>
134+
<span id="filterTerms">Filter terms</span>
135+
<TagGroup aria-label="Keywords" styles={style({minWidth: 208})}>
136+
<Tag>keyword 1</Tag>
137+
<Tag>keyword 2</Tag>
138+
</TagGroup>
139+
</div>
140+
<Divider size="S" />
141+
<div role="group" aria-labelledby="colorLabel" className={style({display: 'flex', alignItems: 'center', gap: 8, font: 'ui'})}>
142+
<span id="colorLabel">Color settings</span>
143+
<ToggleButton>
144+
Enable color
145+
</ToggleButton>
146+
<ColorField aria-label="Fill color" styles={style({width: 144})} />
147+
<ColorSlider channel="alpha" defaultValue="#000" />
148+
</div>
149+
<Divider size="S" />
150+
<div role="group" aria-labelledby="searchLabel" className={style({display: 'flex', alignItems: 'center', gap: 8, font: 'ui'})}>
151+
<span id="searchLabel">Search</span>
152+
<ToggleButton>
153+
Enable search
154+
</ToggleButton>
155+
<TextField aria-label="Query" styles={style({width: 144})} />
156+
<ComboBox aria-label="Search terms" styles={style({width: 144})}>
157+
<ComboBoxItem>search term 1</ComboBoxItem>
158+
<ComboBoxItem>search term 2</ComboBoxItem>
159+
</ComboBox>
160+
<NumberField aria-label="Number of results" defaultValue={50} styles={style({width: 96})} />
161+
</div>
162+
<div role="group" aria-labelledby="searchParameters" className={style({display: 'flex', alignItems: 'center', gap: 16, font: 'ui'})}>
163+
<span id="searchParameters">Search parameters</span>
164+
<RadioGroup aria-label="Search range" orientation="horizontal" styles={style({width: 208})}>
165+
<Radio value="text">Text</Radio>
166+
<Radio value="images">Images</Radio>
167+
<Radio value="video">Video</Radio>
168+
</RadioGroup>
169+
<CheckboxGroup aria-label="Content display" orientation="horizontal" styles={style({width: 256})}>
170+
<Checkbox value="summary">Summary</Checkbox>
171+
<Checkbox value="date">Date</Checkbox>
172+
<Checkbox value="author">Author</Checkbox>
173+
</CheckboxGroup>
174+
</div>
175+
<Divider size="S" />
176+
<div role="group" aria-label="Progress" className={style({display: 'flex', alignItems: 'center', gap: 16, font: 'ui'})}>
177+
<span>28% complete</span>
178+
<ProgressBar aria-label="Percent complete" value={28} styles={style({width: 144})} />
179+
<span>44% confidence</span>
180+
<Meter aria-label="Search confidence" variant="positive" value={44} styles={style({width: 144})} />
181+
</div>
182+
<Divider size="S" />
183+
<div role="group" aria-labelledby="sliders" className={style({font: 'ui'})}>
184+
<div id="sliders">Sliders (with and without label)</div>
185+
<Slider
186+
aria-label="Days to search"
187+
label="With label"
188+
labelPosition="side"
189+
contextualHelp={
190+
<ContextualHelp>
191+
<Heading>Help</Heading>
192+
<Content>Help content</Content>
193+
</ContextualHelp>
194+
} />
195+
<Slider
196+
aria-label="Days to search"
197+
labelPosition="side"
198+
contextualHelp={
199+
<ContextualHelp>
200+
<Heading>Help</Heading>
201+
<Content>Help content</Content>
202+
</ContextualHelp>
203+
} />
204+
</div>
205+
<Button type="submit" variant="primary" styles={style({gridColumnStart: 'field', width: 'fit'})}>Submit</Button>
206+
</Form>
207+
);
208+
};
209+
210+
CustomLabelsExample.parameters = {
211+
docs: {
212+
disable: true
213+
}
214+
};

0 commit comments

Comments
 (0)