@tcn/ui 0.7.0 → 0.8.1
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/{Color-6BZIO3FS-CWWwv-fq.js → Color-6BZIO3FS-C9xkPWgz.js} +2 -2
- package/dist/{Color-6BZIO3FS-CWWwv-fq.js.map → Color-6BZIO3FS-C9xkPWgz.js.map} +1 -1
- package/dist/{WithTooltip-65CFNBJE-DvcUZizH.js → WithTooltip-65CFNBJE-DEnh547F.js} +2 -2
- package/dist/{WithTooltip-65CFNBJE-DvcUZizH.js.map → WithTooltip-65CFNBJE-DEnh547F.js.map} +1 -1
- package/dist/actions/__docs__/components/showcase.js +1 -1
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +8 -6
- package/dist/actions/index.js.map +1 -1
- package/dist/body.css +1 -0
- package/dist/form/field_presenters/field_presenter.d.ts +2 -2
- package/dist/form/field_presenters/field_presenter.d.ts.map +1 -1
- package/dist/form/field_presenters/field_presenter.js.map +1 -1
- package/dist/formatter-EIJCOSYU-DWmgEY3b.js +6 -0
- package/dist/{formatter-EIJCOSYU-D6nmx63h.js.map → formatter-EIJCOSYU-DWmgEY3b.js.map} +1 -1
- package/dist/inputs/color_input/color_input.js +10 -9
- package/dist/inputs/color_input/color_input.js.map +1 -1
- package/dist/inputs/date_picker/date_picker_header.js +7 -6
- package/dist/inputs/date_picker/date_picker_header.js.map +1 -1
- package/dist/inputs/date_picker/date_picker_input.js +3 -2
- package/dist/inputs/date_picker/date_picker_input.js.map +1 -1
- package/dist/inputs/date_picker/date_picker_time_selector.js +3 -2
- package/dist/inputs/date_picker/date_picker_time_selector.js.map +1 -1
- package/dist/inputs/date_picker/date_picker_year_input.js +6 -5
- package/dist/inputs/date_picker/date_picker_year_input.js.map +1 -1
- package/dist/inputs/date_picker/date_picker_year_selector.js +3 -2
- package/dist/inputs/date_picker/date_picker_year_selector.js.map +1 -1
- package/dist/inputs/multiselect/multiselect_inline_values.js +8 -7
- package/dist/inputs/multiselect/multiselect_inline_values.js.map +1 -1
- package/dist/inputs/multiselect/multiselect_values.js +3 -2
- package/dist/inputs/multiselect/multiselect_values.js.map +1 -1
- package/dist/inputs/phone_number_input/phone_number_input.js +44 -43
- package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
- package/dist/inputs/select/select.js +3 -2
- package/dist/inputs/select/select.js.map +1 -1
- package/dist/inputs/suggestions/suggestion_list.js +3 -2
- package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
- package/dist/layouts/body/body.d.ts +6 -0
- package/dist/layouts/body/body.d.ts.map +1 -0
- package/dist/layouts/body/body.js +21 -0
- package/dist/layouts/body/body.js.map +1 -0
- package/dist/layouts/index.d.ts +5 -0
- package/dist/layouts/index.d.ts.map +1 -1
- package/dist/layouts/index.js +38 -22
- package/dist/layouts/index.js.map +1 -1
- package/dist/layouts/rail/main/main.d.ts +6 -0
- package/dist/layouts/rail/main/main.d.ts.map +1 -0
- package/dist/layouts/rail/main/main.js +21 -0
- package/dist/layouts/rail/main/main.js.map +1 -0
- package/dist/layouts/rail/rail.d.ts +9 -0
- package/dist/layouts/rail/rail.d.ts.map +1 -0
- package/dist/layouts/rail/rail.js +55 -0
- package/dist/layouts/rail/rail.js.map +1 -0
- package/dist/layouts/rail/side/side.d.ts +6 -0
- package/dist/layouts/rail/side/side.d.ts.map +1 -0
- package/dist/layouts/rail/side/side.js +21 -0
- package/dist/layouts/rail/side/side.js.map +1 -0
- package/dist/layouts/rail/utility_strip/utility_strip.d.ts +9 -0
- package/dist/layouts/rail/utility_strip/utility_strip.d.ts.map +1 -0
- package/dist/layouts/rail/utility_strip/utility_strip.js +32 -0
- package/dist/layouts/rail/utility_strip/utility_strip.js.map +1 -0
- package/dist/layouts/scaffold/scaffold.js +31 -31
- package/dist/layouts/scaffold/scaffold.js.map +1 -1
- package/dist/layouts/table/table.d.ts +27 -0
- package/dist/layouts/table/table.d.ts.map +1 -0
- package/dist/layouts/table/table.js +70 -0
- package/dist/layouts/table/table.js.map +1 -0
- package/dist/main.css +1 -0
- package/dist/navigation/tabs/primitives/tabs_list.d.ts.map +1 -1
- package/dist/navigation/tabs/primitives/tabs_list.js +61 -21
- package/dist/navigation/tabs/primitives/tabs_list.js.map +1 -1
- package/dist/navigation/tabs/state/link/tab_link.d.ts.map +1 -1
- package/dist/navigation/tabs/state/link/tab_link.js +20 -17
- package/dist/navigation/tabs/state/link/tab_link.js.map +1 -1
- package/dist/navigation/tabs/state/tab.d.ts.map +1 -1
- package/dist/navigation/tabs/state/tab.js +8 -3
- package/dist/navigation/tabs/state/tab.js.map +1 -1
- package/dist/rail.css +1 -0
- package/dist/scaffold.css +1 -1
- package/dist/{showcase-DK557szS.js → showcase-y9D3_Y8T.js} +3413 -3396
- package/dist/showcase-y9D3_Y8T.js.map +1 -0
- package/dist/side.css +1 -0
- package/dist/stacks/box/box.d.ts +2 -2
- package/dist/stacks/box/box.d.ts.map +1 -1
- package/dist/stacks/box/box.js.map +1 -1
- package/dist/stacks/story_components/style_box.d.ts +1 -1
- package/dist/stacks/story_components/style_box.d.ts.map +1 -1
- package/dist/surfaces/alert/alert.js +3 -2
- package/dist/surfaces/alert/alert.js.map +1 -1
- package/dist/surfaces/pop_confirm/pop_confirm.js +13 -2
- package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
- package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js} +2 -2
- package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js.map → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js.map} +1 -1
- package/dist/table.css +1 -0
- package/dist/table.module-BtSxOntS.js +5 -0
- package/dist/table.module-BtSxOntS.js.map +1 -0
- package/dist/themes/themes/ergo/ergo_theme.css +1 -1
- package/dist/themes/themes/ergo/ergo_theme.js +179 -44
- package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
- package/dist/utility_strip.css +1 -0
- package/package.json +2 -2
- package/src/actions/index.ts +1 -0
- package/src/form/field_presenters/field_presenter.ts +3 -3
- package/src/layouts/__stories__/composed.stories.tsx +113 -0
- package/src/layouts/__stories__/composed_stories.module.css +142 -0
- package/src/layouts/__stories__/utils.tsx +174 -0
- package/src/layouts/body/body.module.css +11 -0
- package/src/layouts/body/body.tsx +23 -0
- package/src/layouts/index.ts +10 -0
- package/src/layouts/rail/__stories__/rail.stories.tsx +64 -0
- package/src/layouts/rail/__stories__/rail_stories.module.css +25 -0
- package/src/layouts/rail/main/main.module.css +7 -0
- package/src/layouts/rail/main/main.tsx +26 -0
- package/src/layouts/rail/rail.module.css +10 -0
- package/src/layouts/rail/rail.tsx +62 -0
- package/src/layouts/rail/side/side.module.css +8 -0
- package/src/layouts/rail/side/side.tsx +25 -0
- package/src/layouts/rail/utility_strip/utility_strip.module.css +6 -0
- package/src/layouts/rail/utility_strip/utility_strip.tsx +40 -0
- package/src/layouts/scaffold/__stories__/scaffold.stories.tsx +53 -0
- package/src/layouts/scaffold/__stories__/scaffold_stories.module.css +31 -0
- package/src/layouts/scaffold/scaffold.module.css +4 -0
- package/src/layouts/table/__stories__/mock_data.ts +420 -0
- package/src/layouts/table/__stories__/table.stories.tsx +326 -0
- package/src/layouts/table/__stories__/table_stories.module.css +30 -0
- package/src/layouts/table/table.module.css +37 -0
- package/src/layouts/table/table.tsx +132 -0
- package/src/navigation/tabs/primitives/tabs_list.tsx +46 -2
- package/src/navigation/tabs/state/link/tab_link.tsx +4 -1
- package/src/navigation/tabs/state/tab.tsx +10 -0
- package/src/stacks/box/box.tsx +1 -1
- package/src/surfaces/modal/__stories__/modal.stories.tsx +5 -5
- package/src/surfaces/panel/__stories__/panel.stories.tsx +114 -1
- package/src/surfaces/pop_confirm/pop_confirm.stories.tsx +4 -2
- package/src/themes/themes/ergo/ergo_theme.css +178 -43
- package/dist/formatter-EIJCOSYU-D6nmx63h.js +0 -6
- package/dist/showcase-DK557szS.js.map +0 -1
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { TTable, THead, TBody, TFoot, TR, TH, TD } from '../table.js';
|
|
4
|
+
import { Caption } from '../../../typography/index.js';
|
|
5
|
+
import { HStack, Spacer, VStack } from '../../../stacks/index.js';
|
|
6
|
+
import { Button } from '../../../actions/index.js';
|
|
7
|
+
import { SearchIcon } from '@tcn/icons/search_icon.js';
|
|
8
|
+
import { FilterOneIcon } from '@tcn/icons/filter_one_icon.js';
|
|
9
|
+
import { TwoClassSortIcon } from '@tcn/icons/two_class_sort_icon.js';
|
|
10
|
+
import { EditOneIcon } from '@tcn/icons/edit_one_icon.js';
|
|
11
|
+
import { TrashOneIcon } from '@tcn/icons/trash_one_icon.js';
|
|
12
|
+
import { CopyIcon } from '@tcn/icons/copy_icon.js';
|
|
13
|
+
import { Chip } from '../../../tokens/index.js';
|
|
14
|
+
import {
|
|
15
|
+
sb_tableMockData,
|
|
16
|
+
sb_tableGroupedMockData,
|
|
17
|
+
sb_tableStatusLabels,
|
|
18
|
+
type SBTableData,
|
|
19
|
+
sb_tableGroupedStats,
|
|
20
|
+
} from './mock_data.js';
|
|
21
|
+
import { CloudLightningIcon } from '@tcn/icons/cloud_lightning_icon.js';
|
|
22
|
+
import styles from './table_stories.module.css';
|
|
23
|
+
|
|
24
|
+
const meta: Meta<typeof TTable> = {
|
|
25
|
+
title: 'Layouts/Table',
|
|
26
|
+
component: TTable,
|
|
27
|
+
tags: ['autodocs'],
|
|
28
|
+
parameters: {
|
|
29
|
+
docs: {
|
|
30
|
+
description: {
|
|
31
|
+
component:
|
|
32
|
+
'Semantic table layout components. Structure follows: caption, thead, tbody, tfoot, with proper scope and colSpan for accessibility.',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default meta;
|
|
39
|
+
|
|
40
|
+
type Story = StoryObj<typeof TTable>;
|
|
41
|
+
|
|
42
|
+
const TableWrapper = ({ children }: { children: React.ReactNode }) => {
|
|
43
|
+
return (
|
|
44
|
+
<VStack padding="16px" height="100%" width="100%" maxHeight="500px">
|
|
45
|
+
{children}
|
|
46
|
+
</VStack>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const ExampleRow: React.FC<{ item: SBTableData }> = ({ item }) => {
|
|
51
|
+
return (
|
|
52
|
+
<TR isSelected={item.selected}>
|
|
53
|
+
<TH scope="row">{item.name}</TH>
|
|
54
|
+
<TD>{item.description}</TD>
|
|
55
|
+
<TD>{item.age}</TD>
|
|
56
|
+
<TD>{item.date.toLocaleDateString()}</TD>
|
|
57
|
+
<TD>
|
|
58
|
+
<Chip className={styles.chip} data-status={item.status}>
|
|
59
|
+
{sb_tableStatusLabels[item.status]}
|
|
60
|
+
</Chip>
|
|
61
|
+
</TD>
|
|
62
|
+
<TH scope="row">
|
|
63
|
+
<HStack gap="4px">
|
|
64
|
+
<Button utility hierarchy="tertiary" severity="dangerous">
|
|
65
|
+
<TrashOneIcon />
|
|
66
|
+
</Button>
|
|
67
|
+
<Button utility hierarchy="tertiary">
|
|
68
|
+
<CopyIcon />
|
|
69
|
+
</Button>
|
|
70
|
+
<Button utility hierarchy="tertiary">
|
|
71
|
+
<EditOneIcon />
|
|
72
|
+
</Button>
|
|
73
|
+
<Button utility hierarchy="primary">
|
|
74
|
+
<CloudLightningIcon />
|
|
75
|
+
</Button>
|
|
76
|
+
</HStack>
|
|
77
|
+
</TH>
|
|
78
|
+
</TR>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const ExampleHeader: React.FC<{
|
|
83
|
+
title: string;
|
|
84
|
+
canSort?: boolean;
|
|
85
|
+
canFilter?: boolean;
|
|
86
|
+
canSearch?: boolean;
|
|
87
|
+
}> = ({ title, canSort, canFilter, canSearch }) => {
|
|
88
|
+
return (
|
|
89
|
+
<TH scope="col">
|
|
90
|
+
<HStack gap="8px">
|
|
91
|
+
{title}
|
|
92
|
+
<Spacer />
|
|
93
|
+
<HStack gap="2px" minWidth="min-content" growWeight={0}>
|
|
94
|
+
{canSearch && (
|
|
95
|
+
<Button utility hierarchy="tertiary">
|
|
96
|
+
<SearchIcon />
|
|
97
|
+
</Button>
|
|
98
|
+
)}
|
|
99
|
+
{canFilter && (
|
|
100
|
+
<Button utility hierarchy="tertiary">
|
|
101
|
+
<FilterOneIcon />
|
|
102
|
+
</Button>
|
|
103
|
+
)}
|
|
104
|
+
{canSort && (
|
|
105
|
+
<Button utility hierarchy="tertiary">
|
|
106
|
+
<TwoClassSortIcon />
|
|
107
|
+
</Button>
|
|
108
|
+
)}
|
|
109
|
+
</HStack>
|
|
110
|
+
</HStack>
|
|
111
|
+
</TH>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Table structured like the [MDN table example](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table):
|
|
116
|
+
* caption, column headers with `scope="col"`, row headers with `scope="row"`, and a footer with a spanning cell.
|
|
117
|
+
*/
|
|
118
|
+
export const Baseline: Story = {
|
|
119
|
+
render: () => (
|
|
120
|
+
<TableWrapper>
|
|
121
|
+
<TTable>
|
|
122
|
+
<caption>
|
|
123
|
+
<Caption>Example description of the a table (caption)</Caption>
|
|
124
|
+
</caption>
|
|
125
|
+
<THead>
|
|
126
|
+
<TR>
|
|
127
|
+
<ExampleHeader title="Name" canSort canFilter canSearch />
|
|
128
|
+
<ExampleHeader title="Description" canSort canFilter canSearch />
|
|
129
|
+
<ExampleHeader title="Age" canSort canFilter canSearch />
|
|
130
|
+
<ExampleHeader title="Date" canSort canFilter canSearch />
|
|
131
|
+
<ExampleHeader title="Status" canSort canFilter canSearch />
|
|
132
|
+
<TH scope="col">Actions</TH>
|
|
133
|
+
</TR>
|
|
134
|
+
</THead>
|
|
135
|
+
<TBody>
|
|
136
|
+
{sb_tableMockData.map(item => (
|
|
137
|
+
<ExampleRow key={item.name} item={item} />
|
|
138
|
+
))}
|
|
139
|
+
</TBody>
|
|
140
|
+
<TFoot>
|
|
141
|
+
<TR>
|
|
142
|
+
<TH scope="row" colSpan={5}>
|
|
143
|
+
Total:
|
|
144
|
+
</TH>
|
|
145
|
+
<TD>33</TD>
|
|
146
|
+
</TR>
|
|
147
|
+
</TFoot>
|
|
148
|
+
</TTable>
|
|
149
|
+
</TableWrapper>
|
|
150
|
+
),
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export const MaxDimensions: Story = {
|
|
154
|
+
render: () => (
|
|
155
|
+
<TableWrapper>
|
|
156
|
+
<TTable style={{ height: '300px', width: '400px' }}>
|
|
157
|
+
<caption>
|
|
158
|
+
<Caption>Example description of the a table (caption)</Caption>
|
|
159
|
+
</caption>
|
|
160
|
+
<THead>
|
|
161
|
+
<TR>
|
|
162
|
+
<ExampleHeader title="Name" canSort canFilter canSearch />
|
|
163
|
+
<ExampleHeader title="Description" canSort canFilter canSearch />
|
|
164
|
+
<ExampleHeader title="Age" canSort canFilter canSearch />
|
|
165
|
+
<ExampleHeader title="Date" canSort canFilter canSearch />
|
|
166
|
+
<ExampleHeader title="Status" canSort canFilter canSearch />
|
|
167
|
+
<TH scope="col">Actions</TH>
|
|
168
|
+
</TR>
|
|
169
|
+
</THead>
|
|
170
|
+
<TBody>
|
|
171
|
+
{sb_tableMockData.map(item => (
|
|
172
|
+
<ExampleRow key={item.name} item={item} />
|
|
173
|
+
))}
|
|
174
|
+
</TBody>
|
|
175
|
+
<TFoot>
|
|
176
|
+
<TR>
|
|
177
|
+
<TH scope="row" colSpan={5}>
|
|
178
|
+
Total:
|
|
179
|
+
</TH>
|
|
180
|
+
<TD>33</TD>
|
|
181
|
+
</TR>
|
|
182
|
+
</TFoot>
|
|
183
|
+
</TTable>
|
|
184
|
+
</TableWrapper>
|
|
185
|
+
),
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const Sticky: Story = {
|
|
189
|
+
render: () => (
|
|
190
|
+
<TableWrapper>
|
|
191
|
+
<TTable sticky>
|
|
192
|
+
<caption>
|
|
193
|
+
<Caption>Example description of the a table (caption)</Caption>
|
|
194
|
+
</caption>
|
|
195
|
+
<THead>
|
|
196
|
+
<TR>
|
|
197
|
+
<ExampleHeader title="Name" canSort canFilter canSearch />
|
|
198
|
+
<ExampleHeader title="Description" canSort canFilter canSearch />
|
|
199
|
+
<ExampleHeader title="Age" canSort canFilter canSearch />
|
|
200
|
+
<ExampleHeader title="Date" canSort canFilter canSearch />
|
|
201
|
+
<ExampleHeader title="Status" canSort canFilter canSearch />
|
|
202
|
+
<TH scope="col">Actions</TH>
|
|
203
|
+
</TR>
|
|
204
|
+
</THead>
|
|
205
|
+
<TBody>
|
|
206
|
+
{sb_tableMockData.map(item => (
|
|
207
|
+
<ExampleRow key={item.name} item={item} />
|
|
208
|
+
))}
|
|
209
|
+
</TBody>
|
|
210
|
+
<TFoot>
|
|
211
|
+
<TR>
|
|
212
|
+
<TH align="right">Total: 33</TH>
|
|
213
|
+
<TH scope="row" colSpan={4} />
|
|
214
|
+
<TH scope="row" />
|
|
215
|
+
</TR>
|
|
216
|
+
</TFoot>
|
|
217
|
+
</TTable>
|
|
218
|
+
</TableWrapper>
|
|
219
|
+
),
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const formatNumber = (number: number) => {
|
|
223
|
+
return number.toFixed(2);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
export const SpanningCell: Story = {
|
|
227
|
+
render: () => (
|
|
228
|
+
<TableWrapper>
|
|
229
|
+
<TTable sticky>
|
|
230
|
+
<caption>
|
|
231
|
+
<Caption>Example description of the a table (caption)</Caption>
|
|
232
|
+
</caption>
|
|
233
|
+
<colgroup span={2}>Name</colgroup>
|
|
234
|
+
<THead>
|
|
235
|
+
<TR>
|
|
236
|
+
<TH scope="colgroup" colSpan={2}>
|
|
237
|
+
Personal Info
|
|
238
|
+
</TH>
|
|
239
|
+
<TH scope="colgroup" colSpan={3}>
|
|
240
|
+
Employment
|
|
241
|
+
</TH>
|
|
242
|
+
<TH scope="colgroup" colSpan={6}>
|
|
243
|
+
Performance
|
|
244
|
+
</TH>
|
|
245
|
+
<TH scope="row" />
|
|
246
|
+
</TR>
|
|
247
|
+
<TR>
|
|
248
|
+
<TH scope="col">First Name</TH>
|
|
249
|
+
<TH scope="col">Last Name</TH>
|
|
250
|
+
<TH scope="col">Branch</TH>
|
|
251
|
+
<TH scope="col">Department</TH>
|
|
252
|
+
<TH scope="col">Role</TH>
|
|
253
|
+
<TH scope="col">Q1</TH>
|
|
254
|
+
<TH scope="col">Q2</TH>
|
|
255
|
+
<TH scope="col">Q3</TH>
|
|
256
|
+
<TH scope="col">Q4</TH>
|
|
257
|
+
<TH scope="col">Score</TH>
|
|
258
|
+
<TH scope="col">Last Review</TH>
|
|
259
|
+
<TH scope="col">Actions</TH>
|
|
260
|
+
</TR>
|
|
261
|
+
</THead>
|
|
262
|
+
<TBody>
|
|
263
|
+
{sb_tableGroupedMockData.map((row, i) => (
|
|
264
|
+
<TR key={i}>
|
|
265
|
+
<TH>{row.firstName}</TH>
|
|
266
|
+
<TD>{row.lastName}</TD>
|
|
267
|
+
<TD>{row.branch}</TD>
|
|
268
|
+
<TD>{row.department}</TD>
|
|
269
|
+
<TD>{row.role}</TD>
|
|
270
|
+
<TD>{row.q1}</TD>
|
|
271
|
+
<TD>{row.q2}</TD>
|
|
272
|
+
<TD>{row.q3}</TD>
|
|
273
|
+
<TD>{row.q4}</TD>
|
|
274
|
+
<TD>{row.score}</TD>
|
|
275
|
+
<TD>{row.lastReview}</TD>
|
|
276
|
+
<TH scope="row">
|
|
277
|
+
<HStack gap="4px">
|
|
278
|
+
<Button utility hierarchy="tertiary" severity="dangerous">
|
|
279
|
+
<TrashOneIcon />
|
|
280
|
+
</Button>
|
|
281
|
+
<Button utility hierarchy="tertiary">
|
|
282
|
+
<CopyIcon />
|
|
283
|
+
</Button>
|
|
284
|
+
<Button utility hierarchy="tertiary">
|
|
285
|
+
<EditOneIcon />
|
|
286
|
+
</Button>
|
|
287
|
+
<Button utility hierarchy="primary">
|
|
288
|
+
<CloudLightningIcon />
|
|
289
|
+
</Button>
|
|
290
|
+
</HStack>
|
|
291
|
+
</TH>
|
|
292
|
+
</TR>
|
|
293
|
+
))}
|
|
294
|
+
</TBody>
|
|
295
|
+
<TFoot>
|
|
296
|
+
<TR>
|
|
297
|
+
<TD scope="row" colSpan={4} />
|
|
298
|
+
<TH scope="row" align="right">
|
|
299
|
+
Totals:
|
|
300
|
+
</TH>
|
|
301
|
+
<TD>{formatNumber(sb_tableGroupedStats.totals.q1)}</TD>
|
|
302
|
+
<TD>{formatNumber(sb_tableGroupedStats.totals.q2)}</TD>
|
|
303
|
+
<TD>{formatNumber(sb_tableGroupedStats.totals.q3)}</TD>
|
|
304
|
+
<TD>{formatNumber(sb_tableGroupedStats.totals.q4)}</TD>
|
|
305
|
+
<TD>{formatNumber(sb_tableGroupedStats.year)}</TD>
|
|
306
|
+
<TD />
|
|
307
|
+
<TD />
|
|
308
|
+
</TR>
|
|
309
|
+
<TR>
|
|
310
|
+
<TD scope="row" colSpan={4} />
|
|
311
|
+
<TH scope="row" align="right">
|
|
312
|
+
Averages:
|
|
313
|
+
</TH>
|
|
314
|
+
<TD>{formatNumber(sb_tableGroupedStats.averages.q1)}</TD>
|
|
315
|
+
<TD>{formatNumber(sb_tableGroupedStats.averages.q2)}</TD>
|
|
316
|
+
<TD>{formatNumber(sb_tableGroupedStats.averages.q3)}</TD>
|
|
317
|
+
<TD>{formatNumber(sb_tableGroupedStats.averages.q4)}</TD>
|
|
318
|
+
<TD>{formatNumber(sb_tableGroupedStats.mean)}</TD>
|
|
319
|
+
<TD />
|
|
320
|
+
<TD />
|
|
321
|
+
</TR>
|
|
322
|
+
</TFoot>
|
|
323
|
+
</TTable>
|
|
324
|
+
</TableWrapper>
|
|
325
|
+
),
|
|
326
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.chip {
|
|
2
|
+
border: 1px solid var(--material);
|
|
3
|
+
background-color: var(--material);
|
|
4
|
+
color: var(--on-material);
|
|
5
|
+
font-size: 12px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.chip[data-status="completed"] {
|
|
9
|
+
border: 1px solid var(--async-color-success);
|
|
10
|
+
background-color: var(--async-color-success);
|
|
11
|
+
color: var(--ergo-white);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.chip[data-status="in_progress"] {
|
|
15
|
+
border: 1px solid var(--async-color-pending);
|
|
16
|
+
background-color: var(--async-color-pending);
|
|
17
|
+
color: var(--ergo-white);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.chip[data-status="not_started"] {
|
|
21
|
+
border: 1px solid var(--async-color-initial);
|
|
22
|
+
background-color: var(--async-color-initial);
|
|
23
|
+
color: var(--ergo-white);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.chip[data-status="failed"] {
|
|
27
|
+
border: 1px solid var(--async-color-failed);
|
|
28
|
+
background-color: var(--async-color-failed);
|
|
29
|
+
color: var(--ergo-white);
|
|
30
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
@layer tcn-system {
|
|
2
|
+
:where(.table) {
|
|
3
|
+
overflow: auto;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: auto;
|
|
6
|
+
}
|
|
7
|
+
:where(.table[data-is-sticky="true"]) {
|
|
8
|
+
th:first-of-type {
|
|
9
|
+
position: sticky;
|
|
10
|
+
left: 0;
|
|
11
|
+
z-index: 2;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
th:last-of-type {
|
|
15
|
+
position: sticky;
|
|
16
|
+
right: 0;
|
|
17
|
+
z-index: 2;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
thead:first-of-type {
|
|
21
|
+
position: sticky;
|
|
22
|
+
top: 0;
|
|
23
|
+
z-index: 3;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
tfoot:first-of-type {
|
|
27
|
+
position: sticky;
|
|
28
|
+
bottom: 0;
|
|
29
|
+
z-index: 3;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* TODO: Double check */
|
|
34
|
+
:where(.tcn-th[data-should-fill="true"]) {
|
|
35
|
+
width: auto;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
import styles from './table.module.css';
|
|
4
|
+
import { Box, type BoxProps } from '../../stacks/index.js';
|
|
5
|
+
|
|
6
|
+
export interface TTableProps extends React.TableHTMLAttributes<HTMLTableElement> {
|
|
7
|
+
// Makes the header, footer and first and last column (th only) sticky
|
|
8
|
+
sticky?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const TTable = ({
|
|
12
|
+
children,
|
|
13
|
+
className,
|
|
14
|
+
sticky = false,
|
|
15
|
+
...props
|
|
16
|
+
}: React.PropsWithChildren<TTableProps>) => {
|
|
17
|
+
return (
|
|
18
|
+
<table
|
|
19
|
+
data-is-sticky={sticky}
|
|
20
|
+
className={clsx('tcn-table', styles.table, className)}
|
|
21
|
+
{...props}
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</table>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export interface THeadProps extends React.HTMLAttributes<HTMLTableSectionElement> {}
|
|
29
|
+
|
|
30
|
+
// Header
|
|
31
|
+
export const THead = ({
|
|
32
|
+
children,
|
|
33
|
+
className,
|
|
34
|
+
...props
|
|
35
|
+
}: React.PropsWithChildren<THeadProps>) => {
|
|
36
|
+
return (
|
|
37
|
+
<thead className={clsx('tcn-thead', className)} {...props}>
|
|
38
|
+
{children}
|
|
39
|
+
</thead>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Body
|
|
44
|
+
export const TBody = ({
|
|
45
|
+
children,
|
|
46
|
+
className,
|
|
47
|
+
...props
|
|
48
|
+
}: React.PropsWithChildren<React.HTMLAttributes<HTMLTableSectionElement>>) => {
|
|
49
|
+
return (
|
|
50
|
+
<tbody className={clsx('tcn-tbody', className)} {...props}>
|
|
51
|
+
{children}
|
|
52
|
+
</tbody>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export interface TFootProps extends React.HTMLAttributes<HTMLTableSectionElement> {}
|
|
57
|
+
|
|
58
|
+
// Footer
|
|
59
|
+
export const TFoot = ({
|
|
60
|
+
children,
|
|
61
|
+
className,
|
|
62
|
+
...props
|
|
63
|
+
}: React.PropsWithChildren<TFootProps>) => {
|
|
64
|
+
return (
|
|
65
|
+
<tfoot className={clsx('tcn-tfoot', className)} {...props}>
|
|
66
|
+
{children}
|
|
67
|
+
</tfoot>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export interface TRProps extends React.HTMLAttributes<HTMLTableRowElement> {
|
|
72
|
+
isSelected?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Row
|
|
76
|
+
export const TR = ({
|
|
77
|
+
children,
|
|
78
|
+
className,
|
|
79
|
+
isSelected = false,
|
|
80
|
+
...props
|
|
81
|
+
}: React.PropsWithChildren<TRProps>) => {
|
|
82
|
+
return (
|
|
83
|
+
<tr
|
|
84
|
+
className={clsx('tcn-tr', className)}
|
|
85
|
+
aria-selected={isSelected}
|
|
86
|
+
data-is-selected={isSelected}
|
|
87
|
+
{...props}
|
|
88
|
+
>
|
|
89
|
+
{children}
|
|
90
|
+
</tr>
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export interface CellSharedProps extends Omit<BoxProps<HTMLTableCellElement>, 'as'> {
|
|
95
|
+
fill?: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface THProps
|
|
99
|
+
extends CellSharedProps,
|
|
100
|
+
React.ThHTMLAttributes<HTMLTableCellElement> {}
|
|
101
|
+
|
|
102
|
+
// Header Cell
|
|
103
|
+
export const TH = ({
|
|
104
|
+
children,
|
|
105
|
+
className,
|
|
106
|
+
fill = false,
|
|
107
|
+
...props
|
|
108
|
+
}: React.PropsWithChildren<THProps>) => {
|
|
109
|
+
return (
|
|
110
|
+
<Box as="th" data-should-fill={fill} className={clsx('tcn-th', className)} {...props}>
|
|
111
|
+
{children}
|
|
112
|
+
</Box>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export interface TDProps
|
|
117
|
+
extends CellSharedProps,
|
|
118
|
+
React.TdHTMLAttributes<HTMLTableCellElement> {}
|
|
119
|
+
|
|
120
|
+
// Data Cell
|
|
121
|
+
export const TD = ({
|
|
122
|
+
children,
|
|
123
|
+
className,
|
|
124
|
+
fill = false,
|
|
125
|
+
...props
|
|
126
|
+
}: React.PropsWithChildren<TDProps>) => {
|
|
127
|
+
return (
|
|
128
|
+
<td data-should-fill={fill} className={clsx('tcn-td', className)} {...props}>
|
|
129
|
+
{children}
|
|
130
|
+
</td>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { forwardRef, type FC, type PropsWithChildren } from 'react';
|
|
1
|
+
import { forwardRef, useCallback, type FC, type PropsWithChildren } from 'react';
|
|
2
2
|
import { type BaseButtonProps } from '../../../actions/index.js';
|
|
3
3
|
import { HStack, type HStackProps } from '../../../stacks/h_stack.js';
|
|
4
4
|
import clsx from 'clsx';
|
|
@@ -6,15 +6,59 @@ import { Toggle } from '../../../actions/toggle/toggle.js';
|
|
|
6
6
|
|
|
7
7
|
export type TabsListProps = HStackProps;
|
|
8
8
|
|
|
9
|
+
const navigateTabs = (event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
10
|
+
const tabs = Array.from(event.currentTarget.querySelectorAll(':scope > [role="tab"]'));
|
|
11
|
+
const currentTab = event.currentTarget.querySelector(':focus');
|
|
12
|
+
const currentIndex = currentTab ? tabs.indexOf(currentTab) : -1;
|
|
13
|
+
if (currentIndex === -1) return; // Exit if the focused element is not a tab
|
|
14
|
+
let newIndex = 0;
|
|
15
|
+
|
|
16
|
+
switch (event.key) {
|
|
17
|
+
case 'ArrowRight':
|
|
18
|
+
newIndex = (currentIndex + 1) % tabs.length;
|
|
19
|
+
break;
|
|
20
|
+
case 'ArrowLeft':
|
|
21
|
+
newIndex = (currentIndex - 1 + tabs.length) % tabs.length;
|
|
22
|
+
break;
|
|
23
|
+
case 'Home':
|
|
24
|
+
newIndex = 0;
|
|
25
|
+
break;
|
|
26
|
+
case 'End':
|
|
27
|
+
newIndex = tabs.length - 1;
|
|
28
|
+
break;
|
|
29
|
+
default:
|
|
30
|
+
return; // Exit if the key is not recognized
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
event.stopPropagation();
|
|
35
|
+
tabs[newIndex]['focus']();
|
|
36
|
+
};
|
|
37
|
+
|
|
9
38
|
export const TabsList: FC<PropsWithChildren<TabsListProps>> = ({
|
|
10
39
|
children,
|
|
11
40
|
className,
|
|
12
41
|
role = 'tablist',
|
|
13
42
|
as = 'menu',
|
|
43
|
+
onKeyDown,
|
|
14
44
|
...props
|
|
15
45
|
}) => {
|
|
46
|
+
const handleKeyDown = useCallback(
|
|
47
|
+
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
48
|
+
navigateTabs(event);
|
|
49
|
+
onKeyDown && onKeyDown(event);
|
|
50
|
+
},
|
|
51
|
+
[onKeyDown]
|
|
52
|
+
);
|
|
53
|
+
|
|
16
54
|
return (
|
|
17
|
-
<HStack
|
|
55
|
+
<HStack
|
|
56
|
+
onKeyDown={handleKeyDown}
|
|
57
|
+
as={as}
|
|
58
|
+
role={role}
|
|
59
|
+
className={clsx('tcn-tabs-list', className)}
|
|
60
|
+
{...props}
|
|
61
|
+
>
|
|
18
62
|
{children}
|
|
19
63
|
</HStack>
|
|
20
64
|
);
|
|
@@ -13,7 +13,7 @@ export interface TabLinkProps
|
|
|
13
13
|
TabLinkOwnProps {}
|
|
14
14
|
|
|
15
15
|
export const TabLink = forwardRef<HTMLButtonElement, PropsWithChildren<TabLinkProps>>(
|
|
16
|
-
({ children, value, onClick, minWidth, maxWidth, ...props }, forwardedRef) => {
|
|
16
|
+
({ children, value, onClick, minWidth, maxWidth, id, ...props }, forwardedRef) => {
|
|
17
17
|
const { ref: internalRef, isMatch } = useTabLink(value);
|
|
18
18
|
const state = useTabs();
|
|
19
19
|
const ref = useForkRef(internalRef, forwardedRef);
|
|
@@ -36,6 +36,9 @@ export const TabLink = forwardRef<HTMLButtonElement, PropsWithChildren<TabLinkPr
|
|
|
36
36
|
onClick={handleClick}
|
|
37
37
|
minWidth={pickMinWidth}
|
|
38
38
|
maxWidth={pickMaxWidth}
|
|
39
|
+
id={`tab-${value}`}
|
|
40
|
+
aria-controls={`tabpanel-${value}`}
|
|
41
|
+
tabIndex={isMatch ? 0 : -1}
|
|
39
42
|
{...props}
|
|
40
43
|
>
|
|
41
44
|
{children}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
import type { FC, PropsWithChildren } from 'react';
|
|
2
3
|
import { useTabs } from './context.js';
|
|
3
4
|
|
|
@@ -8,5 +9,14 @@ export interface TabProps {
|
|
|
8
9
|
export const Tab: FC<PropsWithChildren<TabProps>> = ({ value, children }) => {
|
|
9
10
|
const state = useTabs();
|
|
10
11
|
if (state.value !== value) return null;
|
|
12
|
+
|
|
13
|
+
if (children && React.isValidElement(children)) {
|
|
14
|
+
return React.cloneElement(children, {
|
|
15
|
+
...children.props,
|
|
16
|
+
id: children.props.id ?? `tabpanel-${value}`,
|
|
17
|
+
role: children.props.role ?? 'tabpanel',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
return children;
|
|
12
22
|
};
|
package/src/stacks/box/box.tsx
CHANGED
|
@@ -12,7 +12,7 @@ import { removeUndefinedProperties } from '../utils/remove_undefined_properties.
|
|
|
12
12
|
import styles from '../stack.module.css';
|
|
13
13
|
import { HandleProps } from './handle_props.js';
|
|
14
14
|
|
|
15
|
-
export interface BoxProps extends HTMLAttributes<
|
|
15
|
+
export interface BoxProps<T extends HTMLElement = HTMLElement> extends HTMLAttributes<T> {
|
|
16
16
|
as?: string;
|
|
17
17
|
style?: React.CSSProperties;
|
|
18
18
|
className?: string;
|
|
@@ -31,13 +31,13 @@ export const ModalStory = () => {
|
|
|
31
31
|
<Header>
|
|
32
32
|
<Title>Modal Title</Title>
|
|
33
33
|
<Spacer />
|
|
34
|
-
<Button utility hierarchy="tertiary"
|
|
34
|
+
<Button utility hierarchy="tertiary" onClick={toggle}>
|
|
35
35
|
<CrossIcon />
|
|
36
36
|
</Button>
|
|
37
|
-
<Button hierarchy="secondary"
|
|
37
|
+
<Button utility hierarchy="secondary" onClick={toggle}>
|
|
38
38
|
<CrossIcon />
|
|
39
39
|
</Button>
|
|
40
|
-
<Button utility hierarchy="primary"
|
|
40
|
+
<Button utility hierarchy="primary" onClick={toggle}>
|
|
41
41
|
<CrossIcon />
|
|
42
42
|
</Button>
|
|
43
43
|
</Header>
|
|
@@ -47,10 +47,10 @@ export const ModalStory = () => {
|
|
|
47
47
|
<Button utility hierarchy="tertiary">
|
|
48
48
|
<BugIcon />
|
|
49
49
|
</Button>
|
|
50
|
-
<Button hierarchy="secondary">
|
|
50
|
+
<Button utility hierarchy="secondary">
|
|
51
51
|
<BugIcon />
|
|
52
52
|
</Button>
|
|
53
|
-
<Button utility
|
|
53
|
+
<Button utility hierarchy="primary">
|
|
54
54
|
<BugIcon />
|
|
55
55
|
</Button>
|
|
56
56
|
</UtilityBar>
|