Skip to content

Commit d8d2127

Browse files
authored
docs(textfield,textarea): migrating docs to storybook (#3204)
Migrating the textfield and textarea documentation to the Storybook.
1 parent b84b93e commit d8d2127

File tree

6 files changed

+575
-49
lines changed

6 files changed

+575
-49
lines changed

components/textfield/stories/template.js

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Template as FieldLabel } from "@spectrum-css/fieldlabel/stories/template.js";
2+
import { Template as HelpText } from "@spectrum-css/helptext/stories/template.js";
23
import { Template as Icon } from "@spectrum-css/icon/stories/template.js";
3-
import { getRandomId } from "@spectrum-css/preview/decorators";
4+
import { Container, getRandomId } from "@spectrum-css/preview/decorators";
45
import { Template as ProgressCircle } from "@spectrum-css/progresscircle/stories/template.js";
56
import { html } from "lit";
67
import { classMap } from "lit/directives/class-map.js";
@@ -72,11 +73,13 @@ export const Template = ({
7273
displayLabel = false,
7374
labelPosition = "top",
7475
labelText,
76+
characterCount,
7577
iconName,
7678
iconSet,
7779
pattern,
7880
placeholder,
7981
name,
82+
helpText = "",
8083
id = getRandomId("textfield"),
8184
value = "",
8285
type = "text",
@@ -134,6 +137,8 @@ export const Template = ({
134137
size,
135138
label: labelText,
136139
}, context))}
140+
${when(typeof characterCount !== "undefined", () => html`
141+
<span class="${rootClass}-characterCount">${characterCount}</span>`)}
137142
${when(iconName, () => Icon({
138143
size,
139144
iconName,
@@ -183,6 +188,90 @@ export const Template = ({
183188
size: "s",
184189
customClasses: customProgressCircleClasses,
185190
}, context))}
191+
${when(helpText, () =>
192+
HelpText({
193+
text: helpText,
194+
variant: isInvalid ? "negative" : "neutral",
195+
size,
196+
hideIcon: true,
197+
isDisabled
198+
}, context ))}
186199
</div>
187200
`;
188201
};
202+
203+
export const HelpTextOptions = (args, context) => Container({
204+
direction: "column",
205+
withBorder: false,
206+
withHeading: false,
207+
content: html`
208+
${Container({
209+
withBorder: false,
210+
heading: "Description",
211+
content: Template({...args, isRequired: true, labelText: "Username", value: "lisawilson24", helpText: "Username must be at least 8 characters."}, context),
212+
})}
213+
${Container({
214+
withBorder: false,
215+
heading: "Error message",
216+
content: Template({...args, isRequired: true, labelText: "Email address", value: "[email protected]", helpText: "Enter your email address", isInvalid: true }, context),
217+
})}
218+
`
219+
});
220+
221+
export const TextFieldOptions = (args, context) => Container({
222+
direction: "row",
223+
withBorder: false,
224+
wrapperStyles: {
225+
rowGap: "12px",
226+
},
227+
content: html`
228+
${Container({
229+
withBorder: false,
230+
containerStyles: {
231+
"gap": "8px",
232+
},
233+
heading: "Default",
234+
content: Template({...args, context})
235+
})}
236+
${Container({
237+
withBorder: false,
238+
containerStyles: {
239+
"gap": "8px",
240+
},
241+
heading: "Invalid",
242+
content: Template({...args, isInvalid: true}, context)
243+
})}
244+
${Container({
245+
withBorder: false,
246+
containerStyles: {
247+
"gap": "8px",
248+
},
249+
heading: "Focused",
250+
content: Template({...args, isFocused: true}, context)
251+
})}
252+
${Container({
253+
withBorder: false,
254+
containerStyles: {
255+
"gap": "8px",
256+
},
257+
heading: "Invalid, focused",
258+
content: Template({...args, isInvalid: true, isFocused: true}, context)
259+
})}
260+
${Container({
261+
withBorder: false,
262+
containerStyles: {
263+
"gap": "8px",
264+
},
265+
heading: "Keyboard-focused",
266+
content: Template({...args, isKeyboardFocused: true}, context)
267+
})}
268+
${Container({
269+
withBorder: false,
270+
containerStyles: {
271+
"gap": "8px",
272+
},
273+
heading: "Invalid, keyboard-focused",
274+
content: Template({...args, isInvalid: true, isKeyboardFocused: true}, context)
275+
})}
276+
`
277+
});
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { Sizes } from "@spectrum-css/preview/decorators";
2+
import { disableDefaultModes } from "@spectrum-css/preview/modes";
3+
import metadata from "../metadata/metadata.json";
4+
import packageJson from "../package.json";
5+
import { HelpTextOptionsTextArea, Template, TextAreaOptions } from "./textarea.template.js";
6+
import { TextAreaGroup } from "./textarea.test.js";
7+
import { default as Textfield } from "./textfield.stories.js";
8+
9+
/**
10+
* A text area is multi-line text field using the `<textarea>` element that lets a user input a longer amount of text than a standard text field. It can include all of the standard validation options supported by the text field component.
11+
*/
12+
13+
export default {
14+
title: "Text area",
15+
component: "TextArea",
16+
argTypes: {
17+
...Textfield.argTypes
18+
},
19+
args: {
20+
...Textfield.args,
21+
labelText: "Comments"
22+
},
23+
parameters: {
24+
packageJson,
25+
metadata,
26+
}
27+
};
28+
29+
export const Default = TextAreaGroup.bind({});
30+
Default.args = {};
31+
Default.tags = ["!autodocs"];
32+
33+
// ********* DOCS ONLY ********* //
34+
35+
export const Standard = TextAreaOptions.bind({});
36+
Standard.tags = ["!dev"];
37+
Standard.storyName = "Default";
38+
Standard.parameters = {
39+
chromatic: { disableSnapshot: true }
40+
};
41+
42+
export const CharacterCount = Template.bind({});
43+
CharacterCount.tags = ["!dev"];
44+
CharacterCount.args = {
45+
hasCharacterCount: true,
46+
characterCount: 50,
47+
value: "Duis mollit ut laboris est labore sunt ipsum. Proident nostrud in ea reprehenderit proident nostrud. Anim ut est anim ex amet."
48+
};
49+
CharacterCount.parameters = {
50+
chromatic: { disableSnapshot: true }
51+
};
52+
53+
/**
54+
* A text area in a disabled state shows that an input field exists, but is not available in that circumstance. This can be used to maintain layout continuity and communicate that a field may become available later.
55+
*/
56+
export const Disabled = Template.bind({});
57+
Disabled.tags = ["!dev"];
58+
Disabled.args = {
59+
isDisabled: true
60+
};
61+
Disabled.parameters = {
62+
chromatic: { disableSnapshot: true }
63+
};
64+
65+
/**
66+
* A text area can have [help text](/docs/components-help-text--docs) below the field to give extra context or instruction about what a user should input in the field. The help text area has two options: a description and an error message. The description communicates a hint or helpful information, such as specific requirements for correctly filling out the field. The error message communicates an error for when the field requirements aren’t met, prompting a user to adjust what they had originally input.
67+
*
68+
* Instead of placeholder text, use the help text description to convey requirements or to show any formatting examples that would help user comprehension. Putting instructions for how to complete an input, requirements, or any other essential information into placeholder text is not accessible.
69+
*/
70+
export const HelpText = HelpTextOptionsTextArea.bind({});
71+
HelpText.tags = ["!dev"];
72+
HelpText.parameters = {
73+
chromatic: { disableSnapshot: true }
74+
};
75+
76+
export const Quiet = TextAreaOptions.bind({});
77+
Quiet.tags = ["!dev"];
78+
Quiet.args = {
79+
isQuiet: true,
80+
};
81+
Quiet.parameters = {
82+
chromatic: { disableSnapshot: true }
83+
};
84+
85+
/**
86+
* Text area has a read-only option for when content in the disabled state still needs to be shown. This allows for content to be copied, but not interacted with or changed.
87+
*/
88+
export const Readonly = Template.bind({});
89+
Readonly.tags = ["!dev"];
90+
Readonly.args = {
91+
isReadOnly: true,
92+
value: "Adipisicing dolor quis ad non ad ipsum irure ullamco."
93+
};
94+
Readonly.parameters = {
95+
chromatic: { disableSnapshot: true }
96+
};
97+
Readonly.storyName = "Read-only";
98+
99+
/**
100+
* Side labels are most useful when vertical space is limited.
101+
*/
102+
export const SideLabel = Template.bind({});
103+
SideLabel.tags = ["!dev"];
104+
SideLabel.args = {
105+
labelPosition: "side",
106+
value: "Qui nulla cupidatat do ex laborum ipsum et culpa reprehenderit dolore.",
107+
displayCounter: true,
108+
characterCount: 50,
109+
helpText: "Example help text. Lorem ipsum dolor sit amet."
110+
};
111+
SideLabel.parameters = {
112+
chromatic: { disableSnapshot: true }
113+
};
114+
115+
116+
/**
117+
* Text area can display a validation icon when the text entry is expected to conform to a specific format (e.g., email address, credit card number, password creation requirements, etc.). The icon appears as soon as a user types a valid entry in the field.
118+
*/
119+
export const Validation = Template.bind({});
120+
Validation.tags = ["!dev"];
121+
Validation.args = {
122+
isValid: true
123+
};
124+
Validation.parameters = {
125+
chromatic: { disableSnapshot: true }
126+
};
127+
Validation.storyName = "Validation icon";
128+
129+
130+
export const Sizing = (args, context) => Sizes({
131+
Template: Template,
132+
withHeading: false,
133+
withBorder: false,
134+
...args,
135+
}, context);
136+
Sizing.args = {
137+
helpText: "Example help text. Lorem ipsum dolor sit amet.",
138+
hasCharacterCount: true
139+
};
140+
Sizing.tags = ["!dev"];
141+
Sizing.parameters = {
142+
chromatic: { disableSnapshot: true }
143+
};
144+
145+
// ********* VRT ONLY ********* //
146+
// @todo should this show text field and text area in the same snapshot?
147+
export const WithForcedColors = TextAreaGroup.bind({});
148+
WithForcedColors.args = Default.args;
149+
WithForcedColors.tags = ["!autodocs", "!dev"];
150+
WithForcedColors.parameters = {
151+
chromatic: {
152+
forcedColors: "active",
153+
modes: disableDefaultModes
154+
},
155+
};
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { Container } from "@spectrum-css/preview/decorators";
2+
import { html } from "lit";
3+
import { Template as Textfield } from "./template";
4+
5+
export const Template = ({
6+
customClasses = [],
7+
rootClass = "spectrum-Textfield",
8+
size = "m",
9+
multiline = true,
10+
...item
11+
} = {}, context = {}) => Textfield({
12+
customClasses: [
13+
rootClass,
14+
typeof size !== "undefined" ? `${rootClass}--size${size.toUpperCase()}` : null,
15+
...customClasses
16+
],
17+
size,
18+
multiline,
19+
...item
20+
}, context );
21+
22+
export const HelpTextOptionsTextArea = (args, context) => Container({
23+
direction: "column",
24+
withBorder: false,
25+
withHeading: false,
26+
content: html`
27+
${Container({
28+
withBorder: false,
29+
heading: "Description",
30+
content: Template({...args, isRequired: true, labelText: "Interests", value: "", helpText: "Describe the interests you'd like to explore through our tutorials."}, context),
31+
})}
32+
${Container({
33+
withBorder: false,
34+
heading: "Error message",
35+
content: Template({...args, isRequired: true, labelText: "Interests", value: "", helpText: "Enter at least one interest.", isInvalid: true }, context),
36+
})}
37+
`
38+
});
39+
40+
export const TextAreaOptions = (args, context) => Container({
41+
direction: "row",
42+
withBorder: false,
43+
wrapperStyles: {
44+
rowGap: "12px",
45+
},
46+
content: html`
47+
${Container({
48+
withBorder: false,
49+
containerStyles: {
50+
"gap": "8px",
51+
},
52+
heading: "Default",
53+
content: Template({...args, context})
54+
})}
55+
${Container({
56+
withBorder: false,
57+
containerStyles: {
58+
"gap": "8px",
59+
},
60+
heading: "Invalid",
61+
content: Template({...args, isInvalid: true}, context)
62+
})}
63+
${Container({
64+
withBorder: false,
65+
containerStyles: {
66+
"gap": "8px",
67+
},
68+
heading: "Focused",
69+
content: Template({...args, isFocused: true}, context)
70+
})}
71+
${Container({
72+
withBorder: false,
73+
containerStyles: {
74+
"gap": "8px",
75+
},
76+
heading: "Invalid, focused",
77+
content: Template({...args, isInvalid: true, isFocused: true}, context)
78+
})}
79+
${Container({
80+
withBorder: false,
81+
containerStyles: {
82+
"gap": "8px",
83+
},
84+
heading: "Keyboard-focused",
85+
content: Template({...args, isKeyboardFocused: true}, context)
86+
})}
87+
${Container({
88+
withBorder: false,
89+
containerStyles: {
90+
"gap": "8px",
91+
},
92+
heading: "Invalid, keyboard-focused",
93+
content: Template({...args, isInvalid: true, isKeyboardFocused: true}, context)
94+
})}
95+
`
96+
});

0 commit comments

Comments
 (0)