@workday/canvas-kit-docs 17.0.0-alpha.0613-next.0 → 17.0.0-alpha.0616-next.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/dist/es6/lib/specs.js +20 -0
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.js +5 -5
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.ts +5 -5
- package/dist/mdx/accessibility/AccessibilityOverview.mdx +3 -1
- package/dist/mdx/preview-react/_examples/mdx/FormLibraryExample.mdx +33 -1
- package/dist/mdx/preview-react/_examples/mdx/examples/TextInputWithReactHookForm.tsx +94 -65
- package/dist/mdx/react/_examples/mdx/Density.mdx +19 -3
- package/dist/mdx/react/_examples/mdx/examples/Density.tsx +139 -212
- package/dist/mdx/react/common/mdx/examples/CreateComponent.tsx +3 -3
- package/package.json +6 -6
- package/dist/mdx/react/_examples/mdx/FormsWithFormik.mdx +0 -9
- package/dist/mdx/react/_examples/mdx/examples/SelectWithFormik.tsx +0 -84
package/dist/es6/lib/specs.js
CHANGED
|
@@ -1491,6 +1491,26 @@ module.exports = {specifications: [
|
|
|
1491
1491
|
{
|
|
1492
1492
|
"type": "it",
|
|
1493
1493
|
"name": "should not have any axe errors"
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
"type": "describe",
|
|
1497
|
+
"name": "when the form is submitted with an empty required select",
|
|
1498
|
+
"children": [
|
|
1499
|
+
{
|
|
1500
|
+
"type": "it",
|
|
1501
|
+
"name": "should focus the first invalid field"
|
|
1502
|
+
}
|
|
1503
|
+
]
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
"type": "describe",
|
|
1507
|
+
"name": "when a later required field is empty",
|
|
1508
|
+
"children": [
|
|
1509
|
+
{
|
|
1510
|
+
"type": "it",
|
|
1511
|
+
"name": "should focus the first invalid field"
|
|
1512
|
+
}
|
|
1513
|
+
]
|
|
1494
1514
|
}
|
|
1495
1515
|
]
|
|
1496
1516
|
}
|
|
@@ -18,11 +18,11 @@ export const packageJSONFile = `{
|
|
|
18
18
|
"@emotion/react": "11.11.4",
|
|
19
19
|
"@types/react": "18.2.60",
|
|
20
20
|
"@types/react-dom": "18.2.19",
|
|
21
|
-
"@workday/canvas-kit-labs-react": "16.1.
|
|
22
|
-
"@workday/canvas-kit-preview-react": "16.1.
|
|
23
|
-
"@workday/canvas-kit-react": "16.1.
|
|
24
|
-
"@workday/canvas-kit-react-fonts": "^16.1.
|
|
25
|
-
"@workday/canvas-kit-styling": "16.1.
|
|
21
|
+
"@workday/canvas-kit-labs-react": "16.1.3",
|
|
22
|
+
"@workday/canvas-kit-preview-react": "16.1.3",
|
|
23
|
+
"@workday/canvas-kit-react": "16.1.3",
|
|
24
|
+
"@workday/canvas-kit-react-fonts": "^16.1.3",
|
|
25
|
+
"@workday/canvas-kit-styling": "16.1.3",
|
|
26
26
|
"@workday/canvas-system-icons-web": "^5.0.3",
|
|
27
27
|
"@workday/canvas-expressive-icons-web": "1.0.1",
|
|
28
28
|
"@workday/canvas-tokens-web": "4.4.0-beta.11"
|
|
@@ -19,11 +19,11 @@ export const packageJSONFile = `{
|
|
|
19
19
|
"@emotion/react": "11.11.4",
|
|
20
20
|
"@types/react": "18.2.60",
|
|
21
21
|
"@types/react-dom": "18.2.19",
|
|
22
|
-
"@workday/canvas-kit-labs-react": "16.1.
|
|
23
|
-
"@workday/canvas-kit-preview-react": "16.1.
|
|
24
|
-
"@workday/canvas-kit-react": "16.1.
|
|
25
|
-
"@workday/canvas-kit-react-fonts": "^16.1.
|
|
26
|
-
"@workday/canvas-kit-styling": "16.1.
|
|
22
|
+
"@workday/canvas-kit-labs-react": "16.1.3",
|
|
23
|
+
"@workday/canvas-kit-preview-react": "16.1.3",
|
|
24
|
+
"@workday/canvas-kit-react": "16.1.3",
|
|
25
|
+
"@workday/canvas-kit-react-fonts": "^16.1.3",
|
|
26
|
+
"@workday/canvas-kit-styling": "16.1.3",
|
|
27
27
|
"@workday/canvas-system-icons-web": "^5.0.3",
|
|
28
28
|
"@workday/canvas-expressive-icons-web": "1.0.1",
|
|
29
29
|
"@workday/canvas-tokens-web": "4.4.0-beta.11"
|
|
@@ -86,7 +86,9 @@ Further reading:
|
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
Check out our [Aria Live Region Examples](?path=/docs/guides-accessibility-aria-live-regions--docs)
|
|
89
|
-
for more detailed information about this topic.
|
|
89
|
+
for more detailed information about this topic. For labels, error text, `aria-invalid`, and focus
|
|
90
|
+
after a failed submit, see
|
|
91
|
+
[Form Validation](?path=/docs/guides-accessibility-form-validation--docs).
|
|
90
92
|
|
|
91
93
|
Sometimes, things change on a webpage without the whole page reloading. Think of a live sports score
|
|
92
94
|
that updates every few seconds or a search result that appears as you type. For users of screen
|
|
@@ -1,7 +1,39 @@
|
|
|
1
1
|
import {ExampleCodeBlock} from '@workday/canvas-kit-docs';
|
|
2
|
+
|
|
2
3
|
import TextInputWithReactHookForm from './examples/TextInputWithReactHookForm';
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
# Form Validation with React Hook Form and Yup
|
|
7
|
+
|
|
8
|
+
Accessible form validation is not a library feature. It is a composition of **labels**, **error text
|
|
9
|
+
tied to the field**, **`aria-invalid`**, and **keyboard focus**. Canvas Kit
|
|
10
|
+
[`FormField`](?path=/docs/components-inputs-form-field--docs#accessibility) owns the first three
|
|
11
|
+
when you use its subcomponents. The application owns when validation runs and where focus goes after
|
|
12
|
+
submit.
|
|
13
|
+
|
|
14
|
+
1. **Identify every field, including required ones** Set `autoComplete` with a
|
|
15
|
+
[standard token](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill)
|
|
16
|
+
when the field collects a known personal data type (`username`, `current-password`, `email`,
|
|
17
|
+
`name`). That supports
|
|
18
|
+
[WCAG 1.3.5 Identify Input Purpose](https://www.w3.org/WAI/WCAG22/Understanding/identify-input-purpose.html).
|
|
19
|
+
2. **Move focus to the first invalid field after submit** Failed submit must not leave focus on the
|
|
20
|
+
submit button. Keyboard and screen-reader users need to land on the first field that is still
|
|
21
|
+
invalid, in **DOM order**.
|
|
22
|
+
3. **Choose when to validate** Prefer validating **on submit**, then on **blur / touched** for
|
|
23
|
+
fields the user has already visited (`mode: 'onTouched'` in this example). Validating on every
|
|
24
|
+
keystroke while the field is still incomplete is noisy and can announce `aria-invalid` too early.
|
|
25
|
+
(Relevant criteria:
|
|
26
|
+
[3.3.1 Error Identification](https://www.w3.org/WAI/WCAG22/Understanding/error-identification.html),
|
|
27
|
+
[3.3.3 Error Suggestion](https://www.w3.org/WAI/WCAG22/Understanding/error-suggestion.html).)
|
|
28
|
+
4. **Do not use a live region for every field error** Field errors belong on the field
|
|
29
|
+
(`aria-invalid` + `aria-describedby`). They are announced when the field **receives focus**. A
|
|
30
|
+
page-level live region that restates every invalid field on submit is easy to overdo. Live
|
|
31
|
+
announcements cannot be replayed, can interrupt, and have uneven support. If you add a form-level
|
|
32
|
+
summary, keep it short, do not duplicate every message, and read
|
|
33
|
+
[ARIA Live Regions](?path=/docs/guides-accessibility-aria-live-regions--docs) first.
|
|
34
|
+
|
|
35
|
+
This example wires `FormField`, `TextInput`, `Select`, and `InputGroup` to
|
|
36
|
+
[React Hook Form](https://www.react-hook-form.com/) with [Yup](https://github.com/jquense/yup). The
|
|
37
|
+
same practices apply if you use Formik, a server round-trip, or hand-rolled state.
|
|
6
38
|
|
|
7
39
|
<ExampleCodeBlock code={TextInputWithReactHookForm} />
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {SchemaOf, object, string} from 'yup';
|
|
2
|
+
import {FieldErrors, Resolver, useForm} from 'react-hook-form';
|
|
3
|
+
import {SchemaOf, ValidationError, object, string} from 'yup';
|
|
4
4
|
|
|
5
5
|
import {PrimaryButton, TertiaryButton} from '@workday/canvas-kit-react/button';
|
|
6
|
-
import {useUniqueId} from '@workday/canvas-kit-react/common';
|
|
7
|
-
import {
|
|
6
|
+
import {ErrorType, useUniqueId} from '@workday/canvas-kit-react/common';
|
|
7
|
+
import {
|
|
8
|
+
FormField,
|
|
9
|
+
useFormFieldInput,
|
|
10
|
+
useFormFieldModel,
|
|
11
|
+
} from '@workday/canvas-kit-react/form-field';
|
|
8
12
|
import {Flex} from '@workday/canvas-kit-react/layout';
|
|
9
13
|
import {Select} from '@workday/canvas-kit-react/select';
|
|
10
|
-
import {TextInput} from '@workday/canvas-kit-react/text-input';
|
|
14
|
+
import {InputGroup, TextInput} from '@workday/canvas-kit-react/text-input';
|
|
15
|
+
import {Tooltip} from '@workday/canvas-kit-react/tooltip';
|
|
11
16
|
import {createStyles, px2rem} from '@workday/canvas-kit-styling';
|
|
12
17
|
import {visibleIcon, visibleStrikethroughIcon} from '@workday/canvas-system-icons-web';
|
|
13
18
|
import {system} from '@workday/canvas-tokens-web';
|
|
@@ -18,31 +23,30 @@ const styles = createStyles({
|
|
|
18
23
|
alignItems: 'flex-start',
|
|
19
24
|
});
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
) => (data: T) => Promise<{values: T; errors: {}} | {values: {}; errors: FieldErrorsImpl<T>}>;
|
|
24
|
-
|
|
25
|
-
const useYupValidationResolver: YupValidationResolver = validationSchema => {
|
|
26
|
-
return React.useCallback(
|
|
26
|
+
const useYupValidationResolver = <T extends {}>(validationSchema: SchemaOf<T>): Resolver<T> => {
|
|
27
|
+
return React.useCallback<Resolver<T>>(
|
|
27
28
|
async data => {
|
|
28
29
|
try {
|
|
29
|
-
|
|
30
|
-
return {values, errors: {}};
|
|
31
|
-
} catch (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
),
|
|
45
|
-
|
|
30
|
+
await validationSchema.validate(data, {abortEarly: false});
|
|
31
|
+
return {values: data, errors: {}};
|
|
32
|
+
} catch (error) {
|
|
33
|
+
// Yup throws a `ValidationError` for failed validation. Anything else is a real error.
|
|
34
|
+
if (!ValidationError.isError(error)) {
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const errors = error.inner.reduce<Record<string, {type: string; message: string}>>(
|
|
39
|
+
(allErrors, currentError) => ({
|
|
40
|
+
...allErrors,
|
|
41
|
+
[currentError.path ?? '']: {
|
|
42
|
+
type: currentError.type ?? 'validation',
|
|
43
|
+
message: currentError.message,
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
{}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return {values: {}, errors: errors as FieldErrors<T>};
|
|
46
50
|
}
|
|
47
51
|
},
|
|
48
52
|
[validationSchema]
|
|
@@ -74,6 +78,9 @@ const options = [
|
|
|
74
78
|
];
|
|
75
79
|
|
|
76
80
|
export default () => {
|
|
81
|
+
const formRef = React.useRef<HTMLFormElement>(null);
|
|
82
|
+
const [showPassword, setShowPassword] = React.useState(false);
|
|
83
|
+
const [submitAttempt, setSubmitAttempt] = React.useState(0);
|
|
77
84
|
const {
|
|
78
85
|
handleSubmit,
|
|
79
86
|
register,
|
|
@@ -84,19 +91,36 @@ export default () => {
|
|
|
84
91
|
password: 'foobarbaz',
|
|
85
92
|
role: '',
|
|
86
93
|
},
|
|
87
|
-
resolver: useYupValidationResolver(validationSchema),
|
|
94
|
+
resolver: useYupValidationResolver<LoginSchema>(validationSchema),
|
|
88
95
|
mode: 'onTouched',
|
|
96
|
+
shouldFocusError: true,
|
|
89
97
|
});
|
|
90
98
|
|
|
91
|
-
const onSubmit = handleSubmit(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
const onSubmit = handleSubmit(
|
|
100
|
+
values => {
|
|
101
|
+
setShowPassword(false);
|
|
102
|
+
// Send data to server
|
|
103
|
+
setTimeout(() => {
|
|
104
|
+
alert(JSON.stringify(values, null, 2));
|
|
105
|
+
}, 0);
|
|
106
|
+
},
|
|
107
|
+
() => {
|
|
108
|
+
// Count failed submits so we can move focus after FormField paints `aria-invalid`.
|
|
109
|
+
setSubmitAttempt(count => count + 1);
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
React.useEffect(() => {
|
|
114
|
+
if (submitAttempt === 0) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const firstInvalidField = formRef.current?.querySelector<HTMLElement>(
|
|
119
|
+
'[aria-invalid="true"]:not([aria-hidden="true"]):not([tabindex="-1"])'
|
|
120
|
+
);
|
|
121
|
+
firstInvalidField?.focus();
|
|
122
|
+
}, [submitAttempt, errors]);
|
|
98
123
|
|
|
99
|
-
const [showPassword, setShowPassword] = React.useState(false);
|
|
100
124
|
const passwordId = useUniqueId();
|
|
101
125
|
const passwordRef = React.useRef<HTMLInputElement | null>(null);
|
|
102
126
|
const {ref: passwordCallbackRef, ...passwordRegistration} = register('password');
|
|
@@ -104,8 +128,15 @@ export default () => {
|
|
|
104
128
|
passwordCallbackRef(ref);
|
|
105
129
|
passwordRef.current = ref;
|
|
106
130
|
};
|
|
131
|
+
// `InputGroup` renders the input, so hoist the model to keep the label, hint, and error wiring.
|
|
132
|
+
const passwordModel = useFormFieldModel({
|
|
133
|
+
id: passwordId,
|
|
134
|
+
isRequired: true,
|
|
135
|
+
error: errors.password ? 'error' : undefined,
|
|
136
|
+
});
|
|
137
|
+
const passwordInputProps = useFormFieldInput(passwordModel);
|
|
107
138
|
return (
|
|
108
|
-
<form onSubmit={onSubmit} action="." noValidate={true}>
|
|
139
|
+
<form ref={formRef} onSubmit={onSubmit} action="." noValidate={true}>
|
|
109
140
|
<Flex cs={styles}>
|
|
110
141
|
<FormField
|
|
111
142
|
orientation="vertical"
|
|
@@ -143,35 +174,33 @@ export default () => {
|
|
|
143
174
|
</FormField.Field>
|
|
144
175
|
<FormField.Hint>{errors.email?.message}</FormField.Hint>
|
|
145
176
|
</FormField>
|
|
146
|
-
<FormField
|
|
147
|
-
orientation="vertical"
|
|
148
|
-
id={passwordId}
|
|
149
|
-
isRequired={true}
|
|
150
|
-
error={!!errors.password ? 'error' : undefined}
|
|
151
|
-
>
|
|
177
|
+
<FormField model={passwordModel} orientation="vertical">
|
|
152
178
|
<FormField.Label>Password</FormField.Label>
|
|
153
|
-
<
|
|
154
|
-
<
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
/>
|
|
163
|
-
</FormField.Field>
|
|
164
|
-
<TertiaryButton
|
|
165
|
-
type="button"
|
|
166
|
-
icon={showPassword ? visibleStrikethroughIcon : visibleIcon}
|
|
167
|
-
aria-label={showPassword ? 'Hide Password' : 'Show Password'}
|
|
168
|
-
aria-controls={`input-${passwordId}`}
|
|
169
|
-
onClick={() => {
|
|
170
|
-
setShowPassword(state => !state);
|
|
171
|
-
passwordRef.current?.focus();
|
|
172
|
-
}}
|
|
179
|
+
<FormField.Field as={InputGroup}>
|
|
180
|
+
<InputGroup.Input
|
|
181
|
+
{...passwordInputProps}
|
|
182
|
+
{...passwordRegistration}
|
|
183
|
+
error={errors.password ? ErrorType.Error : undefined}
|
|
184
|
+
type={showPassword ? 'text' : 'password'}
|
|
185
|
+
autoComplete="current-password"
|
|
186
|
+
spellCheck={false}
|
|
187
|
+
ref={combinePasswordRef}
|
|
173
188
|
/>
|
|
174
|
-
|
|
189
|
+
<InputGroup.InnerEnd>
|
|
190
|
+
<Tooltip title={showPassword ? 'Hide Password' : 'Show Password'}>
|
|
191
|
+
<TertiaryButton
|
|
192
|
+
type="button"
|
|
193
|
+
size="small"
|
|
194
|
+
icon={showPassword ? visibleStrikethroughIcon : visibleIcon}
|
|
195
|
+
aria-controls={`input-${passwordId}`}
|
|
196
|
+
onClick={() => {
|
|
197
|
+
setShowPassword(state => !state);
|
|
198
|
+
passwordRef.current?.focus();
|
|
199
|
+
}}
|
|
200
|
+
/>
|
|
201
|
+
</Tooltip>
|
|
202
|
+
</InputGroup.InnerEnd>
|
|
203
|
+
</FormField.Field>
|
|
175
204
|
<FormField.Hint>{errors.password?.message || passwordHint}</FormField.Hint>
|
|
176
205
|
</FormField>
|
|
177
206
|
|
|
@@ -4,8 +4,24 @@ import Density from './examples/Density';
|
|
|
4
4
|
|
|
5
5
|
# Canvas Kit Density Examples
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
Canvas Kit does not ship a density system. Forms often still need compact, default, and
|
|
8
|
+
comfortable spacing. This example shows how to style Canvas Kit form elements with
|
|
9
|
+
`createStencil` to get three densities.
|
|
10
|
+
|
|
11
|
+
Density in this demo changes:
|
|
12
|
+
|
|
13
|
+
- **Input height and padding** (`system.size.sm` / `md` / `md + 4px`)
|
|
14
|
+
- **Label and input type** (`subtext.medium` / `subtext.large` / `body.small`)
|
|
15
|
+
- **Space between fields** (`system.gap.md` / `lg` / `xl`)
|
|
16
|
+
- **Space between a label and its input** (tighter when labels are vertical)
|
|
17
|
+
|
|
18
|
+
| Density | Input height | Field spacing | Type |
|
|
19
|
+
| ------- | ------------ | ------------- | ---- |
|
|
20
|
+
| High | 32px | 16px | `subtext.medium` |
|
|
21
|
+
| Medium | 40px | 24px | `subtext.large` |
|
|
22
|
+
| Low | 48px | 32px | `body.small` |
|
|
23
|
+
|
|
24
|
+
`Switch` does not expose a size API, so its dimensions stay the same across densities. Only its
|
|
25
|
+
label type and surrounding field spacing change.
|
|
10
26
|
|
|
11
27
|
<ExampleCodeBlock code={Density} />
|
|
@@ -1,30 +1,38 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {Switch} from '@workday/canvas-kit-preview-react/switch';
|
|
4
|
+
import {useUniqueId} from '@workday/canvas-kit-react/common';
|
|
5
|
+
import {FormField} from '@workday/canvas-kit-react/form-field';
|
|
4
6
|
import {SegmentedControl} from '@workday/canvas-kit-react/segmented-control';
|
|
5
7
|
import {Select} from '@workday/canvas-kit-react/select';
|
|
6
|
-
import {
|
|
7
|
-
import {Heading, Text} from '@workday/canvas-kit-react/text';
|
|
8
|
+
import {Heading, Subtext, Text} from '@workday/canvas-kit-react/text';
|
|
8
9
|
import {TextInput} from '@workday/canvas-kit-react/text-input';
|
|
9
10
|
import {calc, createStencil, createStyles, px2rem} from '@workday/canvas-kit-styling';
|
|
10
11
|
import {base, system} from '@workday/canvas-tokens-web';
|
|
11
12
|
|
|
13
|
+
type DensityLevel = 'high' | 'medium' | 'low';
|
|
14
|
+
type LabelOrientation = 'vertical' | 'horizontalStart' | 'horizontalEnd';
|
|
15
|
+
type ContainerAlignment = 'left' | 'center';
|
|
16
|
+
type DensityTypeLevel = 'subtext.medium' | 'subtext.large' | 'body.small';
|
|
17
|
+
|
|
18
|
+
const densitySummary: Record<
|
|
19
|
+
DensityLevel,
|
|
20
|
+
{inputHeight: string; stackGap: string; typeLevel: DensityTypeLevel}
|
|
21
|
+
> = {
|
|
22
|
+
high: {inputHeight: '32px', stackGap: '16px', typeLevel: 'subtext.medium'},
|
|
23
|
+
medium: {inputHeight: '40px', stackGap: '24px', typeLevel: 'subtext.large'},
|
|
24
|
+
low: {inputHeight: '48px', stackGap: '32px', typeLevel: 'body.small'},
|
|
25
|
+
};
|
|
26
|
+
|
|
12
27
|
const formStyles = createStyles({
|
|
13
28
|
margin: `${px2rem(12)} ${'0'}`,
|
|
14
29
|
maxWidth: px2rem(600),
|
|
15
30
|
minWidth: '0',
|
|
16
31
|
});
|
|
17
32
|
|
|
18
|
-
const formFieldGroupListStyles = createStyles({
|
|
19
|
-
display: 'inline-flex',
|
|
20
|
-
flexDirection: 'row',
|
|
21
|
-
flexWrap: 'wrap',
|
|
22
|
-
});
|
|
23
|
-
|
|
24
33
|
const sideBySideInputs = createStencil({
|
|
25
34
|
base: {
|
|
26
35
|
display: 'inline-flex',
|
|
27
|
-
gap: system.gap.sm,
|
|
28
36
|
justifyContent: 'space-between',
|
|
29
37
|
},
|
|
30
38
|
modifiers: {
|
|
@@ -39,52 +47,21 @@ const sideBySideInputs = createStencil({
|
|
|
39
47
|
},
|
|
40
48
|
vertical: {
|
|
41
49
|
display: 'inline-flex',
|
|
50
|
+
flexDirection: 'row',
|
|
42
51
|
},
|
|
43
52
|
},
|
|
44
53
|
density: {
|
|
45
|
-
high: {
|
|
46
|
-
medium: {},
|
|
47
|
-
low: {},
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
compound: [
|
|
51
|
-
{
|
|
52
|
-
modifiers: {labelOrientation: 'horizontalStart', density: 'high'},
|
|
53
|
-
styles: {
|
|
54
|
-
gap: system.gap.md,
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
modifiers: {labelOrientation: 'horizontalStart', density: 'medium'},
|
|
59
|
-
styles: {
|
|
60
|
-
gap: system.gap.lg,
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
modifiers: {labelOrientation: 'horizontalStart', density: 'low'},
|
|
65
|
-
styles: {
|
|
66
|
-
gap: system.gap.xl,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
modifiers: {labelOrientation: 'horizontalEnd', density: 'high'},
|
|
71
|
-
styles: {
|
|
54
|
+
high: {
|
|
72
55
|
gap: system.gap.md,
|
|
73
56
|
},
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
modifiers: {labelOrientation: 'horizontalEnd', density: 'medium'},
|
|
77
|
-
styles: {
|
|
57
|
+
medium: {
|
|
78
58
|
gap: system.gap.lg,
|
|
79
59
|
},
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
modifiers: {labelOrientation: 'horizontalEnd', density: 'low'},
|
|
83
|
-
styles: {
|
|
60
|
+
low: {
|
|
84
61
|
gap: system.gap.xl,
|
|
85
62
|
},
|
|
86
63
|
},
|
|
87
|
-
|
|
64
|
+
},
|
|
88
65
|
});
|
|
89
66
|
|
|
90
67
|
const zipCodeInput = createStyles({
|
|
@@ -96,7 +73,10 @@ const zipCodeContainerStyles = createStyles({
|
|
|
96
73
|
});
|
|
97
74
|
|
|
98
75
|
const formFieldStencil = createStencil({
|
|
99
|
-
base: {
|
|
76
|
+
base: {
|
|
77
|
+
// FormField's built-in margin would double-space with the stack gap below.
|
|
78
|
+
margin: 0,
|
|
79
|
+
},
|
|
100
80
|
modifiers: {
|
|
101
81
|
density: {
|
|
102
82
|
high: {
|
|
@@ -155,32 +135,6 @@ const formFieldStencil = createStencil({
|
|
|
155
135
|
],
|
|
156
136
|
});
|
|
157
137
|
|
|
158
|
-
const selectStencil = createStencil({
|
|
159
|
-
base: {},
|
|
160
|
-
modifiers: {
|
|
161
|
-
density: {
|
|
162
|
-
high: {
|
|
163
|
-
height: system.size.sm,
|
|
164
|
-
padding: `${system.padding.xxs} ${system.padding.xs}`,
|
|
165
|
-
'& + div': {
|
|
166
|
-
height: system.size.sm,
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
medium: {
|
|
170
|
-
height: system.size.md,
|
|
171
|
-
padding: `${system.padding.xs}`,
|
|
172
|
-
},
|
|
173
|
-
low: {
|
|
174
|
-
height: calc.add(system.size.md, base.size100),
|
|
175
|
-
padding: `${system.padding.sm} ${system.padding.xs}`,
|
|
176
|
-
'& + div': {
|
|
177
|
-
height: calc.add(system.size.md, base.size100),
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
|
|
184
138
|
const inputStencil = createStencil({
|
|
185
139
|
base: {
|
|
186
140
|
minWidth: px2rem(200),
|
|
@@ -190,29 +144,25 @@ const inputStencil = createStencil({
|
|
|
190
144
|
high: {
|
|
191
145
|
height: system.size.sm,
|
|
192
146
|
padding: `${system.padding.xxs} ${system.padding.xs}`,
|
|
147
|
+
fontSize: system.legacy.fontSize.subtext.md,
|
|
148
|
+
lineHeight: system.legacy.lineHeight.subtext.md,
|
|
193
149
|
},
|
|
194
150
|
medium: {
|
|
195
151
|
height: system.size.md,
|
|
196
152
|
padding: `${system.padding.xs}`,
|
|
153
|
+
fontSize: system.legacy.fontSize.subtext.lg,
|
|
154
|
+
lineHeight: system.legacy.lineHeight.subtext.lg,
|
|
197
155
|
},
|
|
198
|
-
|
|
199
156
|
low: {
|
|
200
157
|
height: calc.add(system.size.md, base.size100),
|
|
201
158
|
padding: `${system.padding.sm} ${system.padding.xs}`,
|
|
159
|
+
fontSize: system.legacy.fontSize.body.sm,
|
|
160
|
+
lineHeight: system.legacy.lineHeight.body.sm,
|
|
202
161
|
},
|
|
203
162
|
},
|
|
204
163
|
},
|
|
205
164
|
});
|
|
206
165
|
|
|
207
|
-
const creditCardInputStencil = createStencil({
|
|
208
|
-
extends: inputStencil,
|
|
209
|
-
base: {
|
|
210
|
-
width: calc.add(system.size.md, system.size.md),
|
|
211
|
-
minWidth: calc.add(system.size.md, system.size.md),
|
|
212
|
-
textAlign: 'center',
|
|
213
|
-
},
|
|
214
|
-
});
|
|
215
|
-
|
|
216
166
|
const flexContainerStencil = createStencil({
|
|
217
167
|
base: {
|
|
218
168
|
display: 'flex',
|
|
@@ -263,37 +213,44 @@ const optionItemStyles = createStyles({
|
|
|
263
213
|
maxWidth: 'fit-content',
|
|
264
214
|
});
|
|
265
215
|
|
|
266
|
-
// high = 32px height on inputs, space between inputs is 16px
|
|
267
|
-
// medium 40px height on inputs, space between inputs is 24px
|
|
268
|
-
// low = 48px height on inputs, space between inputs is 32px
|
|
269
|
-
|
|
270
216
|
export default () => {
|
|
271
|
-
const [density, setDensity] = React.useState<
|
|
272
|
-
const [containerAlignment, setContainerAlignment] = React.useState<
|
|
273
|
-
const [labelOrientation, setLabelOrientation] = React.useState<
|
|
274
|
-
|
|
275
|
-
|
|
217
|
+
const [density, setDensity] = React.useState<DensityLevel>('medium');
|
|
218
|
+
const [containerAlignment, setContainerAlignment] = React.useState<ContainerAlignment>('left');
|
|
219
|
+
const [labelOrientation, setLabelOrientation] = React.useState<LabelOrientation>('vertical');
|
|
220
|
+
const [fastShipping, setFastShipping] = React.useState(false);
|
|
221
|
+
const densityLabelId = useUniqueId();
|
|
222
|
+
const containerAlignmentLabelId = useUniqueId();
|
|
223
|
+
const labelOrientationLabelId = useUniqueId();
|
|
224
|
+
|
|
225
|
+
const handleDensity = (data: {id: string}) => {
|
|
226
|
+
setDensity(data.id as DensityLevel);
|
|
227
|
+
};
|
|
276
228
|
|
|
277
|
-
const
|
|
278
|
-
|
|
229
|
+
const handleContainerAlignment = (data: {id: string}) => {
|
|
230
|
+
setContainerAlignment(data.id as ContainerAlignment);
|
|
279
231
|
};
|
|
280
232
|
|
|
281
|
-
const
|
|
282
|
-
|
|
233
|
+
const handleLabelOrientation = (data: {id: string}) => {
|
|
234
|
+
setLabelOrientation(data.id as LabelOrientation);
|
|
283
235
|
};
|
|
284
236
|
|
|
285
|
-
const
|
|
286
|
-
|
|
237
|
+
const handleFastShipping = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
238
|
+
setFastShipping(event.target.checked);
|
|
287
239
|
};
|
|
288
240
|
|
|
241
|
+
const labelTypeLevel = densitySummary[density].typeLevel;
|
|
242
|
+
const fieldCs = formFieldStencil({density, labelOrientation});
|
|
243
|
+
const inputCs = inputStencil({density});
|
|
244
|
+
|
|
289
245
|
return (
|
|
290
|
-
|
|
291
|
-
<Heading size="small">Choose Your Density and Alignment</Heading>
|
|
246
|
+
<>
|
|
292
247
|
<div className={optionStyles}>
|
|
293
248
|
<div className={optionItemStyles}>
|
|
294
|
-
<Text>
|
|
295
|
-
|
|
296
|
-
|
|
249
|
+
<Text as="h3" id={densityLabelId}>
|
|
250
|
+
Density
|
|
251
|
+
</Text>
|
|
252
|
+
<SegmentedControl initialValue={density} onSelect={handleDensity} size="small">
|
|
253
|
+
<SegmentedControl.List aria-label="Density" aria-labelledby={densityLabelId}>
|
|
297
254
|
<SegmentedControl.Item data-id="high">High</SegmentedControl.Item>
|
|
298
255
|
<SegmentedControl.Item data-id="medium">Medium</SegmentedControl.Item>
|
|
299
256
|
<SegmentedControl.Item data-id="low">Low</SegmentedControl.Item>
|
|
@@ -301,9 +258,18 @@ export default () => {
|
|
|
301
258
|
</SegmentedControl>
|
|
302
259
|
</div>
|
|
303
260
|
<div className={optionItemStyles}>
|
|
304
|
-
<Text
|
|
305
|
-
|
|
306
|
-
|
|
261
|
+
<Text as="h3" id={labelOrientationLabelId}>
|
|
262
|
+
Label Orientation
|
|
263
|
+
</Text>
|
|
264
|
+
<SegmentedControl
|
|
265
|
+
initialValue={labelOrientation}
|
|
266
|
+
onSelect={handleLabelOrientation}
|
|
267
|
+
size="small"
|
|
268
|
+
>
|
|
269
|
+
<SegmentedControl.List
|
|
270
|
+
aria-label="Label Orientation"
|
|
271
|
+
aria-labelledby={labelOrientationLabelId}
|
|
272
|
+
>
|
|
307
273
|
<SegmentedControl.Item data-id="vertical">Vertical</SegmentedControl.Item>
|
|
308
274
|
<SegmentedControl.Item data-id="horizontalStart">
|
|
309
275
|
Horizontal Start
|
|
@@ -313,131 +279,92 @@ export default () => {
|
|
|
313
279
|
</SegmentedControl>
|
|
314
280
|
</div>
|
|
315
281
|
<div className={optionItemStyles}>
|
|
316
|
-
<Text
|
|
317
|
-
|
|
318
|
-
|
|
282
|
+
<Text as="h3" id={containerAlignmentLabelId}>
|
|
283
|
+
Container Alignment
|
|
284
|
+
</Text>
|
|
285
|
+
<SegmentedControl
|
|
286
|
+
initialValue={containerAlignment}
|
|
287
|
+
onSelect={handleContainerAlignment}
|
|
288
|
+
size="small"
|
|
289
|
+
>
|
|
290
|
+
<SegmentedControl.List
|
|
291
|
+
aria-label="Container Alignment"
|
|
292
|
+
aria-labelledby={containerAlignmentLabelId}
|
|
293
|
+
>
|
|
319
294
|
<SegmentedControl.Item data-id="left">Left</SegmentedControl.Item>
|
|
320
295
|
<SegmentedControl.Item data-id="center">Center</SegmentedControl.Item>
|
|
321
296
|
</SegmentedControl.List>
|
|
322
297
|
</SegmentedControl>
|
|
323
298
|
</div>
|
|
299
|
+
<Subtext size="large">
|
|
300
|
+
Input height: {densitySummary[density].inputHeight}. Field spacing:{' '}
|
|
301
|
+
{densitySummary[density].stackGap}. Type: {densitySummary[density].typeLevel}.
|
|
302
|
+
</Subtext>
|
|
324
303
|
</div>
|
|
325
304
|
|
|
326
305
|
<div {...containerAlignmentStencil({alignment: containerAlignment})}>
|
|
327
|
-
<form
|
|
306
|
+
<form className={formStyles} autoComplete="off">
|
|
307
|
+
<Heading size="small">Shipping Address</Heading>
|
|
328
308
|
<div {...flexContainerStencil({density})}>
|
|
329
|
-
<FormField
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
cs={formFieldStencil({density, labelOrientation})}
|
|
333
|
-
id="foo"
|
|
334
|
-
>
|
|
335
|
-
<FormField.Label>Choose Country</FormField.Label>
|
|
336
|
-
<Select items={['Dominican Republic', 'Spain', 'United States']}>
|
|
337
|
-
<FormField.Input
|
|
338
|
-
cs={selectStencil({density})}
|
|
339
|
-
placeholder="Choose a country"
|
|
340
|
-
as={Select.Input}
|
|
341
|
-
/>
|
|
342
|
-
<Select.Popper>
|
|
343
|
-
<Select.Card>
|
|
344
|
-
<Select.List>{item => <Select.Item>{item}</Select.Item>}</Select.List>
|
|
345
|
-
</Select.Card>
|
|
346
|
-
</Select.Popper>
|
|
347
|
-
</Select>
|
|
348
|
-
</FormField>
|
|
349
|
-
<FormField
|
|
350
|
-
grow
|
|
351
|
-
orientation={labelOrientation}
|
|
352
|
-
cs={formFieldStencil({density, labelOrientation})}
|
|
353
|
-
>
|
|
354
|
-
<FormField.Label>Full Name</FormField.Label>
|
|
355
|
-
<FormField.Input as={TextInput} cs={inputStencil({density})} />
|
|
309
|
+
<FormField grow orientation={labelOrientation} cs={fieldCs}>
|
|
310
|
+
<FormField.Label typeLevel={labelTypeLevel}>Full Name</FormField.Label>
|
|
311
|
+
<FormField.Input as={TextInput} autoComplete="name" cs={inputCs} />
|
|
356
312
|
</FormField>
|
|
357
|
-
<
|
|
358
|
-
grow
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
<FormField
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
<FormField.Label>Street Address</FormField.Label>
|
|
371
|
-
<FormField.Input as={TextInput} cs={inputStencil({density})} />
|
|
372
|
-
</FormField>
|
|
373
|
-
<FormField
|
|
374
|
-
grow
|
|
375
|
-
orientation={labelOrientation}
|
|
376
|
-
cs={formFieldStencil({density, labelOrientation})}
|
|
377
|
-
>
|
|
378
|
-
<FormField.Label>City</FormField.Label>
|
|
379
|
-
<FormField.Input as={TextInput} cs={inputStencil({density})} />
|
|
313
|
+
<div {...sideBySideInputs({labelOrientation, density})}>
|
|
314
|
+
<FormField grow orientation={labelOrientation} cs={fieldCs}>
|
|
315
|
+
<FormField.Label typeLevel={labelTypeLevel}>Phone Number</FormField.Label>
|
|
316
|
+
<FormField.Input as={TextInput} autoComplete="tel" cs={inputCs} />
|
|
317
|
+
</FormField>
|
|
318
|
+
<FormField grow orientation={labelOrientation} cs={fieldCs}>
|
|
319
|
+
<FormField.Label typeLevel={labelTypeLevel}>Email</FormField.Label>
|
|
320
|
+
<FormField.Input as={TextInput} autoComplete="email" cs={inputCs} />
|
|
321
|
+
</FormField>
|
|
322
|
+
</div>
|
|
323
|
+
<FormField grow orientation={labelOrientation} cs={fieldCs}>
|
|
324
|
+
<FormField.Label typeLevel={labelTypeLevel}>Street Address</FormField.Label>
|
|
325
|
+
<FormField.Input as={TextInput} autoComplete="street-address" cs={inputCs} />
|
|
380
326
|
</FormField>
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
cs={
|
|
386
|
-
>
|
|
387
|
-
<FormField.Label>State</FormField.Label>
|
|
388
|
-
<FormField.Input as={TextInput} cs={inputStencil({density})} />
|
|
327
|
+
|
|
328
|
+
<div {...sideBySideInputs({labelOrientation, density})}>
|
|
329
|
+
<FormField grow orientation={labelOrientation} cs={fieldCs}>
|
|
330
|
+
<FormField.Label typeLevel={labelTypeLevel}>City</FormField.Label>
|
|
331
|
+
<FormField.Input as={TextInput} autoComplete="address-level2" cs={inputCs} />
|
|
389
332
|
</FormField>
|
|
390
|
-
<FormField
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
>
|
|
395
|
-
<FormField.Label>Zip Code</FormField.Label>
|
|
396
|
-
<FormField.Input
|
|
333
|
+
<FormField grow orientation={labelOrientation} cs={fieldCs}>
|
|
334
|
+
<FormField.Label typeLevel={labelTypeLevel}>State</FormField.Label>
|
|
335
|
+
<FormField.Input as={TextInput} autoComplete="address-level1" cs={inputCs} />
|
|
336
|
+
</FormField>
|
|
337
|
+
<FormField grow orientation={labelOrientation} cs={[fieldCs, zipCodeContainerStyles]}>
|
|
338
|
+
<FormField.Label typeLevel={labelTypeLevel}>Zip Code</FormField.Label>
|
|
339
|
+
<FormField.Input
|
|
340
|
+
cs={[inputCs, zipCodeInput]}
|
|
341
|
+
as={TextInput}
|
|
342
|
+
autoComplete="postal-code"
|
|
343
|
+
/>
|
|
397
344
|
</FormField>
|
|
398
345
|
</div>
|
|
399
|
-
<FormField
|
|
400
|
-
|
|
401
|
-
cs={formFieldStencil({density, labelOrientation})}
|
|
402
|
-
>
|
|
403
|
-
<FormField.Label>Enable Fast Shipping</FormField.Label>
|
|
346
|
+
<FormField grow orientation={labelOrientation} cs={fieldCs}>
|
|
347
|
+
<FormField.Label typeLevel={labelTypeLevel}>Country</FormField.Label>
|
|
404
348
|
<FormField.Field>
|
|
405
|
-
<
|
|
349
|
+
<Select items={['Dominican Republic', 'Spain', 'United States']}>
|
|
350
|
+
<FormField.Input cs={inputCs} placeholder="Choose a country" as={Select.Input} />
|
|
351
|
+
<Select.Popper>
|
|
352
|
+
<Select.Card>
|
|
353
|
+
<Select.List>{item => <Select.Item>{item}</Select.Item>}</Select.List>
|
|
354
|
+
</Select.Card>
|
|
355
|
+
</Select.Popper>
|
|
356
|
+
</Select>
|
|
357
|
+
</FormField.Field>
|
|
358
|
+
</FormField>
|
|
359
|
+
<FormField orientation={labelOrientation} cs={fieldCs}>
|
|
360
|
+
<FormField.Label typeLevel={labelTypeLevel}>Enable Fast Shipping</FormField.Label>
|
|
361
|
+
<FormField.Field>
|
|
362
|
+
<FormField.Input as={Switch} checked={fastShipping} onChange={handleFastShipping} />
|
|
406
363
|
</FormField.Field>
|
|
407
364
|
</FormField>
|
|
408
|
-
<FormFieldGroup
|
|
409
|
-
cs={formFieldStencil({density, labelOrientation})}
|
|
410
|
-
orientation={labelOrientation}
|
|
411
|
-
>
|
|
412
|
-
<FormFieldGroup.Label>Credit Card</FormFieldGroup.Label>
|
|
413
|
-
<FormFieldGroup.Field>
|
|
414
|
-
<FormFieldGroup.List cs={formFieldGroupListStyles}>
|
|
415
|
-
<FormFieldGroup.Input
|
|
416
|
-
as={TextInput}
|
|
417
|
-
placeholder="XXXX"
|
|
418
|
-
cs={creditCardInputStencil({density})}
|
|
419
|
-
/>
|
|
420
|
-
<FormFieldGroup.Input
|
|
421
|
-
as={TextInput}
|
|
422
|
-
placeholder="XXXX"
|
|
423
|
-
cs={creditCardInputStencil({density})}
|
|
424
|
-
/>
|
|
425
|
-
<FormFieldGroup.Input
|
|
426
|
-
as={TextInput}
|
|
427
|
-
placeholder="XXXX"
|
|
428
|
-
cs={creditCardInputStencil({density})}
|
|
429
|
-
/>
|
|
430
|
-
<FormFieldGroup.Input
|
|
431
|
-
cs={creditCardInputStencil({density})}
|
|
432
|
-
placeholder="XXXX"
|
|
433
|
-
as={TextInput}
|
|
434
|
-
/>
|
|
435
|
-
</FormFieldGroup.List>
|
|
436
|
-
</FormFieldGroup.Field>
|
|
437
|
-
</FormFieldGroup>
|
|
438
365
|
</div>
|
|
439
366
|
</form>
|
|
440
367
|
</div>
|
|
441
|
-
|
|
368
|
+
</>
|
|
442
369
|
);
|
|
443
370
|
};
|
|
@@ -6,7 +6,7 @@ import {system} from '@workday/canvas-tokens-web';
|
|
|
6
6
|
|
|
7
7
|
// Extend Heading Props and omitting size since we've added a default
|
|
8
8
|
interface CardHeadingProps extends Omit<ExtractProps<typeof Heading>, 'size'> {}
|
|
9
|
-
export
|
|
9
|
+
export default createComponent('h2')({
|
|
10
10
|
displayName: 'CardHeading',
|
|
11
11
|
Component: ({children, ...elemProps}: CardHeadingProps, ref, Element) => {
|
|
12
12
|
return (
|
|
@@ -19,7 +19,7 @@ export const CardHeading = createComponent('h2')({
|
|
|
19
19
|
|
|
20
20
|
// Extend Box Props for customization
|
|
21
21
|
interface CardProps extends BoxProps {}
|
|
22
|
-
export
|
|
22
|
+
export default createComponent('div')({
|
|
23
23
|
displayName: 'Card',
|
|
24
24
|
subComponents: {
|
|
25
25
|
Heading: CardHeading,
|
|
@@ -39,7 +39,7 @@ const cardStyles = createStyles({
|
|
|
39
39
|
padding: system.padding.sm,
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
export
|
|
42
|
+
export default () => {
|
|
43
43
|
return (
|
|
44
44
|
<Card cs={cardStyles} as="section">
|
|
45
45
|
<Card.Heading>Card Heading</Card.Heading>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workday/canvas-kit-docs",
|
|
3
|
-
"version": "17.0.0-alpha.
|
|
3
|
+
"version": "17.0.0-alpha.0616-next.0",
|
|
4
4
|
"description": "Documentation components of Canvas Kit components",
|
|
5
5
|
"author": "Workday, Inc. (https://www.workday.com)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"@stackblitz/sdk": "^1.11.0",
|
|
48
48
|
"@storybook/csf": "0.0.1",
|
|
49
49
|
"@workday/canvas-expressive-icons-web": "1.0.2",
|
|
50
|
-
"@workday/canvas-kit-labs-react": "^17.0.0-alpha.
|
|
51
|
-
"@workday/canvas-kit-preview-react": "^17.0.0-alpha.
|
|
52
|
-
"@workday/canvas-kit-react": "^17.0.0-alpha.
|
|
53
|
-
"@workday/canvas-kit-styling": "^17.0.0-alpha.
|
|
50
|
+
"@workday/canvas-kit-labs-react": "^17.0.0-alpha.0616-next.0",
|
|
51
|
+
"@workday/canvas-kit-preview-react": "^17.0.0-alpha.0616-next.0",
|
|
52
|
+
"@workday/canvas-kit-react": "^17.0.0-alpha.0616-next.0",
|
|
53
|
+
"@workday/canvas-kit-styling": "^17.0.0-alpha.0616-next.0",
|
|
54
54
|
"@workday/canvas-system-icons-web": "^5.0.3",
|
|
55
55
|
"@workday/canvas-tokens-web": "^4.4.0",
|
|
56
56
|
"markdown-to-jsx": "^7.2.0",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"mkdirp": "^1.0.3",
|
|
64
64
|
"typescript": "5.0"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "593c0f1f5ee5047c7bea41027f76716a0f42caee"
|
|
67
67
|
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import {useFormik} from 'formik';
|
|
2
|
-
|
|
3
|
-
import {PrimaryButton} from '@workday/canvas-kit-react/button';
|
|
4
|
-
import {FormField} from '@workday/canvas-kit-react/form-field';
|
|
5
|
-
import {Flex} from '@workday/canvas-kit-react/layout';
|
|
6
|
-
import {Select, useSelectModel} from '@workday/canvas-kit-react/select';
|
|
7
|
-
import {px2rem} from '@workday/canvas-kit-styling';
|
|
8
|
-
import {cloudArrowUpIcon, cloudIcon, commentIcon, userIcon} from '@workday/canvas-system-icons-web';
|
|
9
|
-
import {system} from '@workday/canvas-tokens-web';
|
|
10
|
-
|
|
11
|
-
export default [
|
|
12
|
-
{
|
|
13
|
-
label: 'Dessert Person by Claire Saffitz',
|
|
14
|
-
serverId: 1,
|
|
15
|
-
icon: commentIcon,
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
label: 'Elements of Pizza by Ken Forkish',
|
|
19
|
-
serverId: 2,
|
|
20
|
-
icon: cloudIcon,
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
label: 'Flour Water Salt Yeast by Ken Forkish',
|
|
24
|
-
serverId: 3,
|
|
25
|
-
icon: cloudArrowUpIcon,
|
|
26
|
-
},
|
|
27
|
-
{label: 'Mastering Pasta by Marc Verti', serverId: 4, icon: userIcon},
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
export default () => {
|
|
31
|
-
const formik = useFormik({
|
|
32
|
-
initialValues: {
|
|
33
|
-
selectedBook: '',
|
|
34
|
-
},
|
|
35
|
-
onSubmit: values => {
|
|
36
|
-
// Send data to server
|
|
37
|
-
setTimeout(() => {
|
|
38
|
-
alert(JSON.stringify(values, null, 2));
|
|
39
|
-
}, 0);
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const selectModel = useSelectModel({
|
|
44
|
-
items: customOptionsMain,
|
|
45
|
-
getId: item => {
|
|
46
|
-
return item.serverId;
|
|
47
|
-
},
|
|
48
|
-
getTextValue: item => item.label,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<form onSubmit={formik.handleSubmit} action=".">
|
|
53
|
-
<Flex cs={{gap: system.gap.sm, flexDirection: 'column', alignItems: 'flex-start'}}>
|
|
54
|
-
<FormField orientation="vertical" cs={{alignSelf: 'stretch', alignItems: 'normal'}}>
|
|
55
|
-
<Select model={selectModel}>
|
|
56
|
-
<FormField.Label>Choose a book</FormField.Label>
|
|
57
|
-
<FormField.Input
|
|
58
|
-
as={Select.Input}
|
|
59
|
-
name="selectedBook"
|
|
60
|
-
onChange={event => formik.setFieldValue('selectedBook', event.currentTarget.value)}
|
|
61
|
-
value={formik.values.selectedBook}
|
|
62
|
-
grow
|
|
63
|
-
/>
|
|
64
|
-
<Select.Popper>
|
|
65
|
-
<Select.Card>
|
|
66
|
-
<Select.List cs={{maxHeight: px2rem(200)}}>
|
|
67
|
-
{item => {
|
|
68
|
-
return (
|
|
69
|
-
<Select.Item data-id={item.serverId} data-text={item.label}>
|
|
70
|
-
<Select.Item.Icon icon={item.icon} />
|
|
71
|
-
{item.label}
|
|
72
|
-
</Select.Item>
|
|
73
|
-
);
|
|
74
|
-
}}
|
|
75
|
-
</Select.List>
|
|
76
|
-
</Select.Card>
|
|
77
|
-
</Select.Popper>
|
|
78
|
-
</Select>
|
|
79
|
-
</FormField>
|
|
80
|
-
<PrimaryButton type="submit">Submit</PrimaryButton>
|
|
81
|
-
</Flex>
|
|
82
|
-
</form>
|
|
83
|
-
);
|
|
84
|
-
};
|