@apify/ui-library 1.132.1 → 1.134.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.
Files changed (147) hide show
  1. package/dist/src/components/box.d.ts.map +1 -1
  2. package/dist/src/components/card_container.js.map +1 -1
  3. package/dist/src/components/chip.d.ts.map +1 -1
  4. package/dist/src/components/chip.js.map +1 -1
  5. package/dist/src/components/code/code_block/code_block.d.ts.map +1 -1
  6. package/dist/src/components/code/inline_code/inline_code.d.ts.map +1 -1
  7. package/dist/src/components/code/one_line_code/one_line_code.d.ts.map +1 -1
  8. package/dist/src/components/code/prism_highlighter.d.ts.map +1 -1
  9. package/dist/src/components/code/prism_highlighter.js.map +1 -1
  10. package/dist/src/components/floating/tooltip.d.ts.map +1 -1
  11. package/dist/src/components/floating/tooltip.js +8 -0
  12. package/dist/src/components/floating/tooltip.js.map +1 -1
  13. package/dist/src/components/icon_button.d.ts.map +1 -1
  14. package/dist/src/components/index.d.ts +1 -0
  15. package/dist/src/components/index.d.ts.map +1 -1
  16. package/dist/src/components/index.js +1 -0
  17. package/dist/src/components/index.js.map +1 -1
  18. package/dist/src/components/link.d.ts +3 -0
  19. package/dist/src/components/link.d.ts.map +1 -1
  20. package/dist/src/components/link.js +2 -2
  21. package/dist/src/components/link.js.map +1 -1
  22. package/dist/src/components/rating.d.ts.map +1 -1
  23. package/dist/src/components/simple_markdown/simple_markdown.d.ts.map +1 -1
  24. package/dist/src/components/spinner.d.ts.map +1 -1
  25. package/dist/src/components/spinner.js.map +1 -1
  26. package/dist/src/components/store/store_actor_header.d.ts.map +1 -1
  27. package/dist/src/components/store/store_actor_header.js.map +1 -1
  28. package/dist/src/components/table/index.d.ts +17 -0
  29. package/dist/src/components/table/index.d.ts.map +1 -0
  30. package/dist/src/components/table/index.js +16 -0
  31. package/dist/src/components/table/index.js.map +1 -0
  32. package/dist/src/components/table/table.context.d.ts +3 -0
  33. package/dist/src/components/table/table.context.d.ts.map +1 -0
  34. package/dist/src/components/table/table.context.js +3 -0
  35. package/dist/src/components/table/table.context.js.map +1 -0
  36. package/dist/src/components/table/table.d.ts +3 -0
  37. package/dist/src/components/table/table.d.ts.map +1 -0
  38. package/dist/src/components/table/table.js +6 -0
  39. package/dist/src/components/table/table.js.map +1 -0
  40. package/dist/src/components/table/table.styled.d.ts +30 -0
  41. package/dist/src/components/table/table.styled.d.ts.map +1 -0
  42. package/dist/src/components/table/table.styled.js +194 -0
  43. package/dist/src/components/table/table.styled.js.map +1 -0
  44. package/dist/src/components/table/table_body.d.ts +3 -0
  45. package/dist/src/components/table/table_body.d.ts.map +1 -0
  46. package/dist/src/components/table/table_body.js +6 -0
  47. package/dist/src/components/table/table_body.js.map +1 -0
  48. package/dist/src/components/table/table_cell.d.ts +10 -0
  49. package/dist/src/components/table/table_cell.d.ts.map +1 -0
  50. package/dist/src/components/table/table_cell.js +18 -0
  51. package/dist/src/components/table/table_cell.js.map +1 -0
  52. package/dist/src/components/table/table_empty_row.d.ts +6 -0
  53. package/dist/src/components/table/table_empty_row.d.ts.map +1 -0
  54. package/dist/src/components/table/table_empty_row.js +5 -0
  55. package/dist/src/components/table/table_empty_row.js.map +1 -0
  56. package/dist/src/components/table/table_error_row.d.ts +7 -0
  57. package/dist/src/components/table/table_error_row.d.ts.map +1 -0
  58. package/dist/src/components/table/table_error_row.js +6 -0
  59. package/dist/src/components/table/table_error_row.js.map +1 -0
  60. package/dist/src/components/table/table_expansion_row.d.ts +10 -0
  61. package/dist/src/components/table/table_expansion_row.d.ts.map +1 -0
  62. package/dist/src/components/table/table_expansion_row.js +10 -0
  63. package/dist/src/components/table/table_expansion_row.js.map +1 -0
  64. package/dist/src/components/table/table_foot.d.ts +3 -0
  65. package/dist/src/components/table/table_foot.d.ts.map +1 -0
  66. package/dist/src/components/table/table_foot.js +6 -0
  67. package/dist/src/components/table/table_foot.js.map +1 -0
  68. package/dist/src/components/table/table_head.d.ts +3 -0
  69. package/dist/src/components/table/table_head.d.ts.map +1 -0
  70. package/dist/src/components/table/table_head.js +6 -0
  71. package/dist/src/components/table/table_head.js.map +1 -0
  72. package/dist/src/components/table/table_head_cell.d.ts +3 -0
  73. package/dist/src/components/table/table_head_cell.d.ts.map +1 -0
  74. package/dist/src/components/table/table_head_cell.js +6 -0
  75. package/dist/src/components/table/table_head_cell.js.map +1 -0
  76. package/dist/src/components/table/table_head_row.d.ts +3 -0
  77. package/dist/src/components/table/table_head_row.d.ts.map +1 -0
  78. package/dist/src/components/table/table_head_row.js +6 -0
  79. package/dist/src/components/table/table_head_row.js.map +1 -0
  80. package/dist/src/components/table/table_loading_row.d.ts +6 -0
  81. package/dist/src/components/table/table_loading_row.d.ts.map +1 -0
  82. package/dist/src/components/table/table_loading_row.js +6 -0
  83. package/dist/src/components/table/table_loading_row.js.map +1 -0
  84. package/dist/src/components/table/table_row.d.ts +4 -0
  85. package/dist/src/components/table/table_row.d.ts.map +1 -0
  86. package/dist/src/components/table/table_row.js +12 -0
  87. package/dist/src/components/table/table_row.js.map +1 -0
  88. package/dist/src/components/table/table_test_ids.d.ts +16 -0
  89. package/dist/src/components/table/table_test_ids.d.ts.map +1 -0
  90. package/dist/src/components/table/table_test_ids.js +16 -0
  91. package/dist/src/components/table/table_test_ids.js.map +1 -0
  92. package/dist/src/components/table/table_wrapper.d.ts +4 -0
  93. package/dist/src/components/table/table_wrapper.d.ts.map +1 -0
  94. package/dist/src/components/table/table_wrapper.js +49 -0
  95. package/dist/src/components/table/table_wrapper.js.map +1 -0
  96. package/dist/src/components/table/types.d.ts +21 -0
  97. package/dist/src/components/table/types.d.ts.map +1 -0
  98. package/dist/src/components/table/types.js +2 -0
  99. package/dist/src/components/table/types.js.map +1 -0
  100. package/dist/src/components/tag.d.ts.map +1 -1
  101. package/dist/src/components/to_consolidate/pagination.d.ts.map +1 -1
  102. package/dist/src/design_system/theme.d.ts.map +1 -1
  103. package/dist/src/type_utils.d.ts.map +1 -1
  104. package/dist/src/ui_dependency_provider.d.ts.map +1 -1
  105. package/dist/tsconfig.build.tsbuildinfo +1 -1
  106. package/package.json +3 -3
  107. package/src/components/box.tsx +1 -1
  108. package/src/components/card_container.tsx +1 -1
  109. package/src/components/chip.tsx +3 -3
  110. package/src/components/code/code_block/code_block.tsx +3 -3
  111. package/src/components/code/inline_code/inline_code.tsx +1 -1
  112. package/src/components/code/one_line_code/one_line_code.tsx +2 -2
  113. package/src/components/code/prism_highlighter.tsx +1 -1
  114. package/src/components/floating/tooltip.tsx +8 -0
  115. package/src/components/image.tsx +1 -1
  116. package/src/components/index.ts +1 -0
  117. package/src/components/link.stories.tsx +12 -0
  118. package/src/components/link.tsx +9 -0
  119. package/src/components/rating.tsx +3 -3
  120. package/src/components/simple_markdown/simple_markdown.tsx +1 -1
  121. package/src/components/spinner.tsx +1 -1
  122. package/src/components/store/store_actor_header.tsx +2 -2
  123. package/src/components/table/index.ts +16 -0
  124. package/src/components/table/table.context.ts +5 -0
  125. package/src/components/table/table.stories.tsx +258 -0
  126. package/src/components/table/table.styled.ts +207 -0
  127. package/src/components/table/table.tsx +9 -0
  128. package/src/components/table/table_body.tsx +9 -0
  129. package/src/components/table/table_cell.tsx +28 -0
  130. package/src/components/table/table_empty_row.tsx +12 -0
  131. package/src/components/table/table_error_row.tsx +13 -0
  132. package/src/components/table/table_expansion_row.tsx +24 -0
  133. package/src/components/table/table_foot.tsx +9 -0
  134. package/src/components/table/table_head.tsx +9 -0
  135. package/src/components/table/table_head_cell.tsx +9 -0
  136. package/src/components/table/table_head_row.tsx +9 -0
  137. package/src/components/table/table_loading_row.tsx +13 -0
  138. package/src/components/table/table_row.tsx +30 -0
  139. package/src/components/table/table_test_ids.ts +15 -0
  140. package/src/components/table/table_wrapper.tsx +71 -0
  141. package/src/components/table/types.ts +24 -0
  142. package/src/components/tabs/tabs.tsx +1 -1
  143. package/src/components/tag.tsx +1 -1
  144. package/src/components/to_consolidate/pagination.tsx +1 -1
  145. package/src/design_system/theme.ts +1 -1
  146. package/src/type_utils.ts +1 -1
  147. package/src/ui_dependency_provider.tsx +1 -1
@@ -0,0 +1,207 @@
1
+ import styled from 'styled-components';
2
+
3
+ import { theme } from '../../design_system/theme.js';
4
+ import { Box } from '../box.js';
5
+
6
+ /** z-index for sticky table head cells. Consumers can override via CSS if needed. */
7
+ const STICKY_HEAD_Z_INDEX = 5;
8
+
9
+ export const tableClassNames = {
10
+ TABLE: 'Table',
11
+ HEAD: 'Table-Head',
12
+ BODY: 'Table-Body',
13
+ FOOT: 'Table-Foot',
14
+
15
+ HEAD_ROW: 'Table-Head-Row',
16
+ HEAD_CELL: 'Table-Head-Cell',
17
+
18
+ BODY_ROW: 'Table-Body-Row',
19
+ BODY_ROW_CLICKABLE: 'Table-Body-Row_clickable',
20
+ BODY_ROW_EXPANDED: 'Table-Body-Row_expanded',
21
+ BODY_CELL: 'Table-Body-Cell',
22
+
23
+ FOOT_ROW: 'Table-Foot-Row',
24
+ FOOT_CELL: 'Table-Foot-Cell',
25
+
26
+ ROW_EMPTY: 'Table-Row-Empty',
27
+ ROW_EMPTY_CELL: 'Table-Row-Empty-Cell',
28
+
29
+ ROW_EXPANSION: 'Table-Row-Expansion',
30
+ ROW_EXPANSION_CELL: 'Table-Row-Expansion-Cell',
31
+
32
+ WRAPPER_SCROLLABLE: 'Table-Scrollable-Content',
33
+ WRAPPER_SHADOW_LEFT: 'Table-Scrollable-Shadow-Left',
34
+ WRAPPER_SHADOW_RIGHT: 'Table-Scrollable-Shadow-Right',
35
+
36
+ // Responsive hiding
37
+ HIDDEN_SM: 'Table-Cell_hiddenSM',
38
+ HIDDEN_MD: 'Table-Cell_hiddenMD',
39
+ HIDDEN_LG: 'Table-Cell_hiddenLG',
40
+
41
+ // Nested links
42
+ CELL_OVERLAY_LINK: 'Table-Cell-Overlay-Link',
43
+ CELL_LINK: 'Table-Cell-Link',
44
+ };
45
+
46
+ export const StyledTable = styled.table`
47
+ position: relative;
48
+ border-collapse: separate;
49
+ border-spacing: 0;
50
+ min-width: 100%;
51
+
52
+ /* Head cell rounding */
53
+ .${tableClassNames.HEAD_CELL}:first-child {
54
+ border-top-left-radius: ${theme.radius.radius12};
55
+ }
56
+ .${tableClassNames.HEAD_CELL}:last-child {
57
+ border-top-right-radius: ${theme.radius.radius12};
58
+ }
59
+
60
+ /* Generic cell padding */
61
+ .${tableClassNames.HEAD_CELL},
62
+ .${tableClassNames.BODY_CELL},
63
+ .${tableClassNames.ROW_EMPTY_CELL},
64
+ .${tableClassNames.ROW_EXPANSION_CELL} {
65
+ padding: ${theme.space.space8};
66
+ position: relative;
67
+ }
68
+
69
+ /* Head styling */
70
+ .${tableClassNames.HEAD_CELL} {
71
+ position: sticky;
72
+ top: 0;
73
+ z-index: ${STICKY_HEAD_Z_INDEX};
74
+ height: 4rem;
75
+ background-color: ${theme.color.neutral.backgroundMuted};
76
+ border-bottom: solid 1px ${theme.color.neutral.separatorSubtle};
77
+ color: ${theme.color.neutral.textMuted};
78
+ }
79
+
80
+ /* Body styling */
81
+ .${tableClassNames.BODY_ROW}:hover {
82
+ background-color: ${theme.color.neutral.hover};
83
+ }
84
+
85
+ .${tableClassNames.BODY_ROW}:not(:first-child) .${tableClassNames.BODY_CELL} {
86
+ border-top: solid 1px ${theme.color.neutral.separatorSubtle};
87
+ }
88
+
89
+ .${tableClassNames.BODY_ROW_CLICKABLE} {
90
+ cursor: pointer;
91
+ }
92
+
93
+ /* Foot styling */
94
+ .${tableClassNames.FOOT_ROW}:not(:first-child) .${tableClassNames.FOOT_CELL} {
95
+ border-top: solid 1px ${theme.color.neutral.separatorSubtle};
96
+ }
97
+
98
+ /* Responsive hiding */
99
+ .${tableClassNames.HIDDEN_SM} {
100
+ display: none !important;
101
+ }
102
+
103
+ @media ${theme.device.tablet} {
104
+ .${tableClassNames.HIDDEN_MD} {
105
+ display: none !important;
106
+ }
107
+ }
108
+
109
+ @media ${theme.device.desktop} {
110
+ .${tableClassNames.HIDDEN_LG} {
111
+ display: none !important;
112
+ }
113
+ }
114
+
115
+ /* Expansion row */
116
+ .${tableClassNames.ROW_EXPANSION_CELL} {
117
+ border-top: solid 1px ${theme.color.neutral.separatorSubtle};
118
+ box-shadow: inset 0rem 0.2rem 0.8rem -0.2rem ${theme.color.neutral.separatorSubtle};
119
+ }
120
+
121
+ /* Nested links — see https://www.notion.so/apify/How-to-Nested-links-4863b883e9e1498b965531d946721926 */
122
+ .${tableClassNames.CELL_OVERLAY_LINK} {
123
+ position: absolute;
124
+ top: 0;
125
+ left: 0;
126
+ width: 100%;
127
+ height: 100%;
128
+ z-index: 0;
129
+ cursor: pointer;
130
+ }
131
+
132
+ .${tableClassNames.CELL_LINK} {
133
+ position: relative;
134
+ z-index: 1;
135
+ color: ${theme.color.neutral.text};
136
+ cursor: pointer;
137
+ /* Extra padding for easier clicking, compensated by negative margin */
138
+ padding: ${theme.space.space4} ${theme.space.space8};
139
+ margin: -${theme.space.space4} -${theme.space.space8};
140
+
141
+ &:hover {
142
+ z-index: 2;
143
+ color: ${theme.color.primary.text};
144
+ }
145
+ }
146
+
147
+ /* Empty row */
148
+ .${tableClassNames.ROW_EMPTY_CELL} {
149
+ text-align: center;
150
+ padding: ${theme.space.space16};
151
+ }
152
+ `;
153
+
154
+ export const StyledHorizontallyScrollableTableWrapper = styled(Box)`
155
+ position: relative;
156
+ width: 100%;
157
+ background-color: ${theme.color.neutral.background};
158
+ border: solid 1px ${theme.color.neutral.separatorSubtle};
159
+ border-radius: ${theme.radius.radius12};
160
+ overflow: hidden;
161
+
162
+ .${tableClassNames.WRAPPER_SCROLLABLE} {
163
+ position: relative;
164
+ overflow-x: auto;
165
+ overflow-y: hidden;
166
+ }
167
+
168
+ &::before,
169
+ &::after {
170
+ content: '';
171
+ position: absolute;
172
+ top: 0;
173
+ bottom: 0;
174
+ width: 1.6rem;
175
+ pointer-events: none;
176
+ opacity: 0;
177
+ transition: opacity 0.3s ease;
178
+ z-index: ${STICKY_HEAD_Z_INDEX + 1};
179
+ }
180
+
181
+ &::before {
182
+ left: 0;
183
+ background: linear-gradient(to right, ${theme.color.neutral.separatorSubtle}, transparent);
184
+ }
185
+
186
+ &::after {
187
+ right: 0;
188
+ background: linear-gradient(to left, ${theme.color.neutral.separatorSubtle}, transparent);
189
+ }
190
+
191
+ &.${tableClassNames.WRAPPER_SHADOW_LEFT}::before {
192
+ opacity: 1;
193
+ }
194
+
195
+ &.${tableClassNames.WRAPPER_SHADOW_RIGHT}::after {
196
+ opacity: 1;
197
+ }
198
+ `;
199
+
200
+ export const StyledTableFooterWrapper = styled(Box)`
201
+ position: relative;
202
+ width: 100%;
203
+ background-color: ${theme.color.neutral.backgroundMuted};
204
+ border-top: solid 1px ${theme.color.neutral.separatorSubtle};
205
+ overflow-x: auto;
206
+ scrollbar-width: none;
207
+ `;
@@ -0,0 +1,9 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, HTMLAttributes } from 'react';
3
+
4
+ import { StyledTable, tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const Table: FC<HTMLAttributes<HTMLTableElement>> = ({ className, ...rest }) => (
8
+ <StyledTable data-test={tableTestIds.TABLE} className={clsx(tableClassNames.TABLE, className)} {...rest} />
9
+ );
@@ -0,0 +1,9 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, HTMLAttributes } from 'react';
3
+
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const TableBody: FC<HTMLAttributes<HTMLTableSectionElement>> = ({ className, ...rest }) => (
8
+ <tbody data-test={tableTestIds.BODY} className={clsx(tableClassNames.BODY, className)} {...rest} />
9
+ );
@@ -0,0 +1,28 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, TdHTMLAttributes } from 'react';
3
+ import { useContext } from 'react';
4
+
5
+ import { Link, type LinkProps } from '../link.js';
6
+ import { TableRowLinkContext } from './table.context.js';
7
+ import { tableClassNames } from './table.styled.js';
8
+ import { tableTestIds } from './table_test_ids.js';
9
+
10
+ export const TableCell: FC<TdHTMLAttributes<HTMLTableCellElement>> = ({ className, children, ...rest }) => {
11
+ const rowLink = useContext(TableRowLinkContext);
12
+
13
+ return (
14
+ <td data-test={tableTestIds.CELL} className={clsx(tableClassNames.BODY_CELL, className)} {...rest}>
15
+ {rowLink && <Link className={tableClassNames.CELL_OVERLAY_LINK} to={rowLink} tabIndex={-1} ariaHidden />}
16
+ {children}
17
+ </td>
18
+ );
19
+ };
20
+
21
+ /**
22
+ * Inner link inside a cell whose row has a `to` prop (overlay link).
23
+ * Elevated above the row overlay via `z-index` so it remains clickable and hoverable.
24
+ * Includes extra padding (compensated by negative margin) for easier click targets.
25
+ */
26
+ export const TableCellLink: FC<LinkProps> = ({ className, ...rest }) => (
27
+ <Link className={clsx(tableClassNames.CELL_LINK, className)} {...rest} />
28
+ );
@@ -0,0 +1,12 @@
1
+ import type { FC, ReactNode } from 'react';
2
+
3
+ import { tableClassNames } from './table.styled.js';
4
+ import { tableTestIds } from './table_test_ids.js';
5
+
6
+ export const TableEmptyRow: FC<{ colSpan: number; children: ReactNode }> = ({ colSpan, children }) => (
7
+ <tr data-test={tableTestIds.EMPTY_ROW} className={tableClassNames.ROW_EMPTY}>
8
+ <td colSpan={colSpan} className={tableClassNames.ROW_EMPTY_CELL}>
9
+ {children}
10
+ </td>
11
+ </tr>
12
+ );
@@ -0,0 +1,13 @@
1
+ import type { FC, ReactNode } from 'react';
2
+
3
+ import { Text } from '../text/index.js';
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const TableErrorRow: FC<{ colSpan: number; children?: ReactNode; error?: Error | null }> = ({ colSpan, children, error }) => (
8
+ <tr data-test={tableTestIds.ERROR_ROW} className={tableClassNames.ROW_EMPTY}>
9
+ <td colSpan={colSpan} className={tableClassNames.ROW_EMPTY_CELL}>
10
+ {children ?? <Text color="error">{error?.message ?? 'Failed to load data'}</Text>}
11
+ </td>
12
+ </tr>
13
+ );
@@ -0,0 +1,24 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, ReactNode } from 'react';
3
+
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+ import type { TableExpansion } from './types.js';
7
+
8
+ export const TableExpansionRow: FC<{
9
+ colSpan: number;
10
+ children: ReactNode;
11
+ expansion: TableExpansion;
12
+ itemId: string;
13
+ className?: string;
14
+ }> = ({ colSpan, children, expansion, itemId, className }) => {
15
+ if (!expansion.isExpanded(itemId)) return null;
16
+
17
+ return (
18
+ <tr data-test={tableTestIds.EXPANSION_ROW} className={clsx(tableClassNames.ROW_EXPANSION, className)}>
19
+ <td colSpan={colSpan} className={tableClassNames.ROW_EXPANSION_CELL}>
20
+ {children}
21
+ </td>
22
+ </tr>
23
+ );
24
+ };
@@ -0,0 +1,9 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, HTMLAttributes } from 'react';
3
+
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const TableFoot: FC<HTMLAttributes<HTMLTableSectionElement>> = ({ className, ...rest }) => (
8
+ <tfoot data-test={tableTestIds.FOOT} className={clsx(tableClassNames.FOOT, className)} {...rest} />
9
+ );
@@ -0,0 +1,9 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, HTMLAttributes } from 'react';
3
+
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const TableHead: FC<HTMLAttributes<HTMLTableSectionElement>> = ({ className, ...rest }) => (
8
+ <thead data-test={tableTestIds.HEAD} className={clsx(tableClassNames.HEAD, className)} {...rest} />
9
+ );
@@ -0,0 +1,9 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, ThHTMLAttributes } from 'react';
3
+
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const TableHeadCell: FC<ThHTMLAttributes<HTMLTableCellElement>> = ({ className, ...rest }) => (
8
+ <th data-test={tableTestIds.HEAD_CELL} className={clsx(tableClassNames.HEAD_CELL, className)} {...rest} />
9
+ );
@@ -0,0 +1,9 @@
1
+ import clsx from 'clsx';
2
+ import type { FC, HTMLAttributes } from 'react';
3
+
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const TableHeadRow: FC<HTMLAttributes<HTMLTableRowElement>> = ({ className, ...rest }) => (
8
+ <tr data-test={tableTestIds.HEAD_ROW} className={clsx(tableClassNames.HEAD_ROW, className)} {...rest} />
9
+ );
@@ -0,0 +1,13 @@
1
+ import type { FC, ReactNode } from 'react';
2
+
3
+ import { InlineSpinner } from '../spinner.js';
4
+ import { tableClassNames } from './table.styled.js';
5
+ import { tableTestIds } from './table_test_ids.js';
6
+
7
+ export const TableLoadingRow: FC<{ colSpan: number; children?: ReactNode }> = ({ colSpan, children }) => (
8
+ <tr data-test={tableTestIds.LOADING_ROW} className={tableClassNames.ROW_EMPTY}>
9
+ <td colSpan={colSpan} className={tableClassNames.ROW_EMPTY_CELL}>
10
+ {children ?? <InlineSpinner />}
11
+ </td>
12
+ </tr>
13
+ );
@@ -0,0 +1,30 @@
1
+ import clsx from 'clsx';
2
+ import type { FC } from 'react';
3
+
4
+ import { TableRowLinkContext } from './table.context.js';
5
+ import { tableClassNames } from './table.styled.js';
6
+ import { tableTestIds } from './table_test_ids.js';
7
+ import type { TableRowProps } from './types.js';
8
+
9
+ export const TableRow: FC<TableRowProps> = ({ className, clickable, expanded, to, ...rest }) => {
10
+ const row = (
11
+ <tr
12
+ data-test={tableTestIds.ROW}
13
+ className={clsx(
14
+ tableClassNames.BODY_ROW,
15
+ (clickable || to) && tableClassNames.BODY_ROW_CLICKABLE,
16
+ expanded && tableClassNames.BODY_ROW_EXPANDED,
17
+ className,
18
+ )}
19
+ {...rest}
20
+ />
21
+ );
22
+
23
+ if (!to) return row;
24
+
25
+ return (
26
+ <TableRowLinkContext.Provider value={to}>
27
+ {row}
28
+ </TableRowLinkContext.Provider>
29
+ );
30
+ };
@@ -0,0 +1,15 @@
1
+ export const tableTestIds = {
2
+ TABLE: 'Table-table',
3
+ HEAD: 'Table-head',
4
+ HEAD_ROW: 'Table-headRow',
5
+ HEAD_CELL: 'Table-headCell',
6
+ BODY: 'Table-body',
7
+ ROW: 'Table-row',
8
+ CELL: 'Table-cell',
9
+ FOOT: 'Table-foot',
10
+ WRAPPER: 'Table-wrapper',
11
+ EMPTY_ROW: 'Table-emptyRow',
12
+ LOADING_ROW: 'Table-loadingRow',
13
+ ERROR_ROW: 'Table-errorRow',
14
+ EXPANSION_ROW: 'Table-expansionRow',
15
+ };
@@ -0,0 +1,71 @@
1
+ import type { FC } from 'react';
2
+ import { useCallback, useEffect, useRef } from 'react';
3
+
4
+ import { Box } from '../box.js';
5
+ import {
6
+ StyledHorizontallyScrollableTableWrapper,
7
+ StyledTableFooterWrapper,
8
+ tableClassNames,
9
+ } from './table.styled.js';
10
+ import { tableTestIds } from './table_test_ids.js';
11
+ import type { HorizontallyScrollableTableWrapperProps } from './types.js';
12
+
13
+ export const HorizontallyScrollableTableWrapper: FC<HorizontallyScrollableTableWrapperProps> = ({ children, footer, className }) => {
14
+ const scrollableRef = useRef<HTMLDivElement>(null);
15
+ const wrapperRef = useRef<HTMLDivElement>(null);
16
+ const animationFrameIdRef = useRef(0);
17
+
18
+ const updateShadows = useCallback(() => {
19
+ const container = scrollableRef.current;
20
+ const wrapper = wrapperRef.current;
21
+ if (!container || !wrapper) return;
22
+
23
+ const isScrollable = container.scrollWidth > container.clientWidth;
24
+
25
+ if (container.scrollLeft > 0) {
26
+ wrapper.classList.add(tableClassNames.WRAPPER_SHADOW_LEFT);
27
+ } else {
28
+ wrapper.classList.remove(tableClassNames.WRAPPER_SHADOW_LEFT);
29
+ }
30
+
31
+ if (isScrollable && container.scrollLeft < container.scrollWidth - container.clientWidth - 1) {
32
+ wrapper.classList.add(tableClassNames.WRAPPER_SHADOW_RIGHT);
33
+ } else {
34
+ wrapper.classList.remove(tableClassNames.WRAPPER_SHADOW_RIGHT);
35
+ }
36
+ }, []);
37
+
38
+ const throttledUpdateShadows = useCallback(() => {
39
+ cancelAnimationFrame(animationFrameIdRef.current);
40
+ animationFrameIdRef.current = requestAnimationFrame(updateShadows);
41
+ }, [updateShadows]);
42
+
43
+ useEffect(() => {
44
+ const container = scrollableRef.current;
45
+ if (!container) return undefined;
46
+
47
+ updateShadows();
48
+ container.addEventListener('scroll', throttledUpdateShadows);
49
+ const resizeObserver = new ResizeObserver(throttledUpdateShadows);
50
+ resizeObserver.observe(container);
51
+
52
+ return () => {
53
+ cancelAnimationFrame(animationFrameIdRef.current);
54
+ container.removeEventListener('scroll', throttledUpdateShadows);
55
+ resizeObserver.disconnect();
56
+ };
57
+ }, [updateShadows, throttledUpdateShadows]);
58
+
59
+ return (
60
+ <StyledHorizontallyScrollableTableWrapper data-test={tableTestIds.WRAPPER} ref={wrapperRef} className={className}>
61
+ <Box className={tableClassNames.WRAPPER_SCROLLABLE} ref={scrollableRef}>
62
+ {children}
63
+ </Box>
64
+ {footer && (
65
+ <StyledTableFooterWrapper>
66
+ {footer}
67
+ </StyledTableFooterWrapper>
68
+ )}
69
+ </StyledHorizontallyScrollableTableWrapper>
70
+ );
71
+ };
@@ -0,0 +1,24 @@
1
+ import type { HTMLAttributes, ReactNode } from 'react';
2
+
3
+ import type { To } from '../link.js';
4
+
5
+ export type TableRowProps = HTMLAttributes<HTMLTableRowElement> & {
6
+ /** Apply clickable cursor style. Automatically set when `to` is provided. */
7
+ clickable?: boolean;
8
+ /** Apply expanded row style. */
9
+ expanded?: boolean;
10
+ /** Row-level navigation URL. Each `TableCell` inside will render an overlay link automatically. */
11
+ to?: To;
12
+ };
13
+
14
+ export type HorizontallyScrollableTableWrapperProps = {
15
+ children: ReactNode;
16
+ footer?: ReactNode;
17
+ className?: string;
18
+ };
19
+
20
+ export type TableExpansion = {
21
+ expandedId: string | null;
22
+ toggle: (id: string) => void;
23
+ isExpanded: (id: string) => boolean;
24
+ };
@@ -128,7 +128,7 @@ const TabsWrapper = styled(Box)<TabsWrapperProps>`
128
128
  type TabOverflowState = {
129
129
  right: boolean;
130
130
  left: boolean;
131
- }
131
+ };
132
132
 
133
133
  const isTabsOverflowing = (node: HTMLDivElement): TabOverflowState => {
134
134
  if (node.scrollWidth > node.clientWidth) {
@@ -35,7 +35,7 @@ type TagNodePropsMap = {
35
35
  element: HTMLButtonElement;
36
36
  props: RegularButtonProps;
37
37
  };
38
- }
38
+ };
39
39
 
40
40
  type SharedTagProps = Omit<RegularBoxProps, 'as'> & MarginSpacingProps;
41
41
  export type TagProps<T extends TagNodeType> = SharedTagProps & ({
@@ -39,7 +39,7 @@ export type PaginationButtonsProps = {
39
39
  page: number;
40
40
  totalPages: number;
41
41
  onPageChange: (page: number) => void;
42
- }
42
+ };
43
43
 
44
44
  // TODO: Consolidate and move to /library
45
45
  export const PaginationButtons: FC<PaginationButtonsProps> = ({
@@ -22,4 +22,4 @@ export const theme = {
22
22
  typography: typographyTokens,
23
23
  };
24
24
 
25
- export type UiThemeOption = 'LIGHT' | 'DARK'
25
+ export type UiThemeOption = 'LIGHT' | 'DARK';
package/src/type_utils.ts CHANGED
@@ -3,5 +3,5 @@
3
3
  // It's called transient props (https://styled-components.com/docs/api#transient-props)
4
4
  export type WithTransientProps<T> = { [P in keyof T & string as `$${P}`]: T[P] };
5
5
 
6
- export type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>
6
+ export type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;
7
7
  export type WithOptional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
@@ -18,7 +18,7 @@ export type ImageProxyOptions = {
18
18
  width?: number,
19
19
  height?: number,
20
20
  }
21
- }
21
+ };
22
22
 
23
23
  export interface UiDependencies {
24
24
  InternalLink: React.ForwardRefExoticComponent<AgnosticInternalLinkProps & React.RefAttributes<HTMLAnchorElement>>,