@workday/canvas-kit-docs 11.0.0-alpha.682-next.0 → 11.0.0-alpha.696-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/docs.js +203 -12
- package/dist/es6/lib/specs.js +24 -0
- package/dist/es6/mdx/versionsTable.d.ts +2 -0
- package/dist/es6/mdx/versionsTable.d.ts.map +1 -0
- package/dist/es6/mdx/versionsTable.js +76 -0
- package/dist/mdx/11.0-UPGRADE-GUIDE.mdx +12 -0
- package/dist/mdx/Versions.mdx +8 -0
- package/dist/mdx/preview-react/_examples/TablesAdvanced.mdx +84 -0
- package/dist/mdx/preview-react/_examples/examples/Table/WithExpandableRows.tsx +219 -0
- package/dist/mdx/preview-react/_examples/examples/Table/WithSelectableRows.tsx +156 -0
- package/dist/mdx/preview-react/_examples/examples/Table/WithSortableColumnHeaders.tsx +213 -0
- package/dist/mdx/preview-react/table/Table.mdx +16 -1
- package/dist/mdx/preview-react/table/examples/FixedColumn.tsx +17 -17
- package/dist/mdx/preview-react/table/examples/RightToLeft.tsx +38 -0
- package/dist/mdx/react/select/Select.mdx +82 -7
- package/dist/mdx/react/select/examples/Basic.tsx +1 -1
- package/dist/mdx/react/select/examples/Complex.tsx +11 -16
- package/dist/mdx/react/select/examples/FetchingDynamicItems.tsx +103 -0
- package/dist/mdx/react/select/examples/Grow.tsx +1 -5
- package/dist/mdx/react/select/examples/HoistedModel.tsx +8 -15
- package/dist/mdx/react/select/examples/InitialSelectedItem.tsx +60 -0
- package/dist/mdx/react/select/examples/LabelPosition.tsx +1 -3
- package/dist/mdx/react/select/examples/Placeholder.tsx +41 -0
- package/dist/mdx/react/select/examples/RefForwarding.tsx +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';
|
|
4
|
+
import {Table} from '@workday/canvas-kit-preview-react/table';
|
|
5
|
+
import {TertiaryButton} from '@workday/canvas-kit-react/button';
|
|
6
|
+
import {createComponent, generateUniqueId} from '@workday/canvas-kit-react/common';
|
|
7
|
+
import {Heading, Subtext} from '@workday/canvas-kit-react/text';
|
|
8
|
+
import {Tooltip} from '@workday/canvas-kit-react/tooltip';
|
|
9
|
+
import {createStyles} from '@workday/canvas-kit-styling';
|
|
10
|
+
|
|
11
|
+
import {chevronDownSmallIcon, chevronRightSmallIcon} from '@workday/canvas-system-icons-web';
|
|
12
|
+
import {system} from '@workday/canvas-tokens-web';
|
|
13
|
+
|
|
14
|
+
interface AutoData {
|
|
15
|
+
id: string;
|
|
16
|
+
brand: string;
|
|
17
|
+
model: string;
|
|
18
|
+
year: string;
|
|
19
|
+
price: string;
|
|
20
|
+
engine: string;
|
|
21
|
+
transmission: string;
|
|
22
|
+
horsepower: string;
|
|
23
|
+
torque: string;
|
|
24
|
+
curbWeight: string;
|
|
25
|
+
orderStatus: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const headingID = generateUniqueId();
|
|
29
|
+
const autoData: AutoData[] = [
|
|
30
|
+
{
|
|
31
|
+
id: generateUniqueId(),
|
|
32
|
+
brand: 'Porsche',
|
|
33
|
+
model: '992 911 GT3',
|
|
34
|
+
year: '2022',
|
|
35
|
+
price: 'Starts at $160,000',
|
|
36
|
+
engine: '4.0L Flat 6',
|
|
37
|
+
transmission: 'PDK or 7-Speed Manual',
|
|
38
|
+
horsepower: '502hp',
|
|
39
|
+
torque: '346 lb-ft',
|
|
40
|
+
curbWeight: '3,164 lbs',
|
|
41
|
+
orderStatus: 'Order Placed',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: generateUniqueId(),
|
|
45
|
+
brand: 'BMW',
|
|
46
|
+
model: 'M5 Competition',
|
|
47
|
+
year: '2018',
|
|
48
|
+
price: 'Starts at $105,000',
|
|
49
|
+
engine: 'Twin-Turbo 4.4L V8',
|
|
50
|
+
transmission: 'Automatic',
|
|
51
|
+
horsepower: '627hp',
|
|
52
|
+
torque: '553 lb-ft',
|
|
53
|
+
curbWeight: '4,345 lbs',
|
|
54
|
+
orderStatus: 'Order Fulfilled',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: generateUniqueId(),
|
|
58
|
+
brand: 'Audi',
|
|
59
|
+
model: 'R8',
|
|
60
|
+
year: '2022',
|
|
61
|
+
price: 'Starts at $148,000',
|
|
62
|
+
engine: '5.2L V10',
|
|
63
|
+
transmission: 'Automatic',
|
|
64
|
+
horsepower: '562hp',
|
|
65
|
+
torque: '408 lb-ft',
|
|
66
|
+
curbWeight: '3,594 lbs',
|
|
67
|
+
orderStatus: 'Order Fulfilled',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: generateUniqueId(),
|
|
71
|
+
brand: 'Lotus',
|
|
72
|
+
model: 'Emira',
|
|
73
|
+
year: '2023',
|
|
74
|
+
price: 'Starts at $78,000',
|
|
75
|
+
engine: 'Supercharged 3.5L V6',
|
|
76
|
+
transmission: 'Automatic or 6-Speed Manual',
|
|
77
|
+
horsepower: '400hp',
|
|
78
|
+
torque: '317 lb-ft',
|
|
79
|
+
curbWeight: '3520 lbs',
|
|
80
|
+
orderStatus: 'Shipped: In Transit',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: generateUniqueId(),
|
|
84
|
+
brand: 'Toyota',
|
|
85
|
+
model: 'Supra',
|
|
86
|
+
year: '1998',
|
|
87
|
+
price: '$40,000 - $80,000',
|
|
88
|
+
engine: '3.0L Inline 6',
|
|
89
|
+
transmission: 'Automatic or 6-Speed Manual',
|
|
90
|
+
horsepower: '320hp',
|
|
91
|
+
torque: '315 lb-ft',
|
|
92
|
+
curbWeight: '3,599 lbs',
|
|
93
|
+
orderStatus: 'Delivered',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: generateUniqueId(),
|
|
97
|
+
brand: 'Nissan',
|
|
98
|
+
model: 'Skyline GT-R',
|
|
99
|
+
year: '1994',
|
|
100
|
+
price: '$45,000 - $90,000',
|
|
101
|
+
engine: '2.6L Twin-Turbo Inline 6',
|
|
102
|
+
transmission: '5-Speed Manual',
|
|
103
|
+
horsepower: '276hp',
|
|
104
|
+
torque: '260 lb-ft',
|
|
105
|
+
curbWeight: '3,153 lbs',
|
|
106
|
+
orderStatus: 'Delivered',
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
interface RowProps {
|
|
111
|
+
data: AutoData;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const expandableSectionStyles = createStyles({
|
|
115
|
+
alignItems: 'flex-start',
|
|
116
|
+
display: 'flex',
|
|
117
|
+
gap: system.space.x4,
|
|
118
|
+
padding: system.space.x8,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const expandableHeadingStyles = createStyles({
|
|
122
|
+
margin: 0,
|
|
123
|
+
fontWeight: system.fontWeight.bold,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const expandableListStyles = createStyles({
|
|
127
|
+
listStyle: 'none',
|
|
128
|
+
margin: 0,
|
|
129
|
+
padding: 0,
|
|
130
|
+
gap: system.space.x2,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
function ExpandableRow({data}: RowProps) {
|
|
134
|
+
const [rowExpanded, setRowExpanded] = React.useState(false);
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<>
|
|
138
|
+
<Table.Row gridTemplateColumns="4rem repeat(4, 1fr)">
|
|
139
|
+
<Table.Cell>
|
|
140
|
+
<Tooltip title={`${data.brand} ${data.model}`}>
|
|
141
|
+
<TertiaryButton
|
|
142
|
+
size="small"
|
|
143
|
+
icon={rowExpanded ? chevronDownSmallIcon : chevronRightSmallIcon}
|
|
144
|
+
aria-expanded={rowExpanded}
|
|
145
|
+
onClick={() => setRowExpanded(!rowExpanded)}
|
|
146
|
+
/>
|
|
147
|
+
</Tooltip>
|
|
148
|
+
</Table.Cell>
|
|
149
|
+
<Table.Header scope="row">{data.brand}</Table.Header>
|
|
150
|
+
<Table.Cell>{data.model}</Table.Cell>
|
|
151
|
+
<Table.Cell>{data.year}</Table.Cell>
|
|
152
|
+
<Table.Cell>{data.price}</Table.Cell>
|
|
153
|
+
</Table.Row>
|
|
154
|
+
{rowExpanded && (
|
|
155
|
+
<Table.Row>
|
|
156
|
+
<Table.Cell colSpan={5} cs={expandableSectionStyles}>
|
|
157
|
+
<div>
|
|
158
|
+
<Subtext as="h4" size="large" cs={expandableHeadingStyles}>
|
|
159
|
+
Status
|
|
160
|
+
</Subtext>
|
|
161
|
+
<StatusIndicator variant="blue">{data.orderStatus}</StatusIndicator>
|
|
162
|
+
</div>
|
|
163
|
+
<div>
|
|
164
|
+
<Subtext as="h4" size="large" cs={expandableHeadingStyles}>
|
|
165
|
+
Specifications
|
|
166
|
+
</Subtext>
|
|
167
|
+
<ul className={expandableListStyles}>
|
|
168
|
+
<Subtext as="li" size="large">
|
|
169
|
+
Engine: {data.engine}
|
|
170
|
+
</Subtext>
|
|
171
|
+
<Subtext as="li" size="large">
|
|
172
|
+
Transmission: {data.transmission}
|
|
173
|
+
</Subtext>
|
|
174
|
+
<Subtext as="li" size="large">
|
|
175
|
+
Horsepower: {data.horsepower}
|
|
176
|
+
</Subtext>
|
|
177
|
+
<Subtext as="li" size="large">
|
|
178
|
+
Torque: {data.torque}
|
|
179
|
+
</Subtext>
|
|
180
|
+
<Subtext as="li" size="large">
|
|
181
|
+
Curb Weight: {data.curbWeight}
|
|
182
|
+
</Subtext>
|
|
183
|
+
</ul>
|
|
184
|
+
</div>
|
|
185
|
+
</Table.Cell>
|
|
186
|
+
</Table.Row>
|
|
187
|
+
)}
|
|
188
|
+
</>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export default createComponent()({
|
|
193
|
+
displayName: 'ExpandableRows',
|
|
194
|
+
Component: () => {
|
|
195
|
+
return (
|
|
196
|
+
<>
|
|
197
|
+
<Heading as="h3" id={headingID} size="small">
|
|
198
|
+
Showroom Inventory
|
|
199
|
+
</Heading>
|
|
200
|
+
<Table aria-labelledby={headingID}>
|
|
201
|
+
<Table.Head>
|
|
202
|
+
<Table.Row gridTemplateColumns="4rem repeat(4, 1fr)">
|
|
203
|
+
<Table.Cell></Table.Cell>
|
|
204
|
+
<Table.Header scope="col">Make</Table.Header>
|
|
205
|
+
<Table.Header scope="col">Model</Table.Header>
|
|
206
|
+
<Table.Header scope="col">Year</Table.Header>
|
|
207
|
+
<Table.Header scope="col">Price</Table.Header>
|
|
208
|
+
</Table.Row>
|
|
209
|
+
</Table.Head>
|
|
210
|
+
<Table.Body>
|
|
211
|
+
{autoData.map(item => (
|
|
212
|
+
<ExpandableRow key={item.id} data={item} />
|
|
213
|
+
))}
|
|
214
|
+
</Table.Body>
|
|
215
|
+
</Table>
|
|
216
|
+
</>
|
|
217
|
+
);
|
|
218
|
+
},
|
|
219
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {Table} from '@workday/canvas-kit-preview-react/table';
|
|
4
|
+
import {Heading} from '@workday/canvas-kit-react/text';
|
|
5
|
+
import {Checkbox} from '@workday/canvas-kit-react/checkbox';
|
|
6
|
+
import {createComponent, generateUniqueId} from '@workday/canvas-kit-react/common';
|
|
7
|
+
import {Tooltip} from '@workday/canvas-kit-react/tooltip';
|
|
8
|
+
import {createStencil, createStyles} from '@workday/canvas-kit-styling';
|
|
9
|
+
import {base} from '@workday/canvas-tokens-web';
|
|
10
|
+
|
|
11
|
+
const selectableRowStencil = createStencil({
|
|
12
|
+
base: {
|
|
13
|
+
gridTemplateColumns: '3.5rem repeat(2, 1fr)',
|
|
14
|
+
transition: 'background-color 200ms',
|
|
15
|
+
},
|
|
16
|
+
modifiers: {
|
|
17
|
+
isSelected: {
|
|
18
|
+
true: {
|
|
19
|
+
backgroundColor: base.blueberry100,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const tableHeaderStyles = createStyles({
|
|
26
|
+
backgroundColor: base.soap100,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const tableCellStyles = createStyles({
|
|
30
|
+
backgroundColor: 'transparent',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
interface SelectableRowProps {
|
|
34
|
+
onSelect?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
35
|
+
rowData: PizzaTopping;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const SelectableRow = createComponent('tr')({
|
|
39
|
+
displayName: 'SelectableRow',
|
|
40
|
+
Component: ({onSelect, rowData}: SelectableRowProps) => {
|
|
41
|
+
return (
|
|
42
|
+
<Table.Row cs={selectableRowStencil({isSelected: rowData.checked})}>
|
|
43
|
+
<Table.Cell cs={tableCellStyles}>
|
|
44
|
+
<Tooltip title={rowData.name}>
|
|
45
|
+
<Checkbox checked={rowData.checked} onChange={onSelect} />
|
|
46
|
+
</Tooltip>
|
|
47
|
+
</Table.Cell>
|
|
48
|
+
<Table.Cell cs={tableCellStyles} scope="row">
|
|
49
|
+
{rowData.name}
|
|
50
|
+
</Table.Cell>
|
|
51
|
+
<Table.Cell cs={tableCellStyles}>{rowData.amount}</Table.Cell>
|
|
52
|
+
</Table.Row>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
interface PizzaTopping {
|
|
58
|
+
name: string;
|
|
59
|
+
amount: string;
|
|
60
|
+
checked: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const pizzaToppingData: PizzaTopping[] = [
|
|
64
|
+
{name: 'Pepperoni', amount: '2.5 oz.', checked: false},
|
|
65
|
+
{name: 'Mozzarella', amount: '5 oz.', checked: false},
|
|
66
|
+
{name: 'Basil', amount: '10 Leaves', checked: false},
|
|
67
|
+
{name: 'Roasted Red Peppers', amount: '3 oz.', checked: false},
|
|
68
|
+
{name: 'Mushrooms', amount: '2 oz.', checked: false},
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const headingID = generateUniqueId();
|
|
72
|
+
|
|
73
|
+
type SelectAll = 'checked' | 'indeterminate' | 'unchecked';
|
|
74
|
+
|
|
75
|
+
export default () => {
|
|
76
|
+
const [selectAllState, setSelectAllState] = React.useState<SelectAll>('unchecked');
|
|
77
|
+
const [toppings, setToppings] = React.useState(pizzaToppingData);
|
|
78
|
+
|
|
79
|
+
const handleToppingChange = (name: string) => {
|
|
80
|
+
// Toggle the selected item's checked state and update state
|
|
81
|
+
const updatedToppings = toppings.map(topping => {
|
|
82
|
+
if (topping.name === name) {
|
|
83
|
+
return {...topping, checked: !topping.checked};
|
|
84
|
+
} else {
|
|
85
|
+
return topping;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
setToppings(updatedToppings);
|
|
89
|
+
|
|
90
|
+
// Update the Select All checkbox state
|
|
91
|
+
const selectedToppings = updatedToppings.filter(topping => topping.checked === true);
|
|
92
|
+
// If no toppings are selected, set the Select All checkbox to 'unchecked'
|
|
93
|
+
if (selectedToppings.length === 0) {
|
|
94
|
+
setSelectAllState('unchecked');
|
|
95
|
+
// If all toppings are selected, set the Select All checkbox to 'checked'
|
|
96
|
+
} else if (selectedToppings.length === updatedToppings.length) {
|
|
97
|
+
setSelectAllState('checked');
|
|
98
|
+
// Otherwise, set the Select All checkbox to 'indeterminate'
|
|
99
|
+
} else {
|
|
100
|
+
setSelectAllState('indeterminate');
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const handleSelectAll = () => {
|
|
105
|
+
// If the Select All checkbox is in a checked or indeterminate state,
|
|
106
|
+
// update it to 'unchecked', and uncheck all topping checkboxes
|
|
107
|
+
if (selectAllState === 'checked' || selectAllState === 'indeterminate') {
|
|
108
|
+
setSelectAllState('unchecked');
|
|
109
|
+
const updatedToppingData = toppings.map(topping => ({...topping, checked: false}));
|
|
110
|
+
setToppings(updatedToppingData);
|
|
111
|
+
}
|
|
112
|
+
// If the Select All checkbox is in an unchecked state,
|
|
113
|
+
// update it to 'checked', and check all topping checkboxes
|
|
114
|
+
if (selectAllState === 'unchecked') {
|
|
115
|
+
setSelectAllState('checked');
|
|
116
|
+
const updatedToppingData = toppings.map(topping => ({...topping, checked: true}));
|
|
117
|
+
setToppings(updatedToppingData);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<>
|
|
123
|
+
<Heading as="h3" id={headingID} size="small">
|
|
124
|
+
Select your pizza toppings
|
|
125
|
+
</Heading>
|
|
126
|
+
<Table aria-labelledby={headingID}>
|
|
127
|
+
<Table.Row gridTemplateColumns="3.5rem repeat(2, 1fr)">
|
|
128
|
+
<Table.Cell cs={tableHeaderStyles}>
|
|
129
|
+
<Tooltip title="Select All">
|
|
130
|
+
<Checkbox
|
|
131
|
+
checked={selectAllState === 'checked'}
|
|
132
|
+
indeterminate={selectAllState === 'indeterminate'}
|
|
133
|
+
onChange={handleSelectAll}
|
|
134
|
+
/>
|
|
135
|
+
</Tooltip>
|
|
136
|
+
</Table.Cell>
|
|
137
|
+
<Table.Header scope="col" cs={tableHeaderStyles}>
|
|
138
|
+
Toppings
|
|
139
|
+
</Table.Header>
|
|
140
|
+
<Table.Header scope="col" cs={tableHeaderStyles}>
|
|
141
|
+
Amount
|
|
142
|
+
</Table.Header>
|
|
143
|
+
</Table.Row>
|
|
144
|
+
<Table.Body>
|
|
145
|
+
{toppings.map(rowData => (
|
|
146
|
+
<SelectableRow
|
|
147
|
+
key={rowData.name}
|
|
148
|
+
rowData={rowData}
|
|
149
|
+
onSelect={() => handleToppingChange(rowData.name)}
|
|
150
|
+
/>
|
|
151
|
+
))}
|
|
152
|
+
</Table.Body>
|
|
153
|
+
</Table>
|
|
154
|
+
</>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import {createComponent} from '@workday/canvas-kit-react/common';
|
|
4
|
+
import {Table} from '@workday/canvas-kit-preview-react/table';
|
|
5
|
+
import {Tooltip} from '@workday/canvas-kit-react/tooltip';
|
|
6
|
+
import {TertiaryButton} from '@workday/canvas-kit-react/button';
|
|
7
|
+
import {Text} from '@workday/canvas-kit-react/text';
|
|
8
|
+
import {sortDownIcon, sortUpIcon} from '@workday/canvas-system-icons-web';
|
|
9
|
+
import {createStyles} from '@workday/canvas-kit-styling';
|
|
10
|
+
import {system} from '@workday/canvas-tokens-web';
|
|
11
|
+
|
|
12
|
+
interface CountryData {
|
|
13
|
+
country: string;
|
|
14
|
+
capital: string;
|
|
15
|
+
population: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const countryData: CountryData[] = [
|
|
19
|
+
{country: 'Australia', capital: 'Canberra', population: 25690000},
|
|
20
|
+
{country: 'Bahamas', capital: 'Nassau', population: 407906},
|
|
21
|
+
{country: 'Canada', capital: 'Ottawa', population: 38250000},
|
|
22
|
+
{country: 'Fiji', capital: 'Suva', population: 924610},
|
|
23
|
+
{country: 'Ghana', capital: 'Accra', population: 32830000},
|
|
24
|
+
{country: 'Hong Kong', capital: 'City of Victoria', population: 7413000},
|
|
25
|
+
{country: 'India', capital: 'New Delhi', population: 1408000000},
|
|
26
|
+
{country: 'Ireland', capital: 'Dublin', population: 5033000},
|
|
27
|
+
{country: 'Jamaica', capital: 'Kingston', population: 2828000},
|
|
28
|
+
{country: 'Kenya', capital: 'Nairobi', population: 53010000},
|
|
29
|
+
{country: 'Micronesia', capital: 'Palikir', population: 113131},
|
|
30
|
+
{country: 'New Zealand', capital: 'Wellington', population: 5123000},
|
|
31
|
+
{country: 'Philippines', capital: 'Manila', population: 113900000},
|
|
32
|
+
{country: 'Puerto Rico', capital: 'San Juan', population: 3264000},
|
|
33
|
+
{country: 'Samoa', capital: 'Apia', population: 218764},
|
|
34
|
+
{country: 'Singapore', capital: 'Singapore', population: 5454000},
|
|
35
|
+
{country: 'Tanzania', capital: 'Dodoma', population: 63590000},
|
|
36
|
+
{country: 'United Kingdom', capital: 'London', population: 67330000},
|
|
37
|
+
{country: 'United States', capital: 'Washington, D.C.', population: 331900000},
|
|
38
|
+
{country: 'Zimbabwe', capital: 'Harare', population: 15990000},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
type SortOrder = 'ascending' | 'descending' | 'none';
|
|
42
|
+
|
|
43
|
+
interface HeaderRowState {
|
|
44
|
+
column1SortDirection: SortOrder;
|
|
45
|
+
column2SortDirection: SortOrder;
|
|
46
|
+
column3SortDirection: SortOrder;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface HeaderRowAction {
|
|
50
|
+
column: 'Country' | 'Capital' | 'Population';
|
|
51
|
+
payload: CountryData[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const initialHeaderRowState: HeaderRowState = {
|
|
55
|
+
column1SortDirection: 'none',
|
|
56
|
+
column2SortDirection: 'none',
|
|
57
|
+
column3SortDirection: 'none',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Given the current sort order, return the next sort order
|
|
62
|
+
*/
|
|
63
|
+
function getNextSortOrder(sortOrder: SortOrder) {
|
|
64
|
+
return sortOrder === 'ascending' ? 'descending' : 'ascending';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function headerRowReducer(state: HeaderRowState, action: HeaderRowAction): HeaderRowState {
|
|
68
|
+
switch (action.column) {
|
|
69
|
+
case 'Country':
|
|
70
|
+
if (state.column1SortDirection === 'ascending') {
|
|
71
|
+
action.payload.sort((a, b) => b.country.localeCompare(a.country));
|
|
72
|
+
} else {
|
|
73
|
+
action.payload.sort((a, b) => a.country.localeCompare(b.country));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
...initialHeaderRowState,
|
|
78
|
+
column1SortDirection: getNextSortOrder(state.column1SortDirection),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
case 'Capital':
|
|
82
|
+
if (state.column2SortDirection === 'ascending') {
|
|
83
|
+
action.payload.sort((a, b) => b.capital.localeCompare(a.capital));
|
|
84
|
+
} else {
|
|
85
|
+
action.payload.sort((a, b) => a.capital.localeCompare(b.capital));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
...initialHeaderRowState,
|
|
90
|
+
column2SortDirection: getNextSortOrder(state.column2SortDirection),
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
case 'Population':
|
|
94
|
+
if (state.column3SortDirection === 'ascending') {
|
|
95
|
+
action.payload.sort((a, b) => b.population - a.population);
|
|
96
|
+
} else {
|
|
97
|
+
action.payload.sort();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
...initialHeaderRowState,
|
|
102
|
+
column3SortDirection: getNextSortOrder(state.column3SortDirection),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
default:
|
|
106
|
+
return initialHeaderRowState;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface SortableColumnHeaderProps {
|
|
111
|
+
label: string;
|
|
112
|
+
onSortAction: (label: string) => void;
|
|
113
|
+
children?: React.ReactNode;
|
|
114
|
+
sortOrder: SortOrder;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const getSortIcon = (sortOrder?: SortOrder) => {
|
|
118
|
+
if (sortOrder === 'ascending') {
|
|
119
|
+
return sortUpIcon;
|
|
120
|
+
} else if (sortOrder === 'descending') {
|
|
121
|
+
return sortDownIcon;
|
|
122
|
+
} else {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export default createComponent('th')({
|
|
128
|
+
displayName: 'SortableColumnHeader',
|
|
129
|
+
Component: (
|
|
130
|
+
{label, sortOrder, onSortAction, children, ...elemProps}: SortableColumnHeaderProps,
|
|
131
|
+
ref
|
|
132
|
+
) => {
|
|
133
|
+
return (
|
|
134
|
+
<Table.Header ref={ref} scope="col" aria-sort={sortOrder} {...elemProps}>
|
|
135
|
+
<Tooltip type="describe" title={`Sort ${getNextSortOrder(sortOrder)}`}>
|
|
136
|
+
<TertiaryButton
|
|
137
|
+
icon={getSortIcon(sortOrder)}
|
|
138
|
+
iconPosition="end"
|
|
139
|
+
onClick={() => onSortAction(label)}
|
|
140
|
+
>
|
|
141
|
+
{children}
|
|
142
|
+
</TertiaryButton>
|
|
143
|
+
</Tooltip>
|
|
144
|
+
</Table.Header>
|
|
145
|
+
);
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const textStyles = createStyles({
|
|
150
|
+
paddingInlineStart: system.space.x3,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
export default () => {
|
|
154
|
+
const [headerRowState, headerRowDispatch] = React.useReducer(
|
|
155
|
+
headerRowReducer,
|
|
156
|
+
initialHeaderRowState
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
function sortColumnHandler(columnName) {
|
|
160
|
+
headerRowDispatch({
|
|
161
|
+
column: columnName,
|
|
162
|
+
payload: countryData,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<Table maxHeight="40rem">
|
|
168
|
+
<Table.Caption>Population Listed by Country (2021)</Table.Caption>
|
|
169
|
+
<Table.Head>
|
|
170
|
+
<Table.Row>
|
|
171
|
+
<SortableColumnHeader
|
|
172
|
+
label="Country"
|
|
173
|
+
sortOrder={headerRowState.column1SortDirection as SortOrder}
|
|
174
|
+
onSortAction={sortColumnHandler}
|
|
175
|
+
>
|
|
176
|
+
Country
|
|
177
|
+
</SortableColumnHeader>
|
|
178
|
+
<SortableColumnHeader
|
|
179
|
+
label="Capital"
|
|
180
|
+
sortOrder={headerRowState.column2SortDirection as SortOrder}
|
|
181
|
+
onSortAction={sortColumnHandler}
|
|
182
|
+
>
|
|
183
|
+
Capital
|
|
184
|
+
</SortableColumnHeader>
|
|
185
|
+
<SortableColumnHeader
|
|
186
|
+
label="Population"
|
|
187
|
+
sortOrder={headerRowState.column3SortDirection as SortOrder}
|
|
188
|
+
onSortAction={sortColumnHandler}
|
|
189
|
+
>
|
|
190
|
+
Population
|
|
191
|
+
</SortableColumnHeader>
|
|
192
|
+
</Table.Row>
|
|
193
|
+
</Table.Head>
|
|
194
|
+
<Table.Body>
|
|
195
|
+
{countryData.map(item => {
|
|
196
|
+
return (
|
|
197
|
+
<Table.Row key={item.country}>
|
|
198
|
+
<Table.Header scope="row">
|
|
199
|
+
<Text cs={textStyles}>{item.country}</Text>
|
|
200
|
+
</Table.Header>
|
|
201
|
+
<Table.Cell>
|
|
202
|
+
<Text cs={textStyles}>{item.capital}</Text>
|
|
203
|
+
</Table.Cell>
|
|
204
|
+
<Table.Cell>
|
|
205
|
+
<Text cs={textStyles}>{item.population.toLocaleString()}</Text>
|
|
206
|
+
</Table.Cell>
|
|
207
|
+
</Table.Row>
|
|
208
|
+
);
|
|
209
|
+
})}
|
|
210
|
+
</Table.Body>
|
|
211
|
+
</Table>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {SymbolDoc
|
|
1
|
+
import {SymbolDoc} from '@workday/canvas-kit-docs';
|
|
2
2
|
import {Table} from '@workday/canvas-kit-preview-react/table';
|
|
3
3
|
// Examples
|
|
4
4
|
import Basic from './examples/Basic';
|
|
5
5
|
import BasicWithHeading from './examples/BasicWithHeading';
|
|
6
6
|
import FixedColumn from './examples/FixedColumn';
|
|
7
|
+
import RightToLeft from './examples/RightToLeft';
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
# Canvas Kit Table
|
|
@@ -29,6 +30,12 @@ customization of the title/heading of their table.
|
|
|
29
30
|
|
|
30
31
|
<ExampleCodeBlock code={BasicWithHeading} />
|
|
31
32
|
|
|
33
|
+
### Right to Left
|
|
34
|
+
|
|
35
|
+
Table supports right-to-left languages when specified in the CanvasProvider theme.
|
|
36
|
+
|
|
37
|
+
<ExampleCodeBlock code={RightToLeft} />
|
|
38
|
+
|
|
32
39
|
### Example with Caption
|
|
33
40
|
|
|
34
41
|
Users are free to use a `caption` instead of a heading. A `caption` is not required but it is good
|
|
@@ -46,6 +53,14 @@ Users may add styles to the `Table.Header` to render a fixed column. The example
|
|
|
46
53
|
|
|
47
54
|
<ExampleCodeBlock code={FixedColumn} />
|
|
48
55
|
|
|
56
|
+
### Advanced
|
|
57
|
+
|
|
58
|
+
You can also find several advanced Table examples in our Storybook Examples section.
|
|
59
|
+
|
|
60
|
+
- [Expandable Rows](/docs/examples-tables-advanced--expandable-rows)
|
|
61
|
+
- [Selectable Rows ](/docs/examples-tables-advanced--selectable-rows)
|
|
62
|
+
- [Sortable Column Headers](/docs/examples-tables-advanced--sortable-column-headers)
|
|
63
|
+
|
|
49
64
|
## Component API
|
|
50
65
|
|
|
51
66
|
<SymbolDoc name="Table" fileName="/preview-react/" />
|