@khanacademy/wonder-blocks-form 3.1.11 → 3.1.13
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/CHANGELOG.md +41 -0
- package/dist/components/checkbox-core.d.ts +16 -0
- package/dist/components/checkbox-core.js.flow +26 -0
- package/dist/components/checkbox-group.d.ts +84 -0
- package/dist/components/checkbox-group.js.flow +103 -0
- package/dist/components/checkbox.d.ts +83 -0
- package/dist/components/checkbox.js.flow +106 -0
- package/dist/components/choice-internal.d.ts +63 -0
- package/dist/components/choice-internal.js.flow +100 -0
- package/dist/components/choice.d.ts +127 -0
- package/dist/components/choice.js.flow +161 -0
- package/dist/components/field-heading.d.ts +50 -0
- package/dist/components/field-heading.js.flow +64 -0
- package/dist/components/group-styles.d.ts +3 -0
- package/dist/components/group-styles.js.flow +10 -0
- package/dist/components/labeled-text-field.d.ts +169 -0
- package/dist/components/labeled-text-field.js.flow +211 -0
- package/dist/components/radio-core.d.ts +15 -0
- package/dist/components/radio-core.js.flow +26 -0
- package/dist/components/radio-group.d.ts +85 -0
- package/dist/components/radio-group.js.flow +104 -0
- package/dist/components/radio.d.ts +68 -0
- package/dist/components/radio.js.flow +92 -0
- package/dist/components/text-field.d.ts +146 -0
- package/dist/components/text-field.js.flow +186 -0
- package/dist/es/index.js +258 -224
- package/dist/index.d.ts +7 -0
- package/dist/index.js +281 -249
- package/dist/index.js.flow +21 -2
- package/dist/util/types.d.ts +62 -0
- package/dist/util/types.js.flow +138 -0
- package/package.json +10 -10
- package/src/__tests__/{custom-snapshot.test.js → custom-snapshot.test.tsx} +8 -9
- package/src/components/__tests__/{checkbox-group.test.js → checkbox-group.test.tsx} +5 -5
- package/src/components/__tests__/{field-heading.test.js → field-heading.test.tsx} +0 -1
- package/src/components/__tests__/{labeled-text-field.test.js → labeled-text-field.test.tsx} +4 -5
- package/src/components/__tests__/{radio-group.test.js → radio-group.test.tsx} +8 -8
- package/src/components/__tests__/{text-field.test.js → text-field.test.tsx} +22 -18
- package/src/components/{checkbox-core.js → checkbox-core.tsx} +12 -15
- package/src/components/{checkbox-group.js → checkbox-group.tsx} +20 -23
- package/src/components/{checkbox.js → checkbox.tsx} +18 -32
- package/src/components/{choice-internal.js → choice-internal.tsx} +25 -39
- package/src/components/{choice.js → choice.tsx} +24 -37
- package/src/components/{field-heading.js → field-heading.tsx} +16 -23
- package/src/components/{group-styles.js → group-styles.ts} +0 -1
- package/src/components/{labeled-text-field.js → labeled-text-field.tsx} +54 -69
- package/src/components/{radio-core.js → radio-core.tsx} +13 -16
- package/src/components/{radio-group.js → radio-group.tsx} +20 -23
- package/src/components/{radio.js → radio.tsx} +18 -32
- package/src/components/{text-field.js → text-field.tsx} +53 -64
- package/src/{index.js → index.ts} +0 -1
- package/src/util/{types.js → types.ts} +32 -35
- package/tsconfig.json +19 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/__docs__/_overview_.stories.mdx +0 -15
- package/src/components/__docs__/checkbox-accessibility.stories.mdx +0 -147
- package/src/components/__docs__/checkbox-group.stories.js +0 -300
- package/src/components/__docs__/checkbox.stories.js +0 -167
- package/src/components/__docs__/choice.stories.js +0 -86
- package/src/components/__docs__/labeled-text-field.argtypes.js +0 -248
- package/src/components/__docs__/labeled-text-field.stories.js +0 -709
- package/src/components/__docs__/radio-group.stories.js +0 -217
- package/src/components/__docs__/radio.stories.js +0 -161
- package/src/components/__docs__/text-field.argtypes.js +0 -206
- package/src/components/__docs__/text-field.stories.js +0 -780
- /package/src/__tests__/__snapshots__/{custom-snapshot.test.js.snap → custom-snapshot.test.tsx.snap} +0 -0
|
@@ -1,709 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import {StyleSheet} from "aphrodite";
|
|
4
|
-
|
|
5
|
-
import {LabeledTextField} from "@khanacademy/wonder-blocks-form";
|
|
6
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
7
|
-
import {LabelMedium, LabelSmall} from "@khanacademy/wonder-blocks-typography";
|
|
8
|
-
import Color from "@khanacademy/wonder-blocks-color";
|
|
9
|
-
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
10
|
-
import {Strut} from "@khanacademy/wonder-blocks-layout";
|
|
11
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
12
|
-
import Link from "@khanacademy/wonder-blocks-link";
|
|
13
|
-
|
|
14
|
-
import type {StoryComponentType} from "@storybook/react";
|
|
15
|
-
|
|
16
|
-
import ComponentInfo from "../../../../../.storybook/components/component-info";
|
|
17
|
-
import {name, version} from "../../../package.json";
|
|
18
|
-
import LabeledTextFieldArgTypes from "./labeled-text-field.argtypes";
|
|
19
|
-
|
|
20
|
-
export default {
|
|
21
|
-
title: "Form / LabeledTextField",
|
|
22
|
-
component: LabeledTextField,
|
|
23
|
-
parameters: {
|
|
24
|
-
componentSubtitle: ((
|
|
25
|
-
<ComponentInfo name={name} version={version} />
|
|
26
|
-
): any),
|
|
27
|
-
},
|
|
28
|
-
argTypes: LabeledTextFieldArgTypes,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const Default: StoryComponentType = (args) => {
|
|
32
|
-
return <LabeledTextField {...args} />;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
Default.args = {
|
|
36
|
-
id: "some-ltf-id",
|
|
37
|
-
type: "text",
|
|
38
|
-
label: "Label",
|
|
39
|
-
description: "Hello, this is the description for this field",
|
|
40
|
-
value: "",
|
|
41
|
-
disabled: false,
|
|
42
|
-
required: false,
|
|
43
|
-
light: false,
|
|
44
|
-
placeholder: "Placeholder",
|
|
45
|
-
readOnly: false,
|
|
46
|
-
autoComplete: "off",
|
|
47
|
-
validate: () => {},
|
|
48
|
-
onValidate: () => {},
|
|
49
|
-
onChange: () => {},
|
|
50
|
-
onKeyDown: () => {},
|
|
51
|
-
onFocus: () => {},
|
|
52
|
-
onBlur: () => {},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const Text: StoryComponentType = () => {
|
|
56
|
-
const [value, setValue] = React.useState("Khan");
|
|
57
|
-
|
|
58
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
59
|
-
if (event.key === "Enter") {
|
|
60
|
-
event.currentTarget.blur();
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<LabeledTextField
|
|
66
|
-
label="Name"
|
|
67
|
-
description="Please enter your name"
|
|
68
|
-
value={value}
|
|
69
|
-
onChange={(newValue) => setValue(newValue)}
|
|
70
|
-
placeholder="Name"
|
|
71
|
-
onKeyDown={handleKeyDown}
|
|
72
|
-
/>
|
|
73
|
-
);
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
Text.parameters = {
|
|
77
|
-
docs: {
|
|
78
|
-
storyDescription:
|
|
79
|
-
"An input field with type `text` takes all kinds of characters.",
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
export const RequiredWithDefaultText: StoryComponentType = () => {
|
|
84
|
-
const [value, setValue] = React.useState("");
|
|
85
|
-
|
|
86
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
87
|
-
if (event.key === "Enter") {
|
|
88
|
-
event.currentTarget.blur();
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<LabeledTextField
|
|
94
|
-
label="Name"
|
|
95
|
-
description="Please enter your name"
|
|
96
|
-
value={value}
|
|
97
|
-
onChange={setValue}
|
|
98
|
-
onKeyDown={handleKeyDown}
|
|
99
|
-
required={true}
|
|
100
|
-
/>
|
|
101
|
-
);
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
RequiredWithDefaultText.parameters = {
|
|
105
|
-
docs: {
|
|
106
|
-
storyDescription: `A required field will show the message
|
|
107
|
-
"This field is required." by default if someone types in it
|
|
108
|
-
at some point but leaves it blank. Type in the field, then
|
|
109
|
-
backspace all the way and click out of the field to see
|
|
110
|
-
this message. Note that this message would not appear if
|
|
111
|
-
the \`validation\` prop were set.`,
|
|
112
|
-
},
|
|
113
|
-
chromatic: {
|
|
114
|
-
// Disabling snapshot because it doesn't show the error message
|
|
115
|
-
// until after the user interacts with this field.
|
|
116
|
-
disableSnapshot: true,
|
|
117
|
-
},
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
export const RequiredWithSpecifiedText: StoryComponentType = () => {
|
|
121
|
-
const [value, setValue] = React.useState("");
|
|
122
|
-
|
|
123
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
124
|
-
if (event.key === "Enter") {
|
|
125
|
-
event.currentTarget.blur();
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
return (
|
|
130
|
-
<LabeledTextField
|
|
131
|
-
label="Name"
|
|
132
|
-
description="Please enter your name"
|
|
133
|
-
value={value}
|
|
134
|
-
onChange={setValue}
|
|
135
|
-
onKeyDown={handleKeyDown}
|
|
136
|
-
required="This specific field is super required."
|
|
137
|
-
/>
|
|
138
|
-
);
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
RequiredWithSpecifiedText.parameters = {
|
|
142
|
-
docs: {
|
|
143
|
-
storyDescription: `If a string is passed into the \`required\` prop,
|
|
144
|
-
the specified message will show when the field is left blank.
|
|
145
|
-
Type in the field, then backspace all the way and click out of
|
|
146
|
-
the field to see this message. Note that this message would not
|
|
147
|
-
appear if the \`validation\` prop were set.`,
|
|
148
|
-
},
|
|
149
|
-
chromatic: {
|
|
150
|
-
// Disabling snapshot because it doesn't show the error message
|
|
151
|
-
// until after the user interacts with this field.
|
|
152
|
-
disableSnapshot: true,
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
export const Number: StoryComponentType = () => {
|
|
157
|
-
const [value, setValue] = React.useState("18");
|
|
158
|
-
|
|
159
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
160
|
-
if (event.key === "Enter") {
|
|
161
|
-
event.currentTarget.blur();
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
return (
|
|
166
|
-
<LabeledTextField
|
|
167
|
-
label="Age"
|
|
168
|
-
type="number"
|
|
169
|
-
description="Please enter your age"
|
|
170
|
-
value={value}
|
|
171
|
-
onChange={setValue}
|
|
172
|
-
placeholder="Age"
|
|
173
|
-
onKeyDown={handleKeyDown}
|
|
174
|
-
/>
|
|
175
|
-
);
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
Number.parameters = {
|
|
179
|
-
docs: {
|
|
180
|
-
storyDescription:
|
|
181
|
-
"An input field with type `number` will only take numeric characters as input.",
|
|
182
|
-
},
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
export const Password: StoryComponentType = () => {
|
|
186
|
-
const [value, setValue] = React.useState("$ecure123");
|
|
187
|
-
|
|
188
|
-
const validate = (value: string) => {
|
|
189
|
-
if (value.length < 8) {
|
|
190
|
-
return "Password must be at least 8 characters long";
|
|
191
|
-
}
|
|
192
|
-
if (!/\d/.test(value)) {
|
|
193
|
-
return "Password must contain a numeric value";
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
198
|
-
if (event.key === "Enter") {
|
|
199
|
-
event.currentTarget.blur();
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<LabeledTextField
|
|
205
|
-
label="Password"
|
|
206
|
-
type="password"
|
|
207
|
-
description="Please enter a secure password"
|
|
208
|
-
value={value}
|
|
209
|
-
onChange={setValue}
|
|
210
|
-
placeholder="Password"
|
|
211
|
-
validate={validate}
|
|
212
|
-
onKeyDown={handleKeyDown}
|
|
213
|
-
/>
|
|
214
|
-
);
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
Password.parameters = {
|
|
218
|
-
docs: {
|
|
219
|
-
storyDescription: `An input field with type \`password\` will
|
|
220
|
-
obscure the input value. It also often contains validation.
|
|
221
|
-
In this example, the password must be over 8 characters long and
|
|
222
|
-
must contain a numeric value.`,
|
|
223
|
-
},
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
export const Email: StoryComponentType = () => {
|
|
227
|
-
const [value, setValue] = React.useState("khan@khan.org");
|
|
228
|
-
|
|
229
|
-
const validate = (value: string) => {
|
|
230
|
-
const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
|
|
231
|
-
if (!emailRegex.test(value)) {
|
|
232
|
-
return "Please enter a valid email";
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
237
|
-
if (event.key === "Enter") {
|
|
238
|
-
event.currentTarget.blur();
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
return (
|
|
243
|
-
<LabeledTextField
|
|
244
|
-
label="Email"
|
|
245
|
-
type="email"
|
|
246
|
-
value={value}
|
|
247
|
-
onChange={setValue}
|
|
248
|
-
description="Please provide your personal email"
|
|
249
|
-
placeholder="Email"
|
|
250
|
-
validate={validate}
|
|
251
|
-
onKeyDown={handleKeyDown}
|
|
252
|
-
/>
|
|
253
|
-
);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
Email.parameters = {
|
|
257
|
-
docs: {
|
|
258
|
-
storyDescription: `An input field with type \`email\` will automatically
|
|
259
|
-
validate an input on submit to ensure it's either formatted properly
|
|
260
|
-
or blank. \`TextField\` will run validation on blur if the
|
|
261
|
-
\`validate\` prop is passed in, as in this example.`,
|
|
262
|
-
},
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
export const EmailRequired: StoryComponentType = () => {
|
|
266
|
-
const [value, setValue] = React.useState("");
|
|
267
|
-
|
|
268
|
-
const validate = (value: string) => {
|
|
269
|
-
const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
|
|
270
|
-
if (!emailRegex.test(value)) {
|
|
271
|
-
return "Please enter a valid email";
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
276
|
-
if (event.key === "Enter") {
|
|
277
|
-
event.currentTarget.blur();
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
return (
|
|
282
|
-
<LabeledTextField
|
|
283
|
-
label="Email"
|
|
284
|
-
type="email"
|
|
285
|
-
onChange={setValue}
|
|
286
|
-
description="Please provide your personal email"
|
|
287
|
-
value={value}
|
|
288
|
-
validate={validate}
|
|
289
|
-
onKeyDown={handleKeyDown}
|
|
290
|
-
required={true}
|
|
291
|
-
/>
|
|
292
|
-
);
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
EmailRequired.parameters = {
|
|
296
|
-
docs: {
|
|
297
|
-
storyDescription: `An example of a required field that also has
|
|
298
|
-
a \`validation\` prop passed in. \`required\` can be a boolean or
|
|
299
|
-
a string. In this case, \`required\` is set to \`true\` since a
|
|
300
|
-
string would not even be used if it were passed in because the
|
|
301
|
-
validation overrides it.`,
|
|
302
|
-
},
|
|
303
|
-
chromatic: {
|
|
304
|
-
// We have screenshots of other stories that cover this case.
|
|
305
|
-
disableSnapshot: true,
|
|
306
|
-
},
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
export const Telephone: StoryComponentType = () => {
|
|
310
|
-
const [value, setValue] = React.useState("123-456-7890");
|
|
311
|
-
|
|
312
|
-
const validate = (value: string) => {
|
|
313
|
-
const telRegex = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/;
|
|
314
|
-
if (!telRegex.test(value)) {
|
|
315
|
-
return "Invalid US telephone number";
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
320
|
-
if (event.key === "Enter") {
|
|
321
|
-
event.currentTarget.blur();
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
return (
|
|
326
|
-
<LabeledTextField
|
|
327
|
-
label="Telephone"
|
|
328
|
-
type="tel"
|
|
329
|
-
value={value}
|
|
330
|
-
onChange={setValue}
|
|
331
|
-
description="Please provide your personal phone number"
|
|
332
|
-
placeholder="Telephone"
|
|
333
|
-
validate={validate}
|
|
334
|
-
onKeyDown={handleKeyDown}
|
|
335
|
-
/>
|
|
336
|
-
);
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
Telephone.parameters = {
|
|
340
|
-
docs: {
|
|
341
|
-
storyDescription: `An input field with type \`tel\` will NOT
|
|
342
|
-
validate an input on submit by default as telephone numbers
|
|
343
|
-
can vary considerably. \`TextField\` will run validation on blur
|
|
344
|
-
if the \`validate\` prop is passed in, as in this example.`,
|
|
345
|
-
},
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
export const Error: StoryComponentType = () => {
|
|
349
|
-
const [value, setValue] = React.useState("khan");
|
|
350
|
-
|
|
351
|
-
const validate = (value: string) => {
|
|
352
|
-
const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
|
|
353
|
-
if (!emailRegex.test(value)) {
|
|
354
|
-
return "Please enter a valid email";
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
359
|
-
if (event.key === "Enter") {
|
|
360
|
-
event.currentTarget.blur();
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
return (
|
|
365
|
-
<LabeledTextField
|
|
366
|
-
label="Email"
|
|
367
|
-
type="email"
|
|
368
|
-
value={value}
|
|
369
|
-
onChange={setValue}
|
|
370
|
-
description="Please provide your personal email"
|
|
371
|
-
placeholder="Email"
|
|
372
|
-
validate={validate}
|
|
373
|
-
onKeyDown={handleKeyDown}
|
|
374
|
-
/>
|
|
375
|
-
);
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
Error.parameters = {
|
|
379
|
-
docs: {
|
|
380
|
-
storyDescription: `If an input value fails validation,
|
|
381
|
-
\`TextField\` will have error styling.`,
|
|
382
|
-
},
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
export const Light: StoryComponentType = () => {
|
|
386
|
-
const [value, setValue] = React.useState("");
|
|
387
|
-
|
|
388
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
389
|
-
if (event.key === "Enter") {
|
|
390
|
-
event.currentTarget.blur();
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
return (
|
|
395
|
-
<View style={styles.darkBackground}>
|
|
396
|
-
<LabeledTextField
|
|
397
|
-
label={
|
|
398
|
-
<LabelMedium style={styles.whiteColor}>Name</LabelMedium>
|
|
399
|
-
}
|
|
400
|
-
description={
|
|
401
|
-
<LabelSmall style={styles.offWhiteColor}>
|
|
402
|
-
Please enter your name
|
|
403
|
-
</LabelSmall>
|
|
404
|
-
}
|
|
405
|
-
value={value}
|
|
406
|
-
onChange={setValue}
|
|
407
|
-
placeholder="Name"
|
|
408
|
-
light={true}
|
|
409
|
-
onKeyDown={handleKeyDown}
|
|
410
|
-
/>
|
|
411
|
-
</View>
|
|
412
|
-
);
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
Light.parameters = {
|
|
416
|
-
docs: {
|
|
417
|
-
storyDescription: `If the \`light\` prop is set to true, the
|
|
418
|
-
underlying \`TextField\` will have a light border when focused.
|
|
419
|
-
This is intended to be used on a dark background. There is also a
|
|
420
|
-
specific light styling for the error state, as seen in the
|
|
421
|
-
\`ErrorLight\` story.`,
|
|
422
|
-
},
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
export const ErrorLight: StoryComponentType = () => {
|
|
426
|
-
const [value, setValue] = React.useState("khan");
|
|
427
|
-
|
|
428
|
-
const validate = (value: string) => {
|
|
429
|
-
const emailRegex = /^[^@\s]+@[^@\s.]+\.[^@.\s]+$/;
|
|
430
|
-
if (!emailRegex.test(value)) {
|
|
431
|
-
return "Please enter a valid email";
|
|
432
|
-
}
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
436
|
-
if (event.key === "Enter") {
|
|
437
|
-
event.currentTarget.blur();
|
|
438
|
-
}
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
return (
|
|
442
|
-
<View style={styles.darkBackground}>
|
|
443
|
-
<LabeledTextField
|
|
444
|
-
label={
|
|
445
|
-
<LabelMedium style={styles.whiteColor}>Email</LabelMedium>
|
|
446
|
-
}
|
|
447
|
-
description={
|
|
448
|
-
<LabelSmall style={styles.offWhiteColor}>
|
|
449
|
-
Please provide your personal email
|
|
450
|
-
</LabelSmall>
|
|
451
|
-
}
|
|
452
|
-
type="email"
|
|
453
|
-
value={value}
|
|
454
|
-
light={true}
|
|
455
|
-
onChange={setValue}
|
|
456
|
-
placeholder="Email"
|
|
457
|
-
validate={validate}
|
|
458
|
-
onKeyDown={handleKeyDown}
|
|
459
|
-
/>
|
|
460
|
-
</View>
|
|
461
|
-
);
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
ErrorLight.parameters = {
|
|
465
|
-
docs: {
|
|
466
|
-
storyDescription: `If an input value fails validation and the
|
|
467
|
-
\`light\` prop is true, \`TextField\` will have light error styling.`,
|
|
468
|
-
},
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
export const Disabled: StoryComponentType = () => (
|
|
472
|
-
<LabeledTextField
|
|
473
|
-
label="Name"
|
|
474
|
-
description="Please enter your name"
|
|
475
|
-
value=""
|
|
476
|
-
onChange={() => {}}
|
|
477
|
-
placeholder="Name"
|
|
478
|
-
disabled={true}
|
|
479
|
-
/>
|
|
480
|
-
);
|
|
481
|
-
|
|
482
|
-
Disabled.parameters = {
|
|
483
|
-
docs: {
|
|
484
|
-
storyDescription: `If the \`disabled\` prop is set to true,
|
|
485
|
-
\`TextField\` will have disabled styling and will not be interactable.`,
|
|
486
|
-
},
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
export const CustomStyle: StoryComponentType = () => {
|
|
490
|
-
const [firstName, setFirstName] = React.useState("");
|
|
491
|
-
const [lastName, setLastName] = React.useState("");
|
|
492
|
-
|
|
493
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
494
|
-
if (event.key === "Enter") {
|
|
495
|
-
event.currentTarget.blur();
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
return (
|
|
500
|
-
<View style={styles.row}>
|
|
501
|
-
<LabeledTextField
|
|
502
|
-
label="First name"
|
|
503
|
-
description="Please enter your first name"
|
|
504
|
-
value={firstName}
|
|
505
|
-
onChange={setFirstName}
|
|
506
|
-
placeholder="Khan"
|
|
507
|
-
style={styles.grow}
|
|
508
|
-
onKeyDown={handleKeyDown}
|
|
509
|
-
/>
|
|
510
|
-
<Strut size={Spacing.xLarge_32} />
|
|
511
|
-
<LabeledTextField
|
|
512
|
-
label="Last name"
|
|
513
|
-
description="Please enter your last name"
|
|
514
|
-
value={lastName}
|
|
515
|
-
onChange={setLastName}
|
|
516
|
-
placeholder="Academy"
|
|
517
|
-
style={styles.grow}
|
|
518
|
-
onKeyDown={handleKeyDown}
|
|
519
|
-
/>
|
|
520
|
-
</View>
|
|
521
|
-
);
|
|
522
|
-
};
|
|
523
|
-
|
|
524
|
-
CustomStyle.parameters = {
|
|
525
|
-
docs: {
|
|
526
|
-
storyDescription: `\`LabeledTextField\` can take in custom styles that
|
|
527
|
-
override the default styles. In this example, each field has the
|
|
528
|
-
style property \`flexGrow: 1\``,
|
|
529
|
-
},
|
|
530
|
-
};
|
|
531
|
-
|
|
532
|
-
export const WithMarkup: StoryComponentType = (args) => {
|
|
533
|
-
return (
|
|
534
|
-
<LabeledTextField
|
|
535
|
-
{...args}
|
|
536
|
-
label="Name"
|
|
537
|
-
description={
|
|
538
|
-
<span>
|
|
539
|
-
Description with <strong>strong</strong> text and a{" "}
|
|
540
|
-
<Link href="/path/to/resource">link</Link>
|
|
541
|
-
</span>
|
|
542
|
-
}
|
|
543
|
-
/>
|
|
544
|
-
);
|
|
545
|
-
};
|
|
546
|
-
|
|
547
|
-
WithMarkup.parameters = {
|
|
548
|
-
docs: {
|
|
549
|
-
storyDescription: `\`LabeledTextField\`'s \`label\` and \`description\` props
|
|
550
|
-
can accept \`React.Node\`s. This is helpful when you need to decorate or use
|
|
551
|
-
specific elements in your form field (e.g. including Popovers, Tooltips or
|
|
552
|
-
emphasized text)`,
|
|
553
|
-
},
|
|
554
|
-
};
|
|
555
|
-
|
|
556
|
-
export const Ref: StoryComponentType = () => {
|
|
557
|
-
const [value, setValue] = React.useState("Khan");
|
|
558
|
-
const inputRef = React.createRef();
|
|
559
|
-
|
|
560
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
561
|
-
if (event.key === "Enter") {
|
|
562
|
-
event.currentTarget.blur();
|
|
563
|
-
}
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
const handleSubmit = () => {
|
|
567
|
-
if (inputRef.current) {
|
|
568
|
-
inputRef.current.focus();
|
|
569
|
-
}
|
|
570
|
-
};
|
|
571
|
-
|
|
572
|
-
return (
|
|
573
|
-
<View>
|
|
574
|
-
<LabeledTextField
|
|
575
|
-
label="Name"
|
|
576
|
-
description="Please enter your name"
|
|
577
|
-
value={value}
|
|
578
|
-
onChange={setValue}
|
|
579
|
-
placeholder="Name"
|
|
580
|
-
onKeyDown={handleKeyDown}
|
|
581
|
-
ref={inputRef}
|
|
582
|
-
/>
|
|
583
|
-
<Strut size={Spacing.medium_16} />
|
|
584
|
-
<Button style={styles.button} onClick={handleSubmit}>
|
|
585
|
-
Focus Input
|
|
586
|
-
</Button>
|
|
587
|
-
</View>
|
|
588
|
-
);
|
|
589
|
-
};
|
|
590
|
-
|
|
591
|
-
Ref.parameters = {
|
|
592
|
-
docs: {
|
|
593
|
-
storyDescription: `If you need to save a reference to the input
|
|
594
|
-
field, you can do so by using the \`ref\` prop. In this example,
|
|
595
|
-
we want the input field to receive focus when the button is
|
|
596
|
-
pressed. We can do this by creating a React ref of type
|
|
597
|
-
\`HTMLInputElement\` and passing it into \`TextField\`'s \`ref\` prop.
|
|
598
|
-
Now we can use the ref variable in the \`handleSubmit\` function to
|
|
599
|
-
shift focus to the field.`,
|
|
600
|
-
chromatic: {
|
|
601
|
-
// Disabling snapshot because this is testing interaction,
|
|
602
|
-
// not visuals.
|
|
603
|
-
disableSnapshot: true,
|
|
604
|
-
},
|
|
605
|
-
},
|
|
606
|
-
};
|
|
607
|
-
|
|
608
|
-
export const ReadOnly: StoryComponentType = () => {
|
|
609
|
-
const [value, setValue] = React.useState("Khan");
|
|
610
|
-
|
|
611
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
612
|
-
if (event.key === "Enter") {
|
|
613
|
-
event.currentTarget.blur();
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
|
|
617
|
-
return (
|
|
618
|
-
<LabeledTextField
|
|
619
|
-
label="Read Only"
|
|
620
|
-
description="This is a read-only field."
|
|
621
|
-
value={value}
|
|
622
|
-
onChange={setValue}
|
|
623
|
-
placeholder="Name"
|
|
624
|
-
onKeyDown={handleKeyDown}
|
|
625
|
-
readOnly={true}
|
|
626
|
-
/>
|
|
627
|
-
);
|
|
628
|
-
};
|
|
629
|
-
|
|
630
|
-
ReadOnly.parameters = {
|
|
631
|
-
docs: {
|
|
632
|
-
storyDescription: `An input field with the prop \`readOnly\` set
|
|
633
|
-
to true is not interactable. It looks the same as if it were not
|
|
634
|
-
read only, and it can still receive focus, but the interaction
|
|
635
|
-
point will not appear and the input will not change.`,
|
|
636
|
-
chromatic: {
|
|
637
|
-
// Disabling snapshot because this is testing interaction,
|
|
638
|
-
// not visuals.
|
|
639
|
-
disableSnapshot: true,
|
|
640
|
-
},
|
|
641
|
-
},
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
export const AutoComplete: StoryComponentType = () => {
|
|
645
|
-
const [value, setValue] = React.useState("");
|
|
646
|
-
|
|
647
|
-
const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
|
648
|
-
if (event.key === "Enter") {
|
|
649
|
-
event.currentTarget.blur();
|
|
650
|
-
}
|
|
651
|
-
};
|
|
652
|
-
|
|
653
|
-
return (
|
|
654
|
-
<form>
|
|
655
|
-
<LabeledTextField
|
|
656
|
-
label="Name"
|
|
657
|
-
description="Please enter your name."
|
|
658
|
-
value={value}
|
|
659
|
-
onChange={setValue}
|
|
660
|
-
placeholder="Name"
|
|
661
|
-
onKeyDown={handleKeyDown}
|
|
662
|
-
style={styles.fieldWithButton}
|
|
663
|
-
autoComplete="name"
|
|
664
|
-
/>
|
|
665
|
-
<Button type="submit">Submit</Button>
|
|
666
|
-
</form>
|
|
667
|
-
);
|
|
668
|
-
};
|
|
669
|
-
|
|
670
|
-
AutoComplete.parameters = {
|
|
671
|
-
docs: {
|
|
672
|
-
storyDescription: `If \`TextField\`'s \`autocomplete\` prop is set,
|
|
673
|
-
the browser can predict values for the input. When the user starts
|
|
674
|
-
to type in the field, a list of options will show up based on
|
|
675
|
-
values that may have been submitted at a previous time.
|
|
676
|
-
In this example, the text field provides options after you
|
|
677
|
-
input a value, press the submit button, and refresh the page.`,
|
|
678
|
-
chromatic: {
|
|
679
|
-
// Disabling snapshot because this is testing interaction,
|
|
680
|
-
// not visuals.
|
|
681
|
-
disableSnapshot: true,
|
|
682
|
-
},
|
|
683
|
-
},
|
|
684
|
-
};
|
|
685
|
-
|
|
686
|
-
const styles = StyleSheet.create({
|
|
687
|
-
darkBackground: {
|
|
688
|
-
background: Color.darkBlue,
|
|
689
|
-
padding: `${Spacing.medium_16}px`,
|
|
690
|
-
},
|
|
691
|
-
whiteColor: {
|
|
692
|
-
color: Color.white,
|
|
693
|
-
},
|
|
694
|
-
offWhiteColor: {
|
|
695
|
-
color: Color.white64,
|
|
696
|
-
},
|
|
697
|
-
button: {
|
|
698
|
-
maxWidth: 150,
|
|
699
|
-
},
|
|
700
|
-
row: {
|
|
701
|
-
flexDirection: "row",
|
|
702
|
-
},
|
|
703
|
-
grow: {
|
|
704
|
-
flexGrow: 1,
|
|
705
|
-
},
|
|
706
|
-
fieldWithButton: {
|
|
707
|
-
marginBottom: Spacing.medium_16,
|
|
708
|
-
},
|
|
709
|
-
});
|