@tcn/ui 0.8.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.
Files changed (121) hide show
  1. package/dist/{Color-6BZIO3FS-CWWwv-fq.js → Color-6BZIO3FS-C9xkPWgz.js} +2 -2
  2. package/dist/{Color-6BZIO3FS-CWWwv-fq.js.map → Color-6BZIO3FS-C9xkPWgz.js.map} +1 -1
  3. package/dist/{WithTooltip-65CFNBJE-DvcUZizH.js → WithTooltip-65CFNBJE-DEnh547F.js} +2 -2
  4. package/dist/{WithTooltip-65CFNBJE-DvcUZizH.js.map → WithTooltip-65CFNBJE-DEnh547F.js.map} +1 -1
  5. package/dist/actions/__docs__/components/showcase.js +1 -1
  6. package/dist/actions/index.d.ts +1 -0
  7. package/dist/actions/index.d.ts.map +1 -1
  8. package/dist/actions/index.js +8 -6
  9. package/dist/actions/index.js.map +1 -1
  10. package/dist/body.css +1 -0
  11. package/dist/formatter-EIJCOSYU-DWmgEY3b.js +6 -0
  12. package/dist/{formatter-EIJCOSYU-D6nmx63h.js.map → formatter-EIJCOSYU-DWmgEY3b.js.map} +1 -1
  13. package/dist/inputs/color_input/color_input.js +10 -9
  14. package/dist/inputs/color_input/color_input.js.map +1 -1
  15. package/dist/inputs/date_picker/date_picker_header.js +7 -6
  16. package/dist/inputs/date_picker/date_picker_header.js.map +1 -1
  17. package/dist/inputs/date_picker/date_picker_input.js +3 -2
  18. package/dist/inputs/date_picker/date_picker_input.js.map +1 -1
  19. package/dist/inputs/date_picker/date_picker_time_selector.js +3 -2
  20. package/dist/inputs/date_picker/date_picker_time_selector.js.map +1 -1
  21. package/dist/inputs/date_picker/date_picker_year_input.js +6 -5
  22. package/dist/inputs/date_picker/date_picker_year_input.js.map +1 -1
  23. package/dist/inputs/date_picker/date_picker_year_selector.js +3 -2
  24. package/dist/inputs/date_picker/date_picker_year_selector.js.map +1 -1
  25. package/dist/inputs/multiselect/multiselect_inline_values.js +8 -7
  26. package/dist/inputs/multiselect/multiselect_inline_values.js.map +1 -1
  27. package/dist/inputs/multiselect/multiselect_values.js +3 -2
  28. package/dist/inputs/multiselect/multiselect_values.js.map +1 -1
  29. package/dist/inputs/phone_number_input/phone_number_input.js +44 -43
  30. package/dist/inputs/phone_number_input/phone_number_input.js.map +1 -1
  31. package/dist/inputs/select/select.js +3 -2
  32. package/dist/inputs/select/select.js.map +1 -1
  33. package/dist/inputs/suggestions/suggestion_list.js +3 -2
  34. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  35. package/dist/layouts/body/body.d.ts +6 -0
  36. package/dist/layouts/body/body.d.ts.map +1 -0
  37. package/dist/layouts/body/body.js +21 -0
  38. package/dist/layouts/body/body.js.map +1 -0
  39. package/dist/layouts/index.d.ts +5 -0
  40. package/dist/layouts/index.d.ts.map +1 -1
  41. package/dist/layouts/index.js +38 -22
  42. package/dist/layouts/index.js.map +1 -1
  43. package/dist/layouts/rail/main/main.d.ts +6 -0
  44. package/dist/layouts/rail/main/main.d.ts.map +1 -0
  45. package/dist/layouts/rail/main/main.js +21 -0
  46. package/dist/layouts/rail/main/main.js.map +1 -0
  47. package/dist/layouts/rail/rail.d.ts +9 -0
  48. package/dist/layouts/rail/rail.d.ts.map +1 -0
  49. package/dist/layouts/rail/rail.js +55 -0
  50. package/dist/layouts/rail/rail.js.map +1 -0
  51. package/dist/layouts/rail/side/side.d.ts +6 -0
  52. package/dist/layouts/rail/side/side.d.ts.map +1 -0
  53. package/dist/layouts/rail/side/side.js +21 -0
  54. package/dist/layouts/rail/side/side.js.map +1 -0
  55. package/dist/layouts/rail/utility_strip/utility_strip.d.ts +9 -0
  56. package/dist/layouts/rail/utility_strip/utility_strip.d.ts.map +1 -0
  57. package/dist/layouts/rail/utility_strip/utility_strip.js +32 -0
  58. package/dist/layouts/rail/utility_strip/utility_strip.js.map +1 -0
  59. package/dist/layouts/scaffold/scaffold.js +31 -31
  60. package/dist/layouts/scaffold/scaffold.js.map +1 -1
  61. package/dist/layouts/table/table.d.ts +27 -0
  62. package/dist/layouts/table/table.d.ts.map +1 -0
  63. package/dist/layouts/table/table.js +70 -0
  64. package/dist/layouts/table/table.js.map +1 -0
  65. package/dist/main.css +1 -0
  66. package/dist/rail.css +1 -0
  67. package/dist/scaffold.css +1 -1
  68. package/dist/{showcase-DK557szS.js → showcase-y9D3_Y8T.js} +3413 -3396
  69. package/dist/showcase-y9D3_Y8T.js.map +1 -0
  70. package/dist/side.css +1 -0
  71. package/dist/stacks/box/box.d.ts +2 -2
  72. package/dist/stacks/box/box.d.ts.map +1 -1
  73. package/dist/stacks/box/box.js.map +1 -1
  74. package/dist/stacks/story_components/style_box.d.ts +1 -1
  75. package/dist/stacks/story_components/style_box.d.ts.map +1 -1
  76. package/dist/surfaces/alert/alert.js +3 -2
  77. package/dist/surfaces/alert/alert.js.map +1 -1
  78. package/dist/surfaces/pop_confirm/pop_confirm.js +13 -2
  79. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  80. package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js} +2 -2
  81. package/dist/{syntaxhighlighter-ED5Y7EFY-DaMS-2cF.js.map → syntaxhighlighter-ED5Y7EFY-CqInEOwQ.js.map} +1 -1
  82. package/dist/table.css +1 -0
  83. package/dist/table.module-BtSxOntS.js +5 -0
  84. package/dist/table.module-BtSxOntS.js.map +1 -0
  85. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  86. package/dist/themes/themes/ergo/ergo_theme.js +174 -43
  87. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  88. package/dist/utility_strip.css +1 -0
  89. package/package.json +1 -1
  90. package/src/actions/index.ts +1 -0
  91. package/src/layouts/__stories__/composed.stories.tsx +113 -0
  92. package/src/layouts/__stories__/composed_stories.module.css +142 -0
  93. package/src/layouts/__stories__/utils.tsx +174 -0
  94. package/src/layouts/body/body.module.css +11 -0
  95. package/src/layouts/body/body.tsx +23 -0
  96. package/src/layouts/index.ts +10 -0
  97. package/src/layouts/rail/__stories__/rail.stories.tsx +64 -0
  98. package/src/layouts/rail/__stories__/rail_stories.module.css +25 -0
  99. package/src/layouts/rail/main/main.module.css +7 -0
  100. package/src/layouts/rail/main/main.tsx +26 -0
  101. package/src/layouts/rail/rail.module.css +10 -0
  102. package/src/layouts/rail/rail.tsx +62 -0
  103. package/src/layouts/rail/side/side.module.css +8 -0
  104. package/src/layouts/rail/side/side.tsx +25 -0
  105. package/src/layouts/rail/utility_strip/utility_strip.module.css +6 -0
  106. package/src/layouts/rail/utility_strip/utility_strip.tsx +40 -0
  107. package/src/layouts/scaffold/__stories__/scaffold.stories.tsx +53 -0
  108. package/src/layouts/scaffold/__stories__/scaffold_stories.module.css +31 -0
  109. package/src/layouts/scaffold/scaffold.module.css +4 -0
  110. package/src/layouts/table/__stories__/mock_data.ts +420 -0
  111. package/src/layouts/table/__stories__/table.stories.tsx +326 -0
  112. package/src/layouts/table/__stories__/table_stories.module.css +30 -0
  113. package/src/layouts/table/table.module.css +37 -0
  114. package/src/layouts/table/table.tsx +132 -0
  115. package/src/stacks/box/box.tsx +1 -1
  116. package/src/surfaces/modal/__stories__/modal.stories.tsx +5 -5
  117. package/src/surfaces/panel/__stories__/panel.stories.tsx +114 -1
  118. package/src/surfaces/pop_confirm/pop_confirm.stories.tsx +4 -2
  119. package/src/themes/themes/ergo/ergo_theme.css +173 -42
  120. package/dist/formatter-EIJCOSYU-D6nmx63h.js +0 -6
  121. 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
