@workday/canvas-kit-docs 6.0.0-beta.0-next.15 → 6.0.2
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/4.0-MIGRATION-GUIDE.mdx +1 -1
- package/dist/mdx/6.0-MIGRATION-GUIDE.mdx +554 -0
- package/dist/mdx/COMPOUND_COMPONENTS.mdx +31 -30
- package/dist/mdx/CONTRIBUTING.mdx +90 -63
- package/dist/mdx/labs-react/search-form/SearchForm.mdx +64 -0
- package/dist/mdx/labs-react/search-form/examples/Basic.tsx +61 -0
- package/dist/mdx/labs-react/search-form/examples/CustomTheme.tsx +72 -0
- package/dist/mdx/labs-react/search-form/examples/Grow.tsx +62 -0
- package/dist/mdx/labs-react/search-form/examples/PropTables.splitProps.tsx +4 -0
- package/dist/mdx/labs-react/search-form/examples/RTL.tsx +70 -0
- package/dist/mdx/labs-react/search-form/examples/Theming.tsx +64 -0
- package/dist/mdx/labs-react/text-input/TextInput.mdx +123 -0
- package/dist/mdx/labs-react/text-input/examples/Alert.tsx +46 -0
- package/dist/mdx/labs-react/text-input/examples/Basic.tsx +20 -0
- package/dist/mdx/labs-react/text-input/examples/Disabled.tsx +20 -0
- package/dist/mdx/labs-react/text-input/examples/Error.tsx +43 -0
- package/dist/mdx/labs-react/text-input/examples/Grow.tsx +20 -0
- package/dist/mdx/labs-react/text-input/examples/HiddenLabel.tsx +17 -0
- package/dist/mdx/labs-react/text-input/examples/LabelPosition.tsx +20 -0
- package/dist/mdx/labs-react/text-input/examples/LoginForm.tsx +100 -0
- package/dist/mdx/labs-react/text-input/examples/Password.tsx +20 -0
- package/dist/mdx/labs-react/text-input/examples/Placeholder.tsx +20 -0
- package/dist/mdx/labs-react/text-input/examples/RefForwarding.tsx +27 -0
- package/dist/mdx/labs-react/text-input/examples/Required.tsx +20 -0
- package/dist/mdx/labs-react/text-input/examples/ThemedAlert.tsx +51 -0
- package/dist/mdx/labs-react/text-input/examples/ThemedError.tsx +40 -0
- package/dist/mdx/preview-react/breadcrumbs/Breadcrumbs.mdx +1 -1
- package/dist/mdx/preview-react/menu/Menu.mdx +17 -9
- package/dist/mdx/preview-react/menu/examples/Basic.tsx +65 -10
- package/dist/mdx/preview-react/menu/examples/ContextMenu.tsx +45 -29
- package/dist/mdx/preview-react/menu/examples/CustomMenuItem.tsx +2 -2
- package/dist/mdx/preview-react/menu/examples/Icons.tsx +1 -1
- package/dist/mdx/preview-react/menu/examples/ManyItems.tsx +2 -2
- package/dist/mdx/preview-react/side-panel/SidePanel.mdx +1 -1
- 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/card/card.mdx +1 -1
- package/dist/mdx/react/pagination/PropTables.splitprops.tsx +47 -0
- package/dist/mdx/react/pagination/examples/{StepControls.tsx → Basic.tsx} +1 -1
- package/dist/mdx/react/pagination/examples/GoToForm.tsx +1 -1
- package/dist/mdx/react/pagination/examples/HoistedModel.tsx +36 -22
- package/dist/mdx/react/pagination/examples/RTL.tsx +1 -1
- package/dist/mdx/react/pagination/pagination.mdx +225 -474
- 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 +160 -88
- package/dist/mdx/react/tabs/TabsModel.splitprops.tsx +5 -0
- package/dist/mdx/react/tabs/examples/{Simple.tsx → Basic.tsx} +0 -0
- 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/text-area/TextArea.mdx +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/CODE_OF_CONDUCT.md +0 -68
- package/dist/mdx/preview-react/menu/examples/ContextMenuTarget.tsx +0 -33
- package/dist/mdx/preview-react/menu/examples/ControlButton.tsx +0 -84
- package/dist/mdx/react/pagination/examples/ShowAdditionalDetails.tsx +0 -52
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
import {Tabs} from '@workday/canvas-kit-react/tabs';
|
|
2
2
|
import {Specifications} from '@workday/canvas-kit-docs';
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import Basic from './examples/Basic';
|
|
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';
|
|
11
13
|
import DynamicTabs from './examples/DynamicTabs';
|
|
14
|
+
import {
|
|
15
|
+
TabsModelConfigComponent,
|
|
16
|
+
TabsStateComponent,
|
|
17
|
+
TabsEventsComponent,
|
|
18
|
+
} from './TabsModel.splitprops.tsx';
|
|
12
19
|
|
|
13
20
|
|
|
14
|
-
# Canvas Kit
|
|
21
|
+
# Canvas Kit Tabs
|
|
22
|
+
|
|
23
|
+
`Tabs` is a [compound component](/getting-started/for-developers/resources/compound-components/)
|
|
24
|
+
that allows users to navigate between related views of content while remaining in context of the
|
|
25
|
+
page.
|
|
26
|
+
|
|
27
|
+
[> Workday Design Reference](https://design.workday.com/components/navigation/tabs)
|
|
15
28
|
|
|
16
29
|
## Installation
|
|
17
30
|
|
|
@@ -21,85 +34,98 @@ yarn add @workday/canvas-kit-react
|
|
|
21
34
|
|
|
22
35
|
## Usage
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
[W3 Tabs specification](https://www.w3.org/TR/wai-aria-practices/#tabpanel). `Tabs` is a
|
|
26
|
-
[Compound Component](/getting-started/for-developers/resources/compound-components/), which means it
|
|
27
|
-
can be composed in a variety of different ways. We'll first cover some basic usage examples followed
|
|
28
|
-
by more advanced usage.
|
|
37
|
+
### Basic Example
|
|
29
38
|
|
|
30
|
-
|
|
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).
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
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.
|
|
34
45
|
|
|
35
|
-
|
|
46
|
+
<ExampleCodeBlock code={Basic} />
|
|
36
47
|
|
|
37
|
-
|
|
48
|
+
### Overflow Tabs
|
|
38
49
|
|
|
39
|
-
|
|
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.
|
|
40
56
|
|
|
41
|
-
|
|
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.
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
`onActivate` callback. This example is the same, but with named keys for the tabs and panels.
|
|
61
|
+
<ExampleCodeBlock code={OverflowTabs} />
|
|
45
62
|
|
|
46
|
-
|
|
63
|
+
### Hoisted Model
|
|
47
64
|
|
|
48
|
-
|
|
65
|
+
By default, `Tabs` will create and use its own [model](#model) internally. Alternatively, you may
|
|
66
|
+
configure your own model with `useTabsModel` and pass it to `Tabs` via the `model` prop. This
|
|
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.
|
|
49
70
|
|
|
50
|
-
|
|
71
|
+
In this example, we set up external observation of the model state and create an external button to
|
|
72
|
+
trigger an event to change the active tab.
|
|
51
73
|
|
|
52
|
-
<ExampleCodeBlock code={
|
|
74
|
+
<ExampleCodeBlock code={HoistedModel} />
|
|
53
75
|
|
|
54
|
-
|
|
76
|
+
### Named Tabs
|
|
55
77
|
|
|
56
|
-
|
|
78
|
+
`Tabs.Item` and `Tabs.Panel` both take an optional `name` attribute that is used for the
|
|
79
|
+
`onActivate` callback. This example is identical to the Basic Example, but with named tabs for the
|
|
80
|
+
`Tabs.Item` and `Tabs.Panel` subcomponents.
|
|
57
81
|
|
|
58
|
-
<ExampleCodeBlock code={
|
|
82
|
+
<ExampleCodeBlock code={NamedTabs} />
|
|
59
83
|
|
|
60
|
-
|
|
84
|
+
### Right-to-Left (RTL)
|
|
61
85
|
|
|
62
|
-
|
|
63
|
-
focusable element, you may disable this default behavior by setting `tabIndex` to `undefined`. This
|
|
64
|
-
example has a tab panel with a focusable button in the tab panel.
|
|
86
|
+
`Tabs` supports right-to-left languages when specified in the `CanvasProvider` `theme`.
|
|
65
87
|
|
|
66
|
-
<ExampleCodeBlock code={
|
|
88
|
+
<ExampleCodeBlock code={RightToLeft} />
|
|
67
89
|
|
|
68
|
-
###
|
|
90
|
+
### Disabled Tab
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
read this section, but if you're needing to go beyond basic examples or are curious, feel free to
|
|
72
|
-
explore this section. While these examples are not exhaustive, they provide additional insight into
|
|
73
|
-
what's possible.
|
|
92
|
+
Set the `disabled` prop of a `Tabs.Item` to `true` to disable it.
|
|
74
93
|
|
|
75
|
-
|
|
94
|
+
<ExampleCodeBlock code={DisabledTab} />
|
|
76
95
|
|
|
77
|
-
|
|
78
|
-
its own. Hoisting the model allows access to state and events outside the `Tabs` component family.
|
|
79
|
-
You can create a `TabsModel` using the `useTabsModel` hook and configure the model with the same
|
|
80
|
-
configuration that the `Tabs` component receives. If you pass in a configured model, configuration
|
|
81
|
-
properties passed to the `Tabs` component will be ignored.
|
|
96
|
+
### Tab Icons
|
|
82
97
|
|
|
83
|
-
|
|
84
|
-
|
|
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.
|
|
85
101
|
|
|
86
|
-
<ExampleCodeBlock code={
|
|
102
|
+
<ExampleCodeBlock code={Icons} />
|
|
103
|
+
|
|
104
|
+
### Alternative Tab Stop
|
|
87
105
|
|
|
88
|
-
|
|
106
|
+
By default, tab panels are focusable for accessibility. If the contents of a tab panel have a
|
|
107
|
+
focusable element, you may disable this default behavior by setting the `tabIndex` prop of
|
|
108
|
+
`Tabs.Panel` to `undefined`. This example has a tab panel with a focusable button.
|
|
109
|
+
|
|
110
|
+
<ExampleCodeBlock code={AlternativeTabStop} />
|
|
89
111
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
112
|
+
### Single Tab Panel
|
|
113
|
+
|
|
114
|
+
The compound component pattern allows for advanced composition. For example, `Tabs` can be composed
|
|
115
|
+
to have only a single `Tabs.Panel` using attribute overrides and callbacks. More information about
|
|
116
|
+
attributes and callbacks can be found in the prop tables below for each subcomponent.
|
|
117
|
+
|
|
118
|
+
In this example, we use a hoisted model and the `activeTab` property of the state to show content
|
|
119
|
+
from the `contents` object.
|
|
94
120
|
|
|
95
121
|
<ExampleCodeBlock code={SinglePanel} />
|
|
96
122
|
|
|
97
|
-
|
|
123
|
+
### Dynamic Tabs
|
|
98
124
|
|
|
99
125
|
The `Tabs.Item` component takes in an optional `index` property if you want to specify the position
|
|
100
|
-
of a tab. If not defined, by default it will append tabs to the end.
|
|
101
|
-
stored as an array in the state
|
|
102
|
-
|
|
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.
|
|
103
129
|
|
|
104
130
|
<ExampleCodeBlock code={DynamicTabs} />
|
|
105
131
|
|
|
@@ -107,83 +133,129 @@ the end.
|
|
|
107
133
|
|
|
108
134
|
### Tabs
|
|
109
135
|
|
|
110
|
-
The `Tabs` component is the container component that is responsible for creating a `TabsModel` that
|
|
111
|
-
is shared using React context. It does not represent a real element.
|
|
112
|
-
|
|
113
136
|
#### Usage
|
|
114
137
|
|
|
138
|
+
`Tabs` is a container component that is responsible for creating a `TabsModel` and sharing it with
|
|
139
|
+
its subcomponents using React context. It does not represent a real element.
|
|
140
|
+
|
|
115
141
|
```tsx
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{/* sub components go here */ }
|
|
142
|
+
<Tabs onActivate={({data}) => console.log('Activated tab', data.tab)}>
|
|
143
|
+
{/* Child components */}
|
|
119
144
|
</Tabs>
|
|
145
|
+
```
|
|
120
146
|
|
|
121
|
-
|
|
147
|
+
Alternatively, you may pass in a model using the hoisted model pattern.
|
|
122
148
|
|
|
123
|
-
|
|
124
|
-
const model = useTabsModel(
|
|
149
|
+
```tsx
|
|
150
|
+
const model = useTabsModel({
|
|
151
|
+
onActivate({data}) {
|
|
152
|
+
console.log('Activated Tab', data.tab);
|
|
153
|
+
},
|
|
154
|
+
});
|
|
125
155
|
|
|
126
|
-
<Tabs model={model}>
|
|
127
|
-
{/* sub components go here */ }
|
|
128
|
-
</Tabs>
|
|
156
|
+
<Tabs model={model}>{/* Child components */}</Tabs>;
|
|
129
157
|
```
|
|
130
158
|
|
|
131
|
-
####
|
|
159
|
+
#### Props
|
|
132
160
|
|
|
133
|
-
|
|
161
|
+
Note that if you pass in a `model` configured with `useTabsModel`, configuration props passed to
|
|
162
|
+
`Tabs` will be ignored.
|
|
134
163
|
|
|
135
|
-
|
|
164
|
+
<ArgsTable of={Tabs} />
|
|
136
165
|
|
|
137
166
|
### Tabs.List
|
|
138
167
|
|
|
139
|
-
`Tabs.List` is a `div` element with a `role=tablist`. It is a container for `Tabs.Item` components.
|
|
140
|
-
Any additional attributes provided will be forwared to the dom element.
|
|
141
|
-
|
|
142
168
|
#### Usage
|
|
143
169
|
|
|
170
|
+
`Tabs.List` is a `<div role="tablist">` element. It is a container for `Tabs.Item` subcomponents.
|
|
171
|
+
|
|
144
172
|
```tsx
|
|
145
|
-
<Tabs.List>{/* Tabs.Items
|
|
173
|
+
<Tabs.List>{/* Tabs.Items */}</Tabs.List>
|
|
146
174
|
```
|
|
147
175
|
|
|
148
|
-
####
|
|
176
|
+
#### Props
|
|
149
177
|
|
|
150
|
-
|
|
178
|
+
Undocumented props are spread to the underlying `<div>` element.
|
|
151
179
|
|
|
152
|
-
|
|
180
|
+
<ArgsTable of={Tabs.List} />
|
|
153
181
|
|
|
154
182
|
### Tabs.Item
|
|
155
183
|
|
|
156
|
-
`Tabs.Item` is a `button` element with a `role=tab`. Each `Tabs.Item` is associated with a
|
|
157
|
-
`Tabs.Panel` either by a `name` attribute or by the position in the list. If a `name` is provided,
|
|
158
|
-
it must match the name passed to the `Tabs.Panel` component.
|
|
159
|
-
|
|
160
184
|
#### Usage
|
|
161
185
|
|
|
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.
|
|
189
|
+
|
|
162
190
|
```tsx
|
|
163
191
|
<Tabs.Item name="first">First Tab</Tabs.Item>
|
|
164
192
|
```
|
|
165
193
|
|
|
166
|
-
####
|
|
194
|
+
#### Props
|
|
167
195
|
|
|
168
|
-
|
|
196
|
+
Undocumented props are spread to the underlying `button` element.
|
|
169
197
|
|
|
170
|
-
|
|
198
|
+
<ArgsTable of={Tabs.Item} />
|
|
171
199
|
|
|
172
200
|
### Tabs.Panel
|
|
173
201
|
|
|
174
|
-
`Tabs.Panel` is a `div` element with a `role=tabpanel`. It is focusable by default. Each
|
|
175
|
-
`Tabs.Panel` is controlled by a `Tabs.Item` either by a `name` attribute or by the position in the
|
|
176
|
-
list. If a `name` is provided, it must match the name passed to the `Tabs.Item` component.
|
|
177
|
-
|
|
178
202
|
#### Usage
|
|
179
203
|
|
|
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.
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
<Tabs.Panel name="first">{/* Contents of the tab panel */}</Tabs.Panel>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### Props
|
|
213
|
+
|
|
214
|
+
Undocumented props are spread to the underlying `<div>` element.
|
|
215
|
+
|
|
216
|
+
<ArgsTable of={Tabs.Panel} />
|
|
217
|
+
|
|
218
|
+
## Model
|
|
219
|
+
|
|
220
|
+
If `Tabs` was stripped of all its markup, attributes, and styling, what would remain is the
|
|
221
|
+
[model](/getting-started/for-developers/resources/compound-components/#models). The model is an
|
|
222
|
+
object composed of two parts: `state` which describes the current snapshot in time of the component
|
|
223
|
+
and `events` which describes events that can be sent to the model.
|
|
224
|
+
|
|
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
|
|
229
|
+
[hoisting the model](/getting-started/for-developers/resources/compound-components/#configuring-a-model).
|
|
230
|
+
|
|
180
231
|
```tsx
|
|
181
|
-
|
|
232
|
+
const model = useTabsModel({
|
|
233
|
+
onActivate({data}) {
|
|
234
|
+
console.log('Activated Tab', data);
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
<Tabs model={model}>{/* Child components */}</Tabs>;
|
|
182
239
|
```
|
|
183
240
|
|
|
184
|
-
|
|
241
|
+
### Config
|
|
242
|
+
|
|
243
|
+
`useTabsModel` accepts a configuration object with the following properties and returns a
|
|
244
|
+
`TabsModel` with `state` and `events` properties.
|
|
245
|
+
|
|
246
|
+
<ArgsTable of={TabsModelConfigComponent} />
|
|
247
|
+
|
|
248
|
+
### State
|
|
249
|
+
|
|
250
|
+
The `TabsModel` `state` is an object with the following properties.
|
|
251
|
+
|
|
252
|
+
<ArgsTable of={TabsStateComponent} />
|
|
253
|
+
|
|
254
|
+
### Events
|
|
255
|
+
|
|
256
|
+
The `TabsModel` `events` is an object with the following properties.
|
|
185
257
|
|
|
186
|
-
<
|
|
258
|
+
<ArgsTable of={TabsEventsComponent} />
|
|
187
259
|
|
|
188
260
|
## Specifications
|
|
189
261
|
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import {TabsModelConfig, TabsState, TabsEvents} from '@workday/canvas-kit-react/tabs';
|
|
2
|
+
|
|
3
|
+
export const TabsModelConfigComponent = (_: TabsModelConfig) => <div />;
|
|
4
|
+
export const TabsStateComponent = (_: TabsState) => <div />;
|
|
5
|
+
export const TabsEventsComponent = (_: TabsEvents) => <div />;
|
|
File without changes
|
|
@@ -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} />
|