@delightui/components 0.1.105 → 0.1.107
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/README.md +104 -1
- package/dist/cjs/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/cjs/components/molecules/Modal/index.d.ts +2 -0
- package/dist/cjs/components/molecules/index.d.ts +2 -0
- package/dist/cjs/library.css +19 -6
- package/dist/cjs/library.js +3 -3
- package/dist/cjs/library.js.map +1 -1
- package/dist/esm/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/esm/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/esm/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/esm/components/molecules/Modal/index.d.ts +2 -0
- package/dist/esm/components/molecules/index.d.ts +2 -0
- package/dist/esm/library.css +19 -6
- package/dist/esm/library.js +3 -3
- package/dist/esm/library.js.map +1 -1
- package/dist/index.d.ts +108 -2
- package/docs/README.md +264 -0
- package/docs/components/atoms/ActionImage.md +119 -0
- package/docs/components/atoms/Button.md +197 -0
- package/docs/components/atoms/Checkbox.md +299 -0
- package/docs/components/atoms/CheckboxItem.md +314 -0
- package/docs/components/atoms/Chip.md +380 -0
- package/docs/components/atoms/CustomToggle.md +270 -0
- package/docs/components/atoms/Icon.md +365 -0
- package/docs/components/atoms/IconButton.md +407 -0
- package/docs/components/atoms/Image.md +448 -0
- package/docs/components/atoms/Input.md +430 -0
- package/docs/components/atoms/ListItem.md +502 -0
- package/docs/components/atoms/Password.md +472 -0
- package/docs/components/atoms/RadioButton.md +614 -0
- package/docs/components/atoms/RadioButtonItem.md +588 -0
- package/docs/components/atoms/ResponsiveComponent.md +612 -0
- package/docs/components/atoms/SelectListItem.md +609 -0
- package/docs/components/atoms/Slider.md +605 -0
- package/docs/components/atoms/Spinner.md +605 -0
- package/docs/components/atoms/Text.md +463 -0
- package/docs/components/atoms/TextArea.md +670 -0
- package/docs/components/atoms/ToastNotification.md +668 -0
- package/docs/components/atoms/Toggle.md +737 -0
- package/docs/components/atoms/ToggleButton.md +751 -0
- package/docs/components/atoms/Tooltip.md +391 -0
- package/docs/components/molecules/Accordion.md +440 -0
- package/docs/components/molecules/AccordionGroup.md +547 -0
- package/docs/components/molecules/ActionCard.md +546 -0
- package/docs/components/molecules/Breadcrumb.md +403 -0
- package/docs/components/molecules/Breadcrumbs.md +485 -0
- package/docs/components/molecules/ButtonGroup.md +383 -0
- package/docs/components/molecules/Card.md +298 -0
- package/docs/components/molecules/ChipInput.md +646 -0
- package/docs/components/molecules/ContextMenu.md +768 -0
- package/docs/components/molecules/CustomTimeSelector.md +116 -0
- package/docs/components/molecules/DatePicker.md +516 -0
- package/docs/components/molecules/DateTimeSelector.md +166 -0
- package/docs/components/molecules/FormField.md +312 -0
- package/docs/components/molecules/Grid.md +577 -0
- package/docs/components/molecules/GridItem.md +834 -0
- package/docs/components/molecules/GridList.md +244 -0
- package/docs/components/molecules/List.md +485 -0
- package/docs/components/molecules/Modal.md +470 -0
- package/docs/components/molecules/ModalFooter.md +702 -0
- package/docs/components/molecules/ModalHeader.md +756 -0
- package/docs/components/molecules/ModalProvider.md +205 -0
- package/docs/components/molecules/Nav.md +530 -0
- package/docs/components/molecules/NavItem.md +572 -0
- package/docs/components/molecules/NavLink.md +499 -0
- package/docs/components/molecules/Option.md +521 -0
- package/docs/components/molecules/Pagination.md +592 -0
- package/docs/components/molecules/PaginationNumberField.md +722 -0
- package/docs/components/molecules/Popover.md +516 -0
- package/docs/components/molecules/ProgressBar.md +624 -0
- package/docs/components/molecules/RadioGroup.md +831 -0
- package/docs/components/molecules/RepeaterList.md +185 -0
- package/docs/components/molecules/Select.md +402 -0
- package/docs/components/molecules/SortableTrigger.md +82 -0
- package/docs/components/molecules/useModal.md +379 -0
- package/docs/components/organisms/Dropzone.md +346 -0
- package/docs/components/organisms/DropzoneClear.md +135 -0
- package/docs/components/organisms/DropzoneContent.md +216 -0
- package/docs/components/organisms/DropzoneFilename.md +191 -0
- package/docs/components/organisms/DropzoneSupportedFormats.md +184 -0
- package/docs/components/organisms/DropzoneTrigger.md +209 -0
- package/docs/components/organisms/Form.md +533 -0
- package/docs/components/organisms/SlideOutPanel.md +662 -0
- package/docs/components/organisms/TabContent.md +902 -0
- package/docs/components/organisms/TabItem.md +1091 -0
- package/docs/components/organisms/Table.md +611 -0
- package/docs/components/organisms/TableBody.md +679 -0
- package/docs/components/organisms/TableCell.md +482 -0
- package/docs/components/organisms/TableHeader.md +513 -0
- package/docs/components/organisms/TableHeaderCell.md +661 -0
- package/docs/components/organisms/TableRow.md +715 -0
- package/docs/components/organisms/Tabs.md +1330 -0
- package/docs/components/utils/ConditionalView.md +568 -0
- package/docs/components/utils/RenderStateView.md +726 -0
- package/docs/components/utils/WrapTextNodes.md +614 -0
- package/package.json +3 -2
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
# TableHeaderCell
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
A specialized table header cell component designed for table headers and column headings. TableHeaderCell provides semantic HTML structure and accessibility features for table column headers, supporting features like column sorting, filtering, and proper screen reader navigation. It extends the standard HTML table header cell element with consistent styling and behavior.
|
|
6
|
+
|
|
7
|
+
## Aliases
|
|
8
|
+
|
|
9
|
+
- TableHeaderCell
|
|
10
|
+
- Header Cell
|
|
11
|
+
- Column Header
|
|
12
|
+
- TH Cell
|
|
13
|
+
- Table Head Cell
|
|
14
|
+
|
|
15
|
+
## Props Breakdown
|
|
16
|
+
|
|
17
|
+
**Extends:** `TdHTMLAttributes<HTMLTableCellElement>`
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default | Required | Description |
|
|
20
|
+
|------|------|---------|----------|-------------|
|
|
21
|
+
| `children` | `ReactNode` | - | No | Content to display in the header cell |
|
|
22
|
+
| `className` | `string` | - | No | Additional CSS class names |
|
|
23
|
+
|
|
24
|
+
Plus all standard HTML td attributes (scope, headers, colSpan, rowSpan, etc.).
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
### Basic Table Header
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell } from '@delightui/components';
|
|
32
|
+
|
|
33
|
+
function BasicTableHeaderExample() {
|
|
34
|
+
const employees = [
|
|
35
|
+
{ name: 'Alice Johnson', department: 'Engineering', salary: 75000 },
|
|
36
|
+
{ name: 'Bob Wilson', department: 'Marketing', salary: 65000 },
|
|
37
|
+
{ name: 'Carol Brown', department: 'Design', salary: 70000 }
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Table>
|
|
42
|
+
<TableHeader>
|
|
43
|
+
<TableRow>
|
|
44
|
+
<TableHeaderCell>Employee Name</TableHeaderCell>
|
|
45
|
+
<TableHeaderCell>Department</TableHeaderCell>
|
|
46
|
+
<TableHeaderCell>Annual Salary</TableHeaderCell>
|
|
47
|
+
</TableRow>
|
|
48
|
+
</TableHeader>
|
|
49
|
+
<TableBody>
|
|
50
|
+
{employees.map((employee, index) => (
|
|
51
|
+
<TableRow key={index}>
|
|
52
|
+
<TableCell>{employee.name}</TableCell>
|
|
53
|
+
<TableCell>{employee.department}</TableCell>
|
|
54
|
+
<TableCell>${employee.salary.toLocaleString()}</TableCell>
|
|
55
|
+
</TableRow>
|
|
56
|
+
))}
|
|
57
|
+
</TableBody>
|
|
58
|
+
</Table>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Sortable Table Headers
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell, Button, Text } from '@delightui/components';
|
|
67
|
+
|
|
68
|
+
function SortableTableHeaderExample() {
|
|
69
|
+
const [sortField, setSortField] = useState<string>('');
|
|
70
|
+
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
|
|
71
|
+
|
|
72
|
+
const products = [
|
|
73
|
+
{ name: 'Laptop Pro', price: 1299.99, stock: 15, category: 'Electronics' },
|
|
74
|
+
{ name: 'Wireless Mouse', price: 49.99, stock: 50, category: 'Accessories' },
|
|
75
|
+
{ name: 'Monitor 27"', price: 399.99, stock: 8, category: 'Electronics' },
|
|
76
|
+
{ name: 'Keyboard Mechanical', price: 129.99, stock: 25, category: 'Accessories' }
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const handleSort = (field: string) => {
|
|
80
|
+
if (sortField === field) {
|
|
81
|
+
setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
|
|
82
|
+
} else {
|
|
83
|
+
setSortField(field);
|
|
84
|
+
setSortDirection('asc');
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const sortedProducts = [...products].sort((a, b) => {
|
|
89
|
+
if (!sortField) return 0;
|
|
90
|
+
const aValue = a[sortField as keyof typeof a];
|
|
91
|
+
const bValue = b[sortField as keyof typeof b];
|
|
92
|
+
const modifier = sortDirection === 'asc' ? 1 : -1;
|
|
93
|
+
return aValue > bValue ? modifier : aValue < bValue ? -modifier : 0;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const getSortIcon = (field: string) => {
|
|
97
|
+
if (sortField !== field) return '↕️';
|
|
98
|
+
return sortDirection === 'asc' ? '↑' : '↓';
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<Table>
|
|
103
|
+
<TableHeader>
|
|
104
|
+
<TableRow>
|
|
105
|
+
<TableHeaderCell>
|
|
106
|
+
<Button
|
|
107
|
+
type="Ghost"
|
|
108
|
+
onClick={() => handleSort('name')}
|
|
109
|
+
style={{ display: 'flex', alignItems: 'center', gap: '4px' }}
|
|
110
|
+
>
|
|
111
|
+
Product Name {getSortIcon('name')}
|
|
112
|
+
</Button>
|
|
113
|
+
</TableHeaderCell>
|
|
114
|
+
<TableHeaderCell>
|
|
115
|
+
<Button
|
|
116
|
+
type="Ghost"
|
|
117
|
+
onClick={() => handleSort('price')}
|
|
118
|
+
style={{ display: 'flex', alignItems: 'center', gap: '4px' }}
|
|
119
|
+
>
|
|
120
|
+
Price {getSortIcon('price')}
|
|
121
|
+
</Button>
|
|
122
|
+
</TableHeaderCell>
|
|
123
|
+
<TableHeaderCell>
|
|
124
|
+
<Button
|
|
125
|
+
type="Ghost"
|
|
126
|
+
onClick={() => handleSort('stock')}
|
|
127
|
+
style={{ display: 'flex', alignItems: 'center', gap: '4px' }}
|
|
128
|
+
>
|
|
129
|
+
Stock {getSortIcon('stock')}
|
|
130
|
+
</Button>
|
|
131
|
+
</TableHeaderCell>
|
|
132
|
+
<TableHeaderCell>Category</TableHeaderCell>
|
|
133
|
+
</TableRow>
|
|
134
|
+
</TableHeader>
|
|
135
|
+
<TableBody>
|
|
136
|
+
{sortedProducts.map((product, index) => (
|
|
137
|
+
<TableRow key={index}>
|
|
138
|
+
<TableCell>{product.name}</TableCell>
|
|
139
|
+
<TableCell>${product.price.toFixed(2)}</TableCell>
|
|
140
|
+
<TableCell>{product.stock}</TableCell>
|
|
141
|
+
<TableCell>{product.category}</TableCell>
|
|
142
|
+
</TableRow>
|
|
143
|
+
))}
|
|
144
|
+
</TableBody>
|
|
145
|
+
</Table>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Multi-Level Headers
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell } from '@delightui/components';
|
|
154
|
+
|
|
155
|
+
function MultiLevelHeaderExample() {
|
|
156
|
+
const salesData = [
|
|
157
|
+
{ region: 'North', q1Sales: 125000, q1Target: 120000, q2Sales: 135000, q2Target: 130000 },
|
|
158
|
+
{ region: 'South', q1Sales: 110000, q1Target: 115000, q2Sales: 125000, q2Target: 120000 },
|
|
159
|
+
{ region: 'East', q1Sales: 95000, q1Target: 100000, q2Sales: 105000, q2Target: 110000 },
|
|
160
|
+
{ region: 'West', q1Sales: 140000, q1Target: 135000, q2Sales: 150000, q2Target: 145000 }
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Table>
|
|
165
|
+
<TableHeader>
|
|
166
|
+
<TableRow>
|
|
167
|
+
<TableHeaderCell rowSpan={2}>Region</TableHeaderCell>
|
|
168
|
+
<TableHeaderCell colSpan={2}>Q1 2024</TableHeaderCell>
|
|
169
|
+
<TableHeaderCell colSpan={2}>Q2 2024</TableHeaderCell>
|
|
170
|
+
</TableRow>
|
|
171
|
+
<TableRow>
|
|
172
|
+
<TableHeaderCell>Sales</TableHeaderCell>
|
|
173
|
+
<TableHeaderCell>Target</TableHeaderCell>
|
|
174
|
+
<TableHeaderCell>Sales</TableHeaderCell>
|
|
175
|
+
<TableHeaderCell>Target</TableHeaderCell>
|
|
176
|
+
</TableRow>
|
|
177
|
+
</TableHeader>
|
|
178
|
+
<TableBody>
|
|
179
|
+
{salesData.map((data, index) => (
|
|
180
|
+
<TableRow key={index}>
|
|
181
|
+
<TableCell style={{ fontWeight: 'bold' }}>{data.region}</TableCell>
|
|
182
|
+
<TableCell>${data.q1Sales.toLocaleString()}</TableCell>
|
|
183
|
+
<TableCell>${data.q1Target.toLocaleString()}</TableCell>
|
|
184
|
+
<TableCell>${data.q2Sales.toLocaleString()}</TableCell>
|
|
185
|
+
<TableCell>${data.q2Target.toLocaleString()}</TableCell>
|
|
186
|
+
</TableRow>
|
|
187
|
+
))}
|
|
188
|
+
</TableBody>
|
|
189
|
+
</Table>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Filterable Headers
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell, Input, Select, Option } from '@delightui/components';
|
|
198
|
+
|
|
199
|
+
function FilterableHeaderExample() {
|
|
200
|
+
const [nameFilter, setNameFilter] = useState('');
|
|
201
|
+
const [departmentFilter, setDepartmentFilter] = useState('');
|
|
202
|
+
|
|
203
|
+
const employees = [
|
|
204
|
+
{ name: 'John Smith', department: 'Engineering', level: 'Senior', salary: 85000 },
|
|
205
|
+
{ name: 'Sarah Davis', department: 'Marketing', level: 'Mid', salary: 65000 },
|
|
206
|
+
{ name: 'Mike Johnson', department: 'Engineering', level: 'Junior', salary: 55000 },
|
|
207
|
+
{ name: 'Lisa Brown', department: 'Design', level: 'Senior', salary: 75000 },
|
|
208
|
+
{ name: 'Tom Wilson', department: 'Marketing', level: 'Senior', salary: 70000 }
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
const departments = ['All', ...new Set(employees.map(emp => emp.department))];
|
|
212
|
+
|
|
213
|
+
const filteredEmployees = employees.filter(employee => {
|
|
214
|
+
const matchesName = employee.name.toLowerCase().includes(nameFilter.toLowerCase());
|
|
215
|
+
const matchesDepartment = departmentFilter === '' || departmentFilter === 'All' || employee.department === departmentFilter;
|
|
216
|
+
return matchesName && matchesDepartment;
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<div>
|
|
221
|
+
<Table>
|
|
222
|
+
<TableHeader>
|
|
223
|
+
<TableRow>
|
|
224
|
+
<TableHeaderCell>
|
|
225
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
226
|
+
<span>Employee Name</span>
|
|
227
|
+
<Input
|
|
228
|
+
placeholder="Filter by name..."
|
|
229
|
+
value={nameFilter}
|
|
230
|
+
onValueChange={setNameFilter}
|
|
231
|
+
size="Small"
|
|
232
|
+
/>
|
|
233
|
+
</div>
|
|
234
|
+
</TableHeaderCell>
|
|
235
|
+
<TableHeaderCell>
|
|
236
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
237
|
+
<span>Department</span>
|
|
238
|
+
<Select value={departmentFilter} onValueChange={setDepartmentFilter}>
|
|
239
|
+
{departments.map(dept => (
|
|
240
|
+
<Option key={dept} value={dept}>{dept}</Option>
|
|
241
|
+
))}
|
|
242
|
+
</Select>
|
|
243
|
+
</div>
|
|
244
|
+
</TableHeaderCell>
|
|
245
|
+
<TableHeaderCell>Level</TableHeaderCell>
|
|
246
|
+
<TableHeaderCell>Salary</TableHeaderCell>
|
|
247
|
+
</TableRow>
|
|
248
|
+
</TableHeader>
|
|
249
|
+
<TableBody>
|
|
250
|
+
{filteredEmployees.map((employee, index) => (
|
|
251
|
+
<TableRow key={index}>
|
|
252
|
+
<TableCell>{employee.name}</TableCell>
|
|
253
|
+
<TableCell>{employee.department}</TableCell>
|
|
254
|
+
<TableCell>{employee.level}</TableCell>
|
|
255
|
+
<TableCell>${employee.salary.toLocaleString()}</TableCell>
|
|
256
|
+
</TableRow>
|
|
257
|
+
))}
|
|
258
|
+
</TableBody>
|
|
259
|
+
</Table>
|
|
260
|
+
</div>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Styled Header Cells
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell, Text } from '@delightui/components';
|
|
269
|
+
|
|
270
|
+
function StyledHeaderExample() {
|
|
271
|
+
const performanceData = [
|
|
272
|
+
{ metric: 'Page Views', current: 125000, previous: 115000, change: 8.7 },
|
|
273
|
+
{ metric: 'Unique Visitors', current: 45000, previous: 42000, change: 7.1 },
|
|
274
|
+
{ metric: 'Bounce Rate', current: 35.2, previous: 38.1, change: -7.6 },
|
|
275
|
+
{ metric: 'Conversion Rate', current: 3.4, previous: 3.1, change: 9.7 }
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
return (
|
|
279
|
+
<Table>
|
|
280
|
+
<TableHeader>
|
|
281
|
+
<TableRow>
|
|
282
|
+
<TableHeaderCell style={{
|
|
283
|
+
backgroundColor: '#f8f9fa',
|
|
284
|
+
fontWeight: 'bold',
|
|
285
|
+
textAlign: 'left',
|
|
286
|
+
padding: '16px'
|
|
287
|
+
}}>
|
|
288
|
+
Performance Metric
|
|
289
|
+
</TableHeaderCell>
|
|
290
|
+
<TableHeaderCell style={{
|
|
291
|
+
backgroundColor: '#e3f2fd',
|
|
292
|
+
fontWeight: 'bold',
|
|
293
|
+
textAlign: 'center',
|
|
294
|
+
padding: '16px'
|
|
295
|
+
}}>
|
|
296
|
+
Current Period
|
|
297
|
+
</TableHeaderCell>
|
|
298
|
+
<TableHeaderCell style={{
|
|
299
|
+
backgroundColor: '#f3e5f5',
|
|
300
|
+
fontWeight: 'bold',
|
|
301
|
+
textAlign: 'center',
|
|
302
|
+
padding: '16px'
|
|
303
|
+
}}>
|
|
304
|
+
Previous Period
|
|
305
|
+
</TableHeaderCell>
|
|
306
|
+
<TableHeaderCell style={{
|
|
307
|
+
backgroundColor: '#e8f5e8',
|
|
308
|
+
fontWeight: 'bold',
|
|
309
|
+
textAlign: 'center',
|
|
310
|
+
padding: '16px'
|
|
311
|
+
}}>
|
|
312
|
+
% Change
|
|
313
|
+
</TableHeaderCell>
|
|
314
|
+
</TableRow>
|
|
315
|
+
</TableHeader>
|
|
316
|
+
<TableBody>
|
|
317
|
+
{performanceData.map((data, index) => (
|
|
318
|
+
<TableRow key={index}>
|
|
319
|
+
<TableCell style={{ fontWeight: 'bold' }}>{data.metric}</TableCell>
|
|
320
|
+
<TableCell style={{ textAlign: 'center' }}>
|
|
321
|
+
{data.metric.includes('Rate') ? `${data.current}%` : data.current.toLocaleString()}
|
|
322
|
+
</TableCell>
|
|
323
|
+
<TableCell style={{ textAlign: 'center' }}>
|
|
324
|
+
{data.metric.includes('Rate') ? `${data.previous}%` : data.previous.toLocaleString()}
|
|
325
|
+
</TableCell>
|
|
326
|
+
<TableCell style={{
|
|
327
|
+
textAlign: 'center',
|
|
328
|
+
color: data.change > 0 ? '#2e7d32' : '#d32f2f',
|
|
329
|
+
fontWeight: 'bold'
|
|
330
|
+
}}>
|
|
331
|
+
{data.change > 0 ? '+' : ''}{data.change.toFixed(1)}%
|
|
332
|
+
</TableCell>
|
|
333
|
+
</TableRow>
|
|
334
|
+
))}
|
|
335
|
+
</TableBody>
|
|
336
|
+
</Table>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Headers with Icons
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell, Icon, Text } from '@delightui/components';
|
|
345
|
+
|
|
346
|
+
function IconHeaderExample() {
|
|
347
|
+
const taskData = [
|
|
348
|
+
{ title: 'Update Homepage', assignee: 'John Doe', priority: 'High', status: 'In Progress', dueDate: '2024-02-15' },
|
|
349
|
+
{ title: 'Fix Login Bug', assignee: 'Jane Smith', priority: 'Critical', status: 'Open', dueDate: '2024-02-10' },
|
|
350
|
+
{ title: 'Design New Logo', assignee: 'Mike Wilson', priority: 'Medium', status: 'Complete', dueDate: '2024-02-20' }
|
|
351
|
+
];
|
|
352
|
+
|
|
353
|
+
const getPriorityColor = (priority: string) => {
|
|
354
|
+
switch (priority) {
|
|
355
|
+
case 'Critical': return '#d32f2f';
|
|
356
|
+
case 'High': return '#f57c00';
|
|
357
|
+
case 'Medium': return '#1976d2';
|
|
358
|
+
default: return '#757575';
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const getStatusIcon = (status: string) => {
|
|
363
|
+
switch (status) {
|
|
364
|
+
case 'Complete': return '✅';
|
|
365
|
+
case 'In Progress': return '⏳';
|
|
366
|
+
case 'Open': return '📋';
|
|
367
|
+
default: return '❓';
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<Table>
|
|
373
|
+
<TableHeader>
|
|
374
|
+
<TableRow>
|
|
375
|
+
<TableHeaderCell>
|
|
376
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
377
|
+
<Icon name="ListItem" />
|
|
378
|
+
<Text weight="Bold">Task</Text>
|
|
379
|
+
</div>
|
|
380
|
+
</TableHeaderCell>
|
|
381
|
+
<TableHeaderCell>
|
|
382
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
383
|
+
<Icon name="Person" />
|
|
384
|
+
<Text weight="Bold">Assignee</Text>
|
|
385
|
+
</div>
|
|
386
|
+
</TableHeaderCell>
|
|
387
|
+
<TableHeaderCell>
|
|
388
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
389
|
+
<Icon name="Priority" />
|
|
390
|
+
<Text weight="Bold">Priority</Text>
|
|
391
|
+
</div>
|
|
392
|
+
</TableHeaderCell>
|
|
393
|
+
<TableHeaderCell>
|
|
394
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
395
|
+
<Icon name="Status" />
|
|
396
|
+
<Text weight="Bold">Status</Text>
|
|
397
|
+
</div>
|
|
398
|
+
</TableHeaderCell>
|
|
399
|
+
<TableHeaderCell>
|
|
400
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
401
|
+
<Icon name="Calendar" />
|
|
402
|
+
<Text weight="Bold">Due Date</Text>
|
|
403
|
+
</div>
|
|
404
|
+
</TableHeaderCell>
|
|
405
|
+
</TableRow>
|
|
406
|
+
</TableHeader>
|
|
407
|
+
<TableBody>
|
|
408
|
+
{taskData.map((task, index) => (
|
|
409
|
+
<TableRow key={index}>
|
|
410
|
+
<TableCell>{task.title}</TableCell>
|
|
411
|
+
<TableCell>{task.assignee}</TableCell>
|
|
412
|
+
<TableCell>
|
|
413
|
+
<Text style={{ color: getPriorityColor(task.priority), fontWeight: 'bold' }}>
|
|
414
|
+
{task.priority}
|
|
415
|
+
</Text>
|
|
416
|
+
</TableCell>
|
|
417
|
+
<TableCell>
|
|
418
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
419
|
+
<span>{getStatusIcon(task.status)}</span>
|
|
420
|
+
<Text>{task.status}</Text>
|
|
421
|
+
</div>
|
|
422
|
+
</TableCell>
|
|
423
|
+
<TableCell>{task.dueDate}</TableCell>
|
|
424
|
+
</TableRow>
|
|
425
|
+
))}
|
|
426
|
+
</TableBody>
|
|
427
|
+
</Table>
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Resizable Headers
|
|
433
|
+
|
|
434
|
+
```tsx
|
|
435
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell } from '@delightui/components';
|
|
436
|
+
|
|
437
|
+
function ResizableHeaderExample() {
|
|
438
|
+
const [columnWidths, setColumnWidths] = useState({
|
|
439
|
+
name: 200,
|
|
440
|
+
email: 250,
|
|
441
|
+
phone: 150,
|
|
442
|
+
department: 150
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const contacts = [
|
|
446
|
+
{ name: 'Alice Johnson', email: 'alice.johnson@company.com', phone: '+1-555-0101', department: 'Engineering' },
|
|
447
|
+
{ name: 'Bob Smith', email: 'bob.smith@company.com', phone: '+1-555-0102', department: 'Marketing' },
|
|
448
|
+
{ name: 'Carol Brown', email: 'carol.brown@company.com', phone: '+1-555-0103', department: 'Design' }
|
|
449
|
+
];
|
|
450
|
+
|
|
451
|
+
const handleResize = (column: string, newWidth: number) => {
|
|
452
|
+
setColumnWidths(prev => ({
|
|
453
|
+
...prev,
|
|
454
|
+
[column]: Math.max(100, newWidth)
|
|
455
|
+
}));
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
return (
|
|
459
|
+
<div style={{ overflowX: 'auto' }}>
|
|
460
|
+
<Table style={{ tableLayout: 'fixed', width: '100%' }}>
|
|
461
|
+
<TableHeader>
|
|
462
|
+
<TableRow>
|
|
463
|
+
<TableHeaderCell
|
|
464
|
+
style={{
|
|
465
|
+
width: `${columnWidths.name}px`,
|
|
466
|
+
position: 'relative',
|
|
467
|
+
minWidth: '100px'
|
|
468
|
+
}}
|
|
469
|
+
>
|
|
470
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
471
|
+
<span>Name</span>
|
|
472
|
+
<div
|
|
473
|
+
style={{
|
|
474
|
+
cursor: 'col-resize',
|
|
475
|
+
padding: '0 4px',
|
|
476
|
+
userSelect: 'none'
|
|
477
|
+
}}
|
|
478
|
+
onMouseDown={(e) => {
|
|
479
|
+
const startX = e.clientX;
|
|
480
|
+
const startWidth = columnWidths.name;
|
|
481
|
+
|
|
482
|
+
const handleMouseMove = (moveEvent: MouseEvent) => {
|
|
483
|
+
const newWidth = startWidth + (moveEvent.clientX - startX);
|
|
484
|
+
handleResize('name', newWidth);
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
const handleMouseUp = () => {
|
|
488
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
489
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
493
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
494
|
+
}}
|
|
495
|
+
>
|
|
496
|
+
⚊
|
|
497
|
+
</div>
|
|
498
|
+
</div>
|
|
499
|
+
</TableHeaderCell>
|
|
500
|
+
<TableHeaderCell style={{ width: `${columnWidths.email}px` }}>
|
|
501
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
502
|
+
<span>Email</span>
|
|
503
|
+
<div
|
|
504
|
+
style={{ cursor: 'col-resize', padding: '0 4px' }}
|
|
505
|
+
onMouseDown={(e) => {
|
|
506
|
+
const startX = e.clientX;
|
|
507
|
+
const startWidth = columnWidths.email;
|
|
508
|
+
|
|
509
|
+
const handleMouseMove = (moveEvent: MouseEvent) => {
|
|
510
|
+
const newWidth = startWidth + (moveEvent.clientX - startX);
|
|
511
|
+
handleResize('email', newWidth);
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
const handleMouseUp = () => {
|
|
515
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
516
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
520
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
521
|
+
}}
|
|
522
|
+
>
|
|
523
|
+
⚊
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
</TableHeaderCell>
|
|
527
|
+
<TableHeaderCell style={{ width: `${columnWidths.phone}px` }}>Phone</TableHeaderCell>
|
|
528
|
+
<TableHeaderCell style={{ width: `${columnWidths.department}px` }}>Department</TableHeaderCell>
|
|
529
|
+
</TableRow>
|
|
530
|
+
</TableHeader>
|
|
531
|
+
<TableBody>
|
|
532
|
+
{contacts.map((contact, index) => (
|
|
533
|
+
<TableRow key={index}>
|
|
534
|
+
<TableCell style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
535
|
+
{contact.name}
|
|
536
|
+
</TableCell>
|
|
537
|
+
<TableCell style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
538
|
+
{contact.email}
|
|
539
|
+
</TableCell>
|
|
540
|
+
<TableCell>{contact.phone}</TableCell>
|
|
541
|
+
<TableCell>{contact.department}</TableCell>
|
|
542
|
+
</TableRow>
|
|
543
|
+
))}
|
|
544
|
+
</TableBody>
|
|
545
|
+
</Table>
|
|
546
|
+
</div>
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Accessibility Enhanced Headers
|
|
552
|
+
|
|
553
|
+
```tsx
|
|
554
|
+
import { Table, TableBody, TableRow, TableHeaderCell, TableHeader, TableCell } from '@delightui/components';
|
|
555
|
+
|
|
556
|
+
function AccessibleHeaderExample() {
|
|
557
|
+
const studentGrades = [
|
|
558
|
+
{ student: 'Emma Wilson', math: 92, science: 88, english: 95, history: 90 },
|
|
559
|
+
{ student: 'Liam Johnson', math: 85, science: 91, english: 87, history: 93 },
|
|
560
|
+
{ student: 'Olivia Brown', math: 96, science: 94, english: 92, history: 89 }
|
|
561
|
+
];
|
|
562
|
+
|
|
563
|
+
return (
|
|
564
|
+
<Table
|
|
565
|
+
role="table"
|
|
566
|
+
aria-label="Student Grade Report"
|
|
567
|
+
>
|
|
568
|
+
<TableHeader>
|
|
569
|
+
<TableRow role="row">
|
|
570
|
+
<TableHeaderCell
|
|
571
|
+
id="student-header"
|
|
572
|
+
scope="col"
|
|
573
|
+
role="columnheader"
|
|
574
|
+
aria-sort="none"
|
|
575
|
+
tabIndex={0}
|
|
576
|
+
>
|
|
577
|
+
Student Name
|
|
578
|
+
</TableHeaderCell>
|
|
579
|
+
<TableHeaderCell
|
|
580
|
+
id="math-header"
|
|
581
|
+
scope="col"
|
|
582
|
+
role="columnheader"
|
|
583
|
+
aria-sort="none"
|
|
584
|
+
tabIndex={0}
|
|
585
|
+
>
|
|
586
|
+
Mathematics
|
|
587
|
+
</TableHeaderCell>
|
|
588
|
+
<TableHeaderCell
|
|
589
|
+
id="science-header"
|
|
590
|
+
scope="col"
|
|
591
|
+
role="columnheader"
|
|
592
|
+
aria-sort="none"
|
|
593
|
+
tabIndex={0}
|
|
594
|
+
>
|
|
595
|
+
Science
|
|
596
|
+
</TableHeaderCell>
|
|
597
|
+
<TableHeaderCell
|
|
598
|
+
id="english-header"
|
|
599
|
+
scope="col"
|
|
600
|
+
role="columnheader"
|
|
601
|
+
aria-sort="none"
|
|
602
|
+
tabIndex={0}
|
|
603
|
+
>
|
|
604
|
+
English
|
|
605
|
+
</TableHeaderCell>
|
|
606
|
+
<TableHeaderCell
|
|
607
|
+
id="history-header"
|
|
608
|
+
scope="col"
|
|
609
|
+
role="columnheader"
|
|
610
|
+
aria-sort="none"
|
|
611
|
+
tabIndex={0}
|
|
612
|
+
>
|
|
613
|
+
History
|
|
614
|
+
</TableHeaderCell>
|
|
615
|
+
</TableRow>
|
|
616
|
+
</TableHeader>
|
|
617
|
+
<TableBody>
|
|
618
|
+
{studentGrades.map((grades, index) => (
|
|
619
|
+
<TableRow key={index} role="row">
|
|
620
|
+
<TableCell
|
|
621
|
+
headers="student-header"
|
|
622
|
+
role="rowheader"
|
|
623
|
+
scope="row"
|
|
624
|
+
>
|
|
625
|
+
{grades.student}
|
|
626
|
+
</TableCell>
|
|
627
|
+
<TableCell
|
|
628
|
+
headers="math-header"
|
|
629
|
+
role="cell"
|
|
630
|
+
aria-label={`Mathematics grade: ${grades.math} out of 100`}
|
|
631
|
+
>
|
|
632
|
+
{grades.math}%
|
|
633
|
+
</TableCell>
|
|
634
|
+
<TableCell
|
|
635
|
+
headers="science-header"
|
|
636
|
+
role="cell"
|
|
637
|
+
aria-label={`Science grade: ${grades.science} out of 100`}
|
|
638
|
+
>
|
|
639
|
+
{grades.science}%
|
|
640
|
+
</TableCell>
|
|
641
|
+
<TableCell
|
|
642
|
+
headers="english-header"
|
|
643
|
+
role="cell"
|
|
644
|
+
aria-label={`English grade: ${grades.english} out of 100`}
|
|
645
|
+
>
|
|
646
|
+
{grades.english}%
|
|
647
|
+
</TableCell>
|
|
648
|
+
<TableCell
|
|
649
|
+
headers="history-header"
|
|
650
|
+
role="cell"
|
|
651
|
+
aria-label={`History grade: ${grades.history} out of 100`}
|
|
652
|
+
>
|
|
653
|
+
{grades.history}%
|
|
654
|
+
</TableCell>
|
|
655
|
+
</TableRow>
|
|
656
|
+
))}
|
|
657
|
+
</TableBody>
|
|
658
|
+
</Table>
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
```
|