+ };
@@ -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<HTMLElement> {
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" size="md" onClick={toggle}>
34
+ <Button utility hierarchy="tertiary" onClick={toggle}>
35
35
  <CrossIcon />
36
36
  </Button>
37
- <Button hierarchy="secondary" size="md" onClick={toggle}>
37
+ <Button utility hierarchy="secondary" onClick={toggle}>
38
38
  <CrossIcon />
39
39
  </Button>
40
- <Button utility hierarchy="primary" size="md" onClick={toggle}>
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 size="md" hierarchy="primary">
53
+ <Button utility hierarchy="primary">
54
54
  <BugIcon />
55
55
  </Button>
56
56
  </UtilityBar>
@@ -4,11 +4,22 @@ import { Footer } from '../../../layouts/footer/footer.js';
4
4
  import { Header } from '../../../layouts/header/header.js';
5
5
  import { Heading, Section, VBody } from '../../../layouts/index.js';
6
6
  import { UtilityBar } from '../../../layouts/utility_bar/utility_bar.js';
7
- import { Box, Spacer } from '../../../stacks/index.js';
7
+ import { Box, HStack, Spacer } from '../../../stacks/index.js';
8
8
  import { Title } from '../../../typography/title/title.js';
9
9
  import { VPanel } from '../v_panel.js';
10
10
  // Styles
11
11
  import styles from './panel_stories.module.css';
12
+ import { TTable, TBody, TD, TH, THead, TR } from '../../../layouts/table/table.js';
13
+ import { FilterOneIcon } from '@tcn/icons/filter_one_icon.js';
14
+ import { PlusIcon } from '@tcn/icons/plus_icon.js';
15
+ import { SearchIcon } from '@tcn/icons/search_icon.js';
16
+ import { ChevronLeftIcon } from '@tcn/icons/chevron_left_icon.js';
17
+ import { ChevronsLeftIcon } from '@tcn/icons/chevrons_left_icon.js';
18
+ import { ChevronsRightIcon } from '@tcn/icons/chevrons_right_icon.js';
19
+ import { ChevronRightIcon } from '@tcn/icons/chevron_right_icon.js';
20
+ import { Toggle } from '../../../actions/toggle/toggle.js';
21
+ import { CrossIcon } from '@tcn/icons/cross_icon.js';
22
+ import { BodyText } from '../../../typography/index.js';
12
23
 
13
24
  export default {
14
25
  title: 'Surfaces/Panel',
@@ -102,3 +113,105 @@ export const Default = () => {
102
113
  </div>
103
114
  );
104
115
  };
116
+
117
+ export const WithTable = () => {
118
+ return (
119
+ <div className={styles['stories-container']}>
120
+ <HStack gap="16px" maxHeight="600px" height="100%" maxWidth="1440px">
121
+ <VPanel minWidth="300px">
122
+ <Header>
123
+ <Title emphasis="strong">Table Title</Title>
124
+ <Spacer />
125
+ <Button utility hierarchy="tertiary">
126
+ <FilterOneIcon />
127
+ </Button>
128
+ <Button utility hierarchy="tertiary">
129
+ <SearchIcon />
130
+ </Button>
131
+ <Button utility hierarchy="primary">
132
+ <PlusIcon />
133
+ </Button>
134
+ </Header>
135
+ <VBody>
136
+ <TTable>
137
+ <THead>
138
+ <TR>
139
+ <TH>Name</TH>
140
+ <TH>Age</TH>
141
+ <TH>Email</TH>
142
+ </TR>
143
+ </THead>
144
+ <TBody>
145
+ <TR>
146
+ <TD>Jane Smith</TD>
147
+ <TD>32</TD>
148
+ <TD>jane.smith@example.com</TD>
149
+ </TR>
150
+ <TR>
151
+ <TD>Samuel Barnett</TD>
152
+ <TD>28</TD>
153
+ <TD>samuel.barnett@example.com</TD>
154
+ </TR>
155
+ <TR isSelected>
156
+ <TD>John Doe</TD>
157
+ <TD>25</TD>
158
+ <TD>john.doe@example.com</TD>
159
+ </TR>
160
+ <TR>
161
+ <TD>Linda Wang</TD>
162
+ <TD>41</TD>
163
+ <TD>linda.wang@example.com</TD>
164
+ </TR>
165
+ </TBody>
166
+ </TTable>
167
+ </VBody>
168
+ <Footer>
169
+ <HStack gap="8px" hAlign="center">
170
+ <Button utility hierarchy="tertiary">
171
+ <ChevronsLeftIcon />
172
+ </Button>
173
+ <Button utility hierarchy="tertiary">
174
+ <ChevronLeftIcon />
175
+ </Button>
176
+ <Toggle utility>1</Toggle>
177
+ ...
178
+ <Toggle utility>4</Toggle>
179
+ <Toggle utility selected>
180
+ 5
181
+ </Toggle>
182
+ <Toggle utility>6</Toggle>
183
+ ...
184
+ <Toggle utility>100</Toggle>
185
+ <Button utility hierarchy="tertiary">
186
+ <ChevronsRightIcon />
187
+ </Button>
188
+ <Button utility hierarchy="tertiary">
189
+ <ChevronRightIcon />
190
+ </Button>
191
+ </HStack>
192
+ </Footer>
193
+ </VPanel>
194
+ <VPanel maxHeight="600px" width="300px" minWidth="300px">
195
+ <Header>
196
+ <Title emphasis="strong">John Doe</Title>
197
+ <Spacer />
198
+ <Button utility hierarchy="tertiary">
199
+ <CrossIcon />
200
+ </Button>
201
+ </Header>
202
+ <VBody>
203
+ <Section>
204
+ <Heading>Personal Information</Heading>
205
+ <BodyText>
206
+ John Doe is a software engineer at FooBaz. He is a very smart guy and he
207
+ loves to code.
208
+ </BodyText>
209
+ <BodyText>Age: 25</BodyText>
210
+ <BodyText>Email: john.doe@example.com</BodyText>
211
+ </Section>
212
+ </VBody>
213
+ </VPanel>
214
+ </HStack>
215
+ </div>
216
+ );
217
+ };