@workday/canvas-kit-docs 5.3.0-next.11 → 5.3.0-next.18
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/LICENSE +1 -1
- package/dist/commonjs/lib/specs.js +263 -33
- package/dist/es6/lib/specs.js +263 -33
- package/dist/mdx/6.0-MIGRATION-GUIDE.mdx +259 -1
- package/dist/mdx/COMPOUND_COMPONENTS.mdx +31 -30
- package/dist/mdx/preview-react/breadcrumbs/Breadcrumbs.mdx +1 -1
- package/dist/mdx/preview-react/form-field/FormField.mdx +27 -0
- package/dist/mdx/preview-react/form-field/examples/Custom.tsx +57 -0
- package/dist/mdx/preview-react/menu/examples/Icons.tsx +1 -1
- package/dist/mdx/preview-react/menu/examples/ManyItems.tsx +1 -1
- package/dist/mdx/preview-react/text-area/TextArea.mdx +122 -0
- package/dist/mdx/preview-react/text-area/examples/Alert.tsx +31 -0
- package/dist/mdx/preview-react/text-area/examples/Basic.tsx +17 -0
- package/dist/mdx/preview-react/text-area/examples/Disabled.tsx +17 -0
- package/dist/mdx/preview-react/text-area/examples/Error.tsx +40 -0
- package/dist/mdx/preview-react/text-area/examples/Grow.tsx +17 -0
- package/dist/mdx/preview-react/text-area/examples/HiddenLabel.tsx +20 -0
- package/dist/mdx/preview-react/text-area/examples/LabelPositionHorizontal.tsx +17 -0
- package/dist/mdx/preview-react/text-area/examples/LabelPositionVertical.tsx +17 -0
- package/dist/mdx/preview-react/text-area/examples/Placeholder.tsx +21 -0
- package/dist/mdx/preview-react/text-area/examples/RefForwarding.tsx +28 -0
- package/dist/mdx/preview-react/text-area/examples/Required.tsx +17 -0
- package/dist/mdx/preview-react/text-area/examples/ResizeConstraints.tsx +22 -0
- package/dist/mdx/{labs-react → preview-react}/text-input/TextInput.mdx +40 -18
- package/dist/mdx/preview-react/text-input/examples/Alert.tsx +40 -0
- package/dist/mdx/{labs-react/text-input/examples/HiddenLabel.tsx → preview-react/text-input/examples/Basic.tsx} +3 -3
- package/dist/mdx/preview-react/text-input/examples/Disabled.tsx +17 -0
- package/dist/mdx/{labs-react → preview-react}/text-input/examples/Error.tsx +6 -9
- package/dist/mdx/preview-react/text-input/examples/Grow.tsx +17 -0
- package/dist/mdx/preview-react/text-input/examples/HiddenLabel.tsx +20 -0
- package/dist/mdx/preview-react/text-input/examples/LabelPositionHorizontal.tsx +17 -0
- package/dist/mdx/preview-react/text-input/examples/LabelPositionVertical.tsx +17 -0
- package/dist/mdx/{labs-react → preview-react}/text-input/examples/LoginForm.tsx +10 -5
- package/dist/mdx/preview-react/text-input/examples/Password.tsx +17 -0
- package/dist/mdx/preview-react/text-input/examples/Placeholder.tsx +17 -0
- package/dist/mdx/{labs-react → preview-react}/text-input/examples/RefForwarding.tsx +7 -6
- package/dist/mdx/preview-react/text-input/examples/Required.tsx +17 -0
- package/dist/mdx/preview-react/text-input/examples/ThemedAlert.tsx +46 -0
- package/dist/mdx/{labs-react → preview-react}/text-input/examples/ThemedError.tsx +8 -11
- package/dist/mdx/react/action-bar/ActionBar.mdx +1 -1
- package/dist/mdx/react/button/button/Button.mdx +34 -9
- package/dist/mdx/react/button/button/examples/Primary.tsx +10 -1
- package/dist/mdx/react/button/button/examples/PrimaryInverse.tsx +14 -0
- package/dist/mdx/react/button/button/examples/Secondary.tsx +10 -1
- package/dist/mdx/react/button/button/examples/SecondaryInverse.tsx +14 -0
- package/dist/mdx/react/button/button/examples/Tertiary.tsx +10 -1
- package/dist/mdx/react/button/button/examples/TertiaryInverse.tsx +14 -0
- package/dist/mdx/react/button/icon-button/IconButton.mdx +1 -1
- package/dist/mdx/react/pagination/pagination.mdx +5 -3
- package/dist/mdx/react/popup/Popup.mdx +34 -36
- package/dist/mdx/react/radio/examples/Alert.tsx +3 -3
- package/dist/mdx/react/radio/examples/Basic.tsx +3 -3
- package/dist/mdx/react/radio/examples/Disabled.tsx +3 -3
- package/dist/mdx/react/radio/examples/Error.tsx +3 -3
- package/dist/mdx/react/radio/examples/LabelPosition.tsx +3 -3
- package/dist/mdx/react/radio/examples/NoValue.tsx +3 -3
- package/dist/mdx/react/radio/examples/RefForwarding.tsx +3 -3
- package/dist/mdx/react/radio/examples/Required.tsx +3 -3
- package/dist/mdx/react/segmented-control/SegmentedControl.mdx +1 -1
- package/dist/mdx/react/tabs/Tabs.mdx +67 -36
- package/dist/mdx/react/tabs/examples/DisabledTab.tsx +1 -1
- package/dist/mdx/react/tabs/examples/DynamicTabs.tsx +41 -13
- package/dist/mdx/react/tabs/examples/HoistedModel.tsx +4 -4
- package/dist/mdx/react/tabs/examples/Icons.tsx +36 -0
- package/dist/mdx/react/tabs/examples/{NamedKeys.tsx → NamedTabs.tsx} +0 -0
- package/dist/mdx/react/tabs/examples/OverflowTabs.tsx +58 -0
- package/dist/mdx/react/tabs/examples/SinglePanel.tsx +1 -1
- package/dist/mdx/react/toast/toast.mdx +1 -17
- package/dist/mdx/react/tooltip/Tooltip.mdx +1 -1
- package/dist/mdx/react/tooltip/examples/Ellipsis.tsx +6 -0
- package/package.json +3 -3
- package/dist/mdx/labs-react/text-input/examples/Alert.tsx +0 -46
- package/dist/mdx/labs-react/text-input/examples/Basic.tsx +0 -20
- package/dist/mdx/labs-react/text-input/examples/Disabled.tsx +0 -20
- package/dist/mdx/labs-react/text-input/examples/Grow.tsx +0 -20
- package/dist/mdx/labs-react/text-input/examples/LabelPosition.tsx +0 -20
- package/dist/mdx/labs-react/text-input/examples/Password.tsx +0 -20
- package/dist/mdx/labs-react/text-input/examples/Placeholder.tsx +0 -20
- package/dist/mdx/labs-react/text-input/examples/Required.tsx +0 -20
- package/dist/mdx/labs-react/text-input/examples/ThemedAlert.tsx +0 -51
|
@@ -10,11 +10,11 @@ export default () => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<FormField label="Choose
|
|
13
|
+
<FormField label="Choose Your Pizza Crust" useFieldset={true}>
|
|
14
14
|
<RadioGroup name="crust" onChange={handleChange} value={value}>
|
|
15
|
-
<Radio label="Deep
|
|
15
|
+
<Radio label="Deep dish" value="deep-dish" />
|
|
16
16
|
<Radio label="Thin" value="thin" />
|
|
17
|
-
<Radio label="Gluten
|
|
17
|
+
<Radio label="Gluten free" value="gluten-free" />
|
|
18
18
|
<Radio label="Cauliflower" value="cauliflower" />
|
|
19
19
|
</RadioGroup>
|
|
20
20
|
</FormField>
|
|
@@ -10,11 +10,11 @@ export default () => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<FormField label="Choose
|
|
13
|
+
<FormField label="Choose Your Pizza Crust" useFieldset={true}>
|
|
14
14
|
<RadioGroup name="crust" onChange={handleChange} value={value}>
|
|
15
|
-
<Radio label="Deep
|
|
15
|
+
<Radio label="Deep dish" value="deep-dish" />
|
|
16
16
|
<Radio label="Thin" value="thin" />
|
|
17
|
-
<Radio disabled={true} label="Gluten
|
|
17
|
+
<Radio disabled={true} label="Gluten free (sold out)" value="gluten-free" />
|
|
18
18
|
<Radio label="Cauliflower" value="cauliflower" />
|
|
19
19
|
</RadioGroup>
|
|
20
20
|
</FormField>
|
|
@@ -14,13 +14,13 @@ export default () => {
|
|
|
14
14
|
error={FormField.ErrorType.Error}
|
|
15
15
|
hintId="hint-error"
|
|
16
16
|
hintText="Deep Dish is no longer available. Please select a different crust."
|
|
17
|
-
label="Choose
|
|
17
|
+
label="Choose Your Pizza Crust"
|
|
18
18
|
useFieldset={true}
|
|
19
19
|
>
|
|
20
20
|
<RadioGroup name="crust" onChange={handleChange} value={value}>
|
|
21
|
-
<Radio disabled={true} label="Deep
|
|
21
|
+
<Radio disabled={true} label="Deep dish (sold out)" value="deep-dish" />
|
|
22
22
|
<Radio label="Thin" value="thin" />
|
|
23
|
-
<Radio label="Gluten
|
|
23
|
+
<Radio label="Gluten free" value="gluten-free" />
|
|
24
24
|
<Radio label="Cauliflower" value="cauliflower" />
|
|
25
25
|
</RadioGroup>
|
|
26
26
|
</FormField>
|
|
@@ -11,14 +11,14 @@ export default () => {
|
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
13
|
<FormField
|
|
14
|
-
label="Choose
|
|
14
|
+
label="Choose Your Pizza Crust"
|
|
15
15
|
labelPosition={FormField.LabelPosition.Left}
|
|
16
16
|
useFieldset={true}
|
|
17
17
|
>
|
|
18
18
|
<RadioGroup name="crust" onChange={handleChange} value={value}>
|
|
19
|
-
<Radio label="Deep
|
|
19
|
+
<Radio label="Deep dish" value="deep-dish" />
|
|
20
20
|
<Radio label="Thin" value="thin" />
|
|
21
|
-
<Radio label="Gluten
|
|
21
|
+
<Radio label="Gluten free" value="gluten-free" />
|
|
22
22
|
<Radio label="Cauliflower" value="cauliflower" />
|
|
23
23
|
</RadioGroup>
|
|
24
24
|
</FormField>
|
|
@@ -12,11 +12,11 @@ export default () => {
|
|
|
12
12
|
|
|
13
13
|
return (
|
|
14
14
|
<>
|
|
15
|
-
<FormField label="Choose
|
|
15
|
+
<FormField label="Choose Your Pizza Crust" useFieldset={true}>
|
|
16
16
|
<RadioGroup name="crust" onChange={handleChange} value={value}>
|
|
17
|
-
<Radio label="Deep
|
|
17
|
+
<Radio label="Deep dish" />
|
|
18
18
|
<Radio label="Thin" />
|
|
19
|
-
<Radio label="Gluten
|
|
19
|
+
<Radio label="Gluten free" />
|
|
20
20
|
<Radio label="Cauliflower" />
|
|
21
21
|
</RadioGroup>
|
|
22
22
|
</FormField>
|
|
@@ -17,11 +17,11 @@ export default () => {
|
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
19
|
<>
|
|
20
|
-
<FormField label="Choose
|
|
20
|
+
<FormField label="Choose Your Pizza Crust" useFieldset={true}>
|
|
21
21
|
<RadioGroup name="crust" onChange={handleChange} value={value}>
|
|
22
|
-
<Radio label="Deep
|
|
22
|
+
<Radio label="Deep dish" value="deep-dish" />
|
|
23
23
|
<Radio label="Thin" value="thin" />
|
|
24
|
-
<Radio label="Gluten
|
|
24
|
+
<Radio label="Gluten free" ref={glutenFreeRef} value="gluten-free" />
|
|
25
25
|
<Radio label="Cauliflower" value="cauliflower" />
|
|
26
26
|
</RadioGroup>
|
|
27
27
|
</FormField>
|
|
@@ -10,11 +10,11 @@ export default () => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<FormField label="Choose
|
|
13
|
+
<FormField label="Choose Your Pizza Crust" required={true} useFieldset={true}>
|
|
14
14
|
<RadioGroup name="crust" onChange={handleChange} value={value}>
|
|
15
|
-
<Radio label="Deep
|
|
15
|
+
<Radio label="Deep dish" value="deep-dish" />
|
|
16
16
|
<Radio label="Thin" value="thin" />
|
|
17
|
-
<Radio label="Gluten
|
|
17
|
+
<Radio label="Gluten free" value="gluten-free" />
|
|
18
18
|
<Radio label="Cauliflower" value="cauliflower" />
|
|
19
19
|
</RadioGroup>
|
|
20
20
|
</FormField>
|
|
@@ -27,6 +27,6 @@ indexes and omit the `value` field. It is strongly recommended to not mix these
|
|
|
27
27
|
|
|
28
28
|
## Props
|
|
29
29
|
|
|
30
|
-
Undocumented props are spread to the underlying container
|
|
30
|
+
Undocumented props are spread to the underlying container `<div>` element.
|
|
31
31
|
|
|
32
32
|
<ArgsTable of={SegmentedControl} />
|
|
@@ -2,9 +2,11 @@ import {Tabs} from '@workday/canvas-kit-react/tabs';
|
|
|
2
2
|
import {Specifications} from '@workday/canvas-kit-docs';
|
|
3
3
|
|
|
4
4
|
import Basic from './examples/Basic';
|
|
5
|
-
import
|
|
5
|
+
import NamedTabs from './examples/NamedTabs';
|
|
6
6
|
import RightToLeft from './examples/RightToLeft';
|
|
7
|
+
import OverflowTabs from './examples/OverflowTabs';
|
|
7
8
|
import DisabledTab from './examples/DisabledTab';
|
|
9
|
+
import Icons from './examples/Icons';
|
|
8
10
|
import SinglePanel from './examples/SinglePanel';
|
|
9
11
|
import AlternativeTabStop from './examples/AlternativeTabStop';
|
|
10
12
|
import HoistedModel from './examples/HoistedModel';
|
|
@@ -19,8 +21,8 @@ import {
|
|
|
19
21
|
# Canvas Kit Tabs
|
|
20
22
|
|
|
21
23
|
`Tabs` is a [compound component](/getting-started/for-developers/resources/compound-components/)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
that allows users to navigate between related views of content while remaining in context of the
|
|
25
|
+
page.
|
|
24
26
|
|
|
25
27
|
[> Workday Design Reference](https://design.workday.com/components/navigation/tabs)
|
|
26
28
|
|
|
@@ -34,34 +36,54 @@ yarn add @workday/canvas-kit-react
|
|
|
34
36
|
|
|
35
37
|
### Basic Example
|
|
36
38
|
|
|
37
|
-
`Tabs` includes a container `Tabs` component and the following subcomponents
|
|
38
|
-
`Tabs.Item` and `Tabs.Panel`.
|
|
39
|
+
`Tabs` includes a container `Tabs` component and the following subcomponents which can be composed
|
|
40
|
+
in a variety of ways: `Tabs.List`, `Tabs.Item` and `Tabs.Panel`. It follows the
|
|
41
|
+
[W3 Tabs specification](https://www.w3.org/TR/wai-aria-practices/#tabpanel).
|
|
42
|
+
|
|
43
|
+
In this example, we set up a basic `Tabs` component with five tabs. This example uses a static API
|
|
44
|
+
that does not support overflow.
|
|
39
45
|
|
|
40
46
|
<ExampleCodeBlock code={Basic} />
|
|
41
47
|
|
|
48
|
+
### Overflow Tabs
|
|
49
|
+
|
|
50
|
+
Tabs is a responsive component based on the width of its container. If the rendered tabs exceed the
|
|
51
|
+
width of the `Tabs.List`, an overflow menu will be rendered. This only works against the dynamic API
|
|
52
|
+
where you give the `TabsModel` an array of items to be rendered. The dynamic API handles the React
|
|
53
|
+
`key` for you based on the item's identifier. The dynamic API requires either an `id` on each item
|
|
54
|
+
object or a `getId` function that returns an identifier based on the item. The below example uses an
|
|
55
|
+
`id` property on each item.
|
|
56
|
+
|
|
57
|
+
The dynamic API takes in any object, but since nothing is known about your object, a
|
|
58
|
+
[render prop](https://reactjs.org/docs/render-props.html) is necessary to instruct a list how it
|
|
59
|
+
should render.
|
|
60
|
+
|
|
61
|
+
<ExampleCodeBlock code={OverflowTabs} />
|
|
62
|
+
|
|
42
63
|
### Hoisted Model
|
|
43
64
|
|
|
44
65
|
By default, `Tabs` will create and use its own [model](#model) internally. Alternatively, you may
|
|
45
66
|
configure your own model with `useTabsModel` and pass it to `Tabs` via the `model` prop. This
|
|
46
|
-
pattern is referred to as
|
|
47
|
-
|
|
67
|
+
pattern is referred to as
|
|
68
|
+
[hoisting the model](/getting-started/for-developers/resources/compound-components/#configuring-a-model)
|
|
69
|
+
and provides direct access to its `state` and `events` outside of the `Tabs` component.
|
|
48
70
|
|
|
49
71
|
In this example, we set up external observation of the model state and create an external button to
|
|
50
72
|
trigger an event to change the active tab.
|
|
51
73
|
|
|
52
74
|
<ExampleCodeBlock code={HoistedModel} />
|
|
53
75
|
|
|
54
|
-
### Named
|
|
76
|
+
### Named Tabs
|
|
55
77
|
|
|
56
78
|
`Tabs.Item` and `Tabs.Panel` both take an optional `name` attribute that is used for the
|
|
57
|
-
`onActivate` callback. This example is identical to the Basic Example, but with named
|
|
79
|
+
`onActivate` callback. This example is identical to the Basic Example, but with named tabs for the
|
|
58
80
|
`Tabs.Item` and `Tabs.Panel` subcomponents.
|
|
59
81
|
|
|
60
|
-
<ExampleCodeBlock code={
|
|
82
|
+
<ExampleCodeBlock code={NamedTabs} />
|
|
61
83
|
|
|
62
|
-
### Right-to-Left
|
|
84
|
+
### Right-to-Left (RTL)
|
|
63
85
|
|
|
64
|
-
`Tabs` supports right-to-left
|
|
86
|
+
`Tabs` supports right-to-left languages when specified in the `CanvasProvider` `theme`.
|
|
65
87
|
|
|
66
88
|
<ExampleCodeBlock code={RightToLeft} />
|
|
67
89
|
|
|
@@ -71,6 +93,14 @@ Set the `disabled` prop of a `Tabs.Item` to `true` to disable it.
|
|
|
71
93
|
|
|
72
94
|
<ExampleCodeBlock code={DisabledTab} />
|
|
73
95
|
|
|
96
|
+
### Tab Icons
|
|
97
|
+
|
|
98
|
+
Tabs can have icons. You must set `hasIcon` on the `Tabs.Item` and use the `Icon` and `Text`
|
|
99
|
+
subcomponent. The `hasIcon` changes the `Tabs.Item` to change where overflow detection is from the
|
|
100
|
+
`Tabs.Item` element to the `Tabs.Item.Text` element.
|
|
101
|
+
|
|
102
|
+
<ExampleCodeBlock code={Icons} />
|
|
103
|
+
|
|
74
104
|
### Alternative Tab Stop
|
|
75
105
|
|
|
76
106
|
By default, tab panels are focusable for accessibility. If the contents of a tab panel have a
|
|
@@ -93,9 +123,9 @@ from the `contents` object.
|
|
|
93
123
|
### Dynamic Tabs
|
|
94
124
|
|
|
95
125
|
The `Tabs.Item` component takes in an optional `index` property if you want to specify the position
|
|
96
|
-
of a tab. If not defined, by default it will append tabs to the end.
|
|
97
|
-
stored as an array in the state
|
|
98
|
-
|
|
126
|
+
of a tab. If not defined, by default it will append tabs to the end. In this example, our tabs are
|
|
127
|
+
stored as an array in the state, and we have a fixed tab at the end that can add new tabs to that
|
|
128
|
+
array.
|
|
99
129
|
|
|
100
130
|
<ExampleCodeBlock code={DynamicTabs} />
|
|
101
131
|
|
|
@@ -106,22 +136,24 @@ the end.
|
|
|
106
136
|
#### Usage
|
|
107
137
|
|
|
108
138
|
`Tabs` is a container component that is responsible for creating a `TabsModel` and sharing it with
|
|
109
|
-
its
|
|
139
|
+
its subcomponents using React context. It does not represent a real element.
|
|
110
140
|
|
|
111
141
|
```tsx
|
|
112
|
-
|
|
113
|
-
|
|
142
|
+
<Tabs onActivate={({data}) => console.log('Activated tab', data.tab)}>
|
|
143
|
+
{/* Child components */}
|
|
144
|
+
</Tabs>
|
|
145
|
+
```
|
|
114
146
|
|
|
115
|
-
|
|
147
|
+
Alternatively, you may pass in a model using the hoisted model pattern.
|
|
116
148
|
|
|
117
|
-
|
|
149
|
+
```tsx
|
|
118
150
|
const model = useTabsModel({
|
|
119
151
|
onActivate({data}) {
|
|
120
152
|
console.log('Activated Tab', data.tab);
|
|
121
153
|
},
|
|
122
154
|
});
|
|
123
155
|
|
|
124
|
-
<Tabs model={model}>{/*
|
|
156
|
+
<Tabs model={model}>{/* Child components */}</Tabs>;
|
|
125
157
|
```
|
|
126
158
|
|
|
127
159
|
#### Props
|
|
@@ -135,8 +167,7 @@ Note that if you pass in a `model` configured with `useTabsModel`, configuration
|
|
|
135
167
|
|
|
136
168
|
#### Usage
|
|
137
169
|
|
|
138
|
-
`Tabs.List` is a
|
|
139
|
-
subcomponents.
|
|
170
|
+
`Tabs.List` is a `<div role="tablist">` element. It is a container for `Tabs.Item` subcomponents.
|
|
140
171
|
|
|
141
172
|
```tsx
|
|
142
173
|
<Tabs.List>{/* Tabs.Items */}</Tabs.List>
|
|
@@ -144,7 +175,7 @@ subcomponents.
|
|
|
144
175
|
|
|
145
176
|
#### Props
|
|
146
177
|
|
|
147
|
-
Undocumented props are spread to the underlying
|
|
178
|
+
Undocumented props are spread to the underlying `<div>` element.
|
|
148
179
|
|
|
149
180
|
<ArgsTable of={Tabs.List} />
|
|
150
181
|
|
|
@@ -152,9 +183,9 @@ Undocumented props are spread to the underlying `div` element.
|
|
|
152
183
|
|
|
153
184
|
#### Usage
|
|
154
185
|
|
|
155
|
-
`Tabs.Item` is a
|
|
156
|
-
|
|
157
|
-
|
|
186
|
+
`Tabs.Item` is a `<button role="tab">` element. Each `Tabs.Item` is associated with a `Tabs.Panel`
|
|
187
|
+
either by a `name` attribute or by the position in the list. If a `name` is provided, it must match
|
|
188
|
+
the name passed to the corresponding `Tabs.Panel` component.
|
|
158
189
|
|
|
159
190
|
```tsx
|
|
160
191
|
<Tabs.Item name="first">First Tab</Tabs.Item>
|
|
@@ -170,10 +201,9 @@ Undocumented props are spread to the underlying `button` element.
|
|
|
170
201
|
|
|
171
202
|
#### Usage
|
|
172
203
|
|
|
173
|
-
`Tabs.Panel` is a
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
component.
|
|
204
|
+
`Tabs.Panel` is a `<div role="tabpanel">` element. It is focusable by default. Each `Tabs.Panel` is
|
|
205
|
+
controlled by a `Tabs.Item` either by a `name` attribute or by the position in the list. If a `name`
|
|
206
|
+
is provided, it must match the name passed to the corresponding `Tabs.Item` component.
|
|
177
207
|
|
|
178
208
|
```tsx
|
|
179
209
|
<Tabs.Panel name="first">{/* Contents of the tab panel */}</Tabs.Panel>
|
|
@@ -181,7 +211,7 @@ component.
|
|
|
181
211
|
|
|
182
212
|
#### Props
|
|
183
213
|
|
|
184
|
-
Undocumented props are spread to the underlying
|
|
214
|
+
Undocumented props are spread to the underlying `<div>` element.
|
|
185
215
|
|
|
186
216
|
<ArgsTable of={Tabs.Panel} />
|
|
187
217
|
|
|
@@ -192,9 +222,10 @@ If `Tabs` was stripped of all its markup, attributes, and styling, what would re
|
|
|
192
222
|
object composed of two parts: `state` which describes the current snapshot in time of the component
|
|
193
223
|
and `events` which describes events that can be sent to the model.
|
|
194
224
|
|
|
195
|
-
By default, `Tabs` will create
|
|
196
|
-
access to the model's `state` and `events
|
|
197
|
-
pass it to `Tabs` via a
|
|
225
|
+
By default, `Tabs` will create a model and share it internally with its subcomponents using React
|
|
226
|
+
context. Alternatively, if you need direct access to the model's `state` and `events` outside of the
|
|
227
|
+
`Tabs` component, you may configure your own model with `useTabsModel` and pass it to `Tabs` via a
|
|
228
|
+
pattern called
|
|
198
229
|
[hoisting the model](/getting-started/for-developers/resources/compound-components/#configuring-a-model).
|
|
199
230
|
|
|
200
231
|
```tsx
|
|
@@ -204,7 +235,7 @@ const model = useTabsModel({
|
|
|
204
235
|
},
|
|
205
236
|
});
|
|
206
237
|
|
|
207
|
-
<Tabs model={model}>{/*
|
|
238
|
+
<Tabs model={model}>{/* Child components */}</Tabs>;
|
|
208
239
|
```
|
|
209
240
|
|
|
210
241
|
### Config
|
|
@@ -8,7 +8,7 @@ export default () => {
|
|
|
8
8
|
<Tabs>
|
|
9
9
|
<Tabs.List>
|
|
10
10
|
<Tabs.Item>First Tab</Tabs.Item>
|
|
11
|
-
<Tabs.Item disabled>Disabled Tab</Tabs.Item>
|
|
11
|
+
<Tabs.Item aria-disabled>Disabled Tab</Tabs.Item>
|
|
12
12
|
<Tabs.Item>Third Tab</Tabs.Item>
|
|
13
13
|
</Tabs.List>
|
|
14
14
|
<div style={{marginTop: space.m}}>
|
|
@@ -1,22 +1,50 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import {space} from '@workday/canvas-kit-react/tokens';
|
|
3
3
|
|
|
4
|
-
import {Tabs, useTabsModel} from '@workday/canvas-kit-react/tabs';
|
|
4
|
+
import {Tabs, useTabsModel, TabsModel} from '@workday/canvas-kit-react/tabs';
|
|
5
|
+
import {SelectionModel} from '../../lib/selection';
|
|
5
6
|
|
|
6
7
|
export default () => {
|
|
7
8
|
const [tabs, setTabs] = React.useState([
|
|
8
|
-
{tab: 'Tab 1',
|
|
9
|
-
{tab: 'Tab 2',
|
|
10
|
-
{tab: 'Tab 3',
|
|
9
|
+
{tab: 'Tab 1', id: 'tab-1'},
|
|
10
|
+
{tab: 'Tab 2', id: 'tab-2'},
|
|
11
|
+
{tab: 'Tab 3', id: 'tab-3'},
|
|
11
12
|
]);
|
|
12
13
|
const addedRef = React.useRef(tabs.length);
|
|
13
14
|
const model = useTabsModel({
|
|
14
|
-
|
|
15
|
+
shouldSelect: ({data}) => data.id !== 'last',
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Helper function that should be called when an item is programmatically removed. The following
|
|
20
|
+
* side effects depend on state of the model:
|
|
21
|
+
* * **Item is focused**: Focus will be moved to next item in the list
|
|
22
|
+
* * **Item is selected**: Selection will be moved to the next item in the list
|
|
23
|
+
* @param id The id of the item that will be removed
|
|
24
|
+
*/
|
|
25
|
+
const removeItem = (id: string, model: SelectionModel) => {
|
|
26
|
+
const index = model.state.items.findIndex(item => model.getId(item) === model.state.cursorId);
|
|
27
|
+
const nextIndex = index === model.state.items.length - 1 ? index - 1 : index + 1;
|
|
28
|
+
const nextId = model.getId(model.state.items[nextIndex]);
|
|
29
|
+
if (model.state.selectedIds[0] === id) {
|
|
30
|
+
// We're removing the currently selected item. Select next item
|
|
31
|
+
model.events.select({id: nextId});
|
|
32
|
+
}
|
|
33
|
+
if (model.state.cursorId === id) {
|
|
34
|
+
// We're removing the currently focused item. Focus next item
|
|
35
|
+
model.events.goTo({id: nextId});
|
|
36
|
+
|
|
37
|
+
// wait for stabilization of state
|
|
38
|
+
requestAnimationFrame(() => {
|
|
39
|
+
document.querySelector<HTMLElement>(`#${model.state.id}-${nextId}`)?.focus();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const onKeyDown = (e: React.KeyboardEvent<HTMLElement>, id: string) => {
|
|
45
|
+
if (e.key === 'Delete') {
|
|
46
|
+
setTabs(tabs.filter(item => item.id !== id));
|
|
47
|
+
removeItem(id, model);
|
|
20
48
|
}
|
|
21
49
|
};
|
|
22
50
|
|
|
@@ -25,10 +53,10 @@ export default () => {
|
|
|
25
53
|
<Tabs.List>
|
|
26
54
|
{tabs.map((item, index) => (
|
|
27
55
|
<Tabs.Item
|
|
28
|
-
key={item.
|
|
29
|
-
name={item.
|
|
56
|
+
key={item.id}
|
|
57
|
+
name={item.id}
|
|
30
58
|
index={index}
|
|
31
|
-
onKeyDown={e => onKeyDown(e, item.
|
|
59
|
+
onKeyDown={e => onKeyDown(e, item.id)}
|
|
32
60
|
>
|
|
33
61
|
{item.tab}
|
|
34
62
|
</Tabs.Item>
|
|
@@ -40,7 +68,7 @@ export default () => {
|
|
|
40
68
|
onClick={() => {
|
|
41
69
|
addedRef.current += 1;
|
|
42
70
|
setTabs(tabs =>
|
|
43
|
-
tabs.concat({tab: `Tab ${addedRef.current}`,
|
|
71
|
+
tabs.concat({tab: `Tab ${addedRef.current}`, id: `tab-${addedRef.current}`})
|
|
44
72
|
);
|
|
45
73
|
model.events.goTo({id: 'last'});
|
|
46
74
|
}}
|
|
@@ -50,7 +78,7 @@ export default () => {
|
|
|
50
78
|
</Tabs.List>
|
|
51
79
|
<div style={{marginTop: space.m}}>
|
|
52
80
|
{tabs.map((item, index) => (
|
|
53
|
-
<Tabs.Panel key={item.
|
|
81
|
+
<Tabs.Panel key={item.id} name={item.id}>
|
|
54
82
|
Contents of {item.tab}
|
|
55
83
|
</Tabs.Panel>
|
|
56
84
|
))}
|
|
@@ -6,8 +6,8 @@ import {Tabs, useTabsModel} from '@workday/canvas-kit-react/tabs';
|
|
|
6
6
|
|
|
7
7
|
export default () => {
|
|
8
8
|
const model = useTabsModel({
|
|
9
|
-
|
|
10
|
-
console.log('
|
|
9
|
+
onSelect({data, prevState}) {
|
|
10
|
+
console.log('Selected Tab', data, prevState);
|
|
11
11
|
},
|
|
12
12
|
});
|
|
13
13
|
|
|
@@ -27,10 +27,10 @@ export default () => {
|
|
|
27
27
|
</Tabs>
|
|
28
28
|
<SecondaryButton
|
|
29
29
|
onClick={() => {
|
|
30
|
-
model.events.
|
|
30
|
+
model.events.select({id: 'third'});
|
|
31
31
|
}}
|
|
32
32
|
>
|
|
33
|
-
|
|
33
|
+
Select Third Tab
|
|
34
34
|
</SecondaryButton>
|
|
35
35
|
</>
|
|
36
36
|
);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {space} from '@workday/canvas-kit-react/tokens';
|
|
4
|
+
import {starIcon, searchIcon, selectIcon, shareIcon} from '@workday/canvas-system-icons-web';
|
|
5
|
+
import {Tabs} from '@workday/canvas-kit-react/tabs';
|
|
6
|
+
|
|
7
|
+
export default () => {
|
|
8
|
+
return (
|
|
9
|
+
<Tabs>
|
|
10
|
+
<Tabs.List>
|
|
11
|
+
<Tabs.Item hasIcon>
|
|
12
|
+
<Tabs.Item.Icon icon={starIcon} />
|
|
13
|
+
<Tabs.Item.Text>First Tab</Tabs.Item.Text>
|
|
14
|
+
</Tabs.Item>
|
|
15
|
+
<Tabs.Item hasIcon>
|
|
16
|
+
<Tabs.Item.Icon icon={searchIcon} />
|
|
17
|
+
<Tabs.Item.Text>Second Tab</Tabs.Item.Text>
|
|
18
|
+
</Tabs.Item>
|
|
19
|
+
<Tabs.Item hasIcon>
|
|
20
|
+
<Tabs.Item.Icon icon={selectIcon} />
|
|
21
|
+
<Tabs.Item.Text>Third Tab</Tabs.Item.Text>
|
|
22
|
+
</Tabs.Item>
|
|
23
|
+
<Tabs.Item hasIcon>
|
|
24
|
+
<Tabs.Item.Icon icon={shareIcon} />
|
|
25
|
+
<Tabs.Item.Text>Fourth Tab</Tabs.Item.Text>
|
|
26
|
+
</Tabs.Item>
|
|
27
|
+
</Tabs.List>
|
|
28
|
+
<div style={{marginTop: space.m}}>
|
|
29
|
+
<Tabs.Panel>Contents of First Tab</Tabs.Panel>
|
|
30
|
+
<Tabs.Panel>Contents of Second Tab</Tabs.Panel>
|
|
31
|
+
<Tabs.Panel>Contents of Third Tab</Tabs.Panel>
|
|
32
|
+
<Tabs.Panel>Contents of Fourth Tab</Tabs.Panel>
|
|
33
|
+
</div>
|
|
34
|
+
</Tabs>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {Tabs, useTabsModel} from '@workday/canvas-kit-react/tabs';
|
|
4
|
+
import {HStack} from '@workday/canvas-kit-labs-react';
|
|
5
|
+
import {SecondaryButton} from '../../../button';
|
|
6
|
+
|
|
7
|
+
type MyTabItem = {
|
|
8
|
+
id: string;
|
|
9
|
+
text: React.ReactNode;
|
|
10
|
+
contents: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default () => {
|
|
14
|
+
const [items] = React.useState<MyTabItem[]>([
|
|
15
|
+
{id: 'first', text: 'First Tab', contents: 'Contents of First Tab'},
|
|
16
|
+
{id: 'second', text: 'Second Tab', contents: 'Contents of Second Tab'},
|
|
17
|
+
{id: 'third', text: 'Third Tab', contents: 'Contents of Third Tab'},
|
|
18
|
+
{id: 'fourth', text: 'Fourth Tab', contents: 'Contents of Fourth Tab'},
|
|
19
|
+
{id: 'fifth', text: 'Fifth Tab', contents: 'Contents of Fifth Tab'},
|
|
20
|
+
{id: 'sixth', text: 'Sixth Tab', contents: 'Contents of Sixth Tab'},
|
|
21
|
+
{id: 'seventh', text: 'Seventh Tab', contents: 'Contents of Seventh Tab'},
|
|
22
|
+
]);
|
|
23
|
+
const model = useTabsModel({
|
|
24
|
+
items,
|
|
25
|
+
});
|
|
26
|
+
const [containerWidth, setContainerWidth] = React.useState('100%');
|
|
27
|
+
return (
|
|
28
|
+
<div style={{width: containerWidth}}>
|
|
29
|
+
<Tabs model={model}>
|
|
30
|
+
<Tabs.List overflowButton={<Tabs.OverflowButton>More</Tabs.OverflowButton>}>
|
|
31
|
+
{(item: MyTabItem) => <Tabs.Item name={item.id}>{item.text}</Tabs.Item>}
|
|
32
|
+
</Tabs.List>
|
|
33
|
+
<Tabs.Menu.Popper>
|
|
34
|
+
<Tabs.Menu.Card maxWidth={300} maxHeight={200}>
|
|
35
|
+
<Tabs.Menu.List>
|
|
36
|
+
{(item: MyTabItem) => <Tabs.Menu.Item name={item.id}>{item.text}</Tabs.Menu.Item>}
|
|
37
|
+
</Tabs.Menu.List>
|
|
38
|
+
</Tabs.Menu.Card>
|
|
39
|
+
</Tabs.Menu.Popper>
|
|
40
|
+
<Tabs.Panels>
|
|
41
|
+
{(item: MyTabItem) => (
|
|
42
|
+
<Tabs.Panel marginTop="m" name={item.id}>
|
|
43
|
+
{item.contents}
|
|
44
|
+
</Tabs.Panel>
|
|
45
|
+
)}
|
|
46
|
+
</Tabs.Panels>
|
|
47
|
+
</Tabs>
|
|
48
|
+
<hr />
|
|
49
|
+
<h4>Change tab container size</h4>
|
|
50
|
+
<HStack spacing="xs">
|
|
51
|
+
<SecondaryButton onClick={() => setContainerWidth('100%')}>100%</SecondaryButton>
|
|
52
|
+
<SecondaryButton onClick={() => setContainerWidth('500px')}>500px</SecondaryButton>
|
|
53
|
+
<SecondaryButton onClick={() => setContainerWidth('235px')}>235px</SecondaryButton>
|
|
54
|
+
<SecondaryButton onClick={() => setContainerWidth('150px')}>150px</SecondaryButton>
|
|
55
|
+
</HStack>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
@@ -29,52 +29,36 @@ Below are examples we expect will work for most use cases. Note that all example
|
|
|
29
29
|
they are an important signifier to communicate meaning. For this reason, Toast notifications should
|
|
30
30
|
always include an icon.
|
|
31
31
|
|
|
32
|
-
---
|
|
33
|
-
|
|
34
32
|
#### Complete Example with Popper
|
|
35
33
|
|
|
36
34
|
We use Popper to position Toast. Here's an example of how to use them together.
|
|
37
35
|
|
|
38
36
|
<ExampleCodeBlock code={WithPopper} />
|
|
39
37
|
|
|
40
|
-
---
|
|
41
|
-
|
|
42
38
|
#### Success
|
|
43
39
|
|
|
44
40
|
<ExampleCodeBlock code={Success} />
|
|
45
41
|
|
|
46
|
-
---
|
|
47
|
-
|
|
48
42
|
#### Error
|
|
49
43
|
|
|
50
44
|
<ExampleCodeBlock code={Error} />
|
|
51
45
|
|
|
52
|
-
---
|
|
53
|
-
|
|
54
46
|
#### WithCloseButton
|
|
55
47
|
|
|
56
48
|
<ExampleCodeBlock code={WithCloseButton} />
|
|
57
49
|
|
|
58
|
-
---
|
|
59
|
-
|
|
60
50
|
#### With an Action Link
|
|
61
51
|
|
|
62
52
|
<ExampleCodeBlock code={WithActionLink} />
|
|
63
53
|
|
|
64
|
-
---
|
|
65
|
-
|
|
66
54
|
#### With an Action Link and CloseIcon
|
|
67
55
|
|
|
68
56
|
<ExampleCodeBlock code={WithActionLinkAndCloseIcon} />
|
|
69
57
|
|
|
70
|
-
---
|
|
71
|
-
|
|
72
58
|
#### With RTL
|
|
73
59
|
|
|
74
60
|
<ExampleCodeBlock code={RTL} />
|
|
75
61
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
## Component Props
|
|
62
|
+
## Props
|
|
79
63
|
|
|
80
64
|
<ArgsTable of={Toast} />
|