@luxfi/ui 5.6.0 → 6.1.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 (155) hide show
  1. package/dist/components/Badge.d.ts.map +1 -0
  2. package/dist/components/Badge.js +91 -0
  3. package/dist/components/Button.d.ts.map +1 -0
  4. package/dist/components/Button.js +137 -0
  5. package/dist/components/Card.d.ts.map +1 -0
  6. package/dist/components/Card.js +86 -0
  7. package/dist/components/IconButton.d.ts.map +1 -0
  8. package/dist/components/IconButton.js +64 -0
  9. package/dist/components/Input.d.ts.map +1 -0
  10. package/dist/components/Input.js +71 -0
  11. package/dist/components/Modal.d.ts.map +1 -0
  12. package/dist/components/Modal.js +98 -0
  13. package/dist/components/Skeleton.d.ts.map +1 -0
  14. package/dist/components/Skeleton.js +44 -0
  15. package/dist/components/Spinner.d.ts.map +1 -0
  16. package/dist/components/Spinner.js +42 -0
  17. package/dist/components/Switch.d.ts.map +1 -0
  18. package/dist/components/Switch.js +10 -0
  19. package/dist/components/TokenLogo.d.ts.map +1 -0
  20. package/dist/components/TokenLogo.js +57 -0
  21. package/dist/components/Tooltip.d.ts.map +1 -0
  22. package/dist/components/Tooltip.js +34 -0
  23. package/dist/components/index.d.ts.map +1 -0
  24. package/dist/components/index.js +19 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +35 -5618
  27. package/dist/theme/index.d.ts.map +1 -0
  28. package/dist/theme/index.js +6 -0
  29. package/dist/theme/themes.d.ts.map +1 -0
  30. package/dist/theme/themes.js +73 -0
  31. package/dist/theme/tokens.d.ts.map +1 -0
  32. package/dist/theme/tokens.js +101 -0
  33. package/package.json +81 -278
  34. package/dist/accordion.cjs +0 -213
  35. package/dist/accordion.js +0 -186
  36. package/dist/alert.cjs +0 -553
  37. package/dist/alert.js +0 -531
  38. package/dist/avatar.cjs +0 -149
  39. package/dist/avatar.js +0 -125
  40. package/dist/badge.cjs +0 -611
  41. package/dist/badge.js +0 -589
  42. package/dist/button.cjs +0 -689
  43. package/dist/button.js +0 -664
  44. package/dist/checkbox.cjs +0 -265
  45. package/dist/checkbox.js +0 -241
  46. package/dist/close-button.cjs +0 -73
  47. package/dist/close-button.js +0 -51
  48. package/dist/collapsible.cjs +0 -702
  49. package/dist/collapsible.js +0 -679
  50. package/dist/color-mode.cjs +0 -96
  51. package/dist/color-mode.js +0 -72
  52. package/dist/dialog.cjs +0 -279
  53. package/dist/dialog.js +0 -246
  54. package/dist/drawer.cjs +0 -207
  55. package/dist/drawer.js +0 -175
  56. package/dist/empty-state.cjs +0 -93
  57. package/dist/empty-state.js +0 -71
  58. package/dist/field.cjs +0 -183
  59. package/dist/field.js +0 -160
  60. package/dist/heading.cjs +0 -46
  61. package/dist/heading.js +0 -40
  62. package/dist/icon-button.cjs +0 -491
  63. package/dist/icon-button.js +0 -470
  64. package/dist/image.cjs +0 -572
  65. package/dist/image.js +0 -551
  66. package/dist/index.cjs +0 -5779
  67. package/dist/input-group.cjs +0 -155
  68. package/dist/input-group.js +0 -133
  69. package/dist/input.cjs +0 -65
  70. package/dist/input.js +0 -59
  71. package/dist/link.cjs +0 -630
  72. package/dist/link.js +0 -606
  73. package/dist/menu.cjs +0 -305
  74. package/dist/menu.js +0 -269
  75. package/dist/pin-input.cjs +0 -182
  76. package/dist/pin-input.js +0 -160
  77. package/dist/popover.cjs +0 -327
  78. package/dist/popover.js +0 -294
  79. package/dist/progress-circle.cjs +0 -152
  80. package/dist/progress-circle.js +0 -128
  81. package/dist/progress.cjs +0 -117
  82. package/dist/progress.js +0 -94
  83. package/dist/provider.cjs +0 -62
  84. package/dist/provider.js +0 -40
  85. package/dist/radio.cjs +0 -177
  86. package/dist/radio.js +0 -153
  87. package/dist/rating.cjs +0 -80
  88. package/dist/rating.js +0 -58
  89. package/dist/select.cjs +0 -791
  90. package/dist/select.js +0 -757
  91. package/dist/separator.cjs +0 -57
  92. package/dist/separator.js +0 -51
  93. package/dist/skeleton.cjs +0 -370
  94. package/dist/skeleton.js +0 -346
  95. package/dist/slider.cjs +0 -138
  96. package/dist/slider.js +0 -115
  97. package/dist/switch.cjs +0 -163
  98. package/dist/switch.js +0 -140
  99. package/dist/table.cjs +0 -1044
  100. package/dist/table.js +0 -1013
  101. package/dist/tabs.cjs +0 -240
  102. package/dist/tabs.js +0 -213
  103. package/dist/tag.cjs +0 -651
  104. package/dist/tag.js +0 -628
  105. package/dist/textarea.cjs +0 -65
  106. package/dist/textarea.js +0 -59
  107. package/dist/toaster.cjs +0 -99
  108. package/dist/toaster.js +0 -96
  109. package/dist/tooltip.cjs +0 -171
  110. package/dist/tooltip.js +0 -148
  111. package/dist/utils.cjs +0 -11
  112. package/dist/utils.js +0 -9
  113. package/src/accordion.tsx +0 -285
  114. package/src/alert.tsx +0 -221
  115. package/src/avatar.tsx +0 -174
  116. package/src/badge.tsx +0 -158
  117. package/src/button.tsx +0 -411
  118. package/src/checkbox.tsx +0 -307
  119. package/src/close-button.tsx +0 -51
  120. package/src/collapsible.tsx +0 -126
  121. package/src/color-mode.tsx +0 -125
  122. package/src/dialog.tsx +0 -356
  123. package/src/drawer.tsx +0 -186
  124. package/src/empty-state.tsx +0 -97
  125. package/src/field.tsx +0 -202
  126. package/src/heading.tsx +0 -55
  127. package/src/icon-button.tsx +0 -192
  128. package/src/image.tsx +0 -280
  129. package/src/index.ts +0 -192
  130. package/src/input-group.tsx +0 -159
  131. package/src/input.tsx +0 -60
  132. package/src/link.tsx +0 -326
  133. package/src/menu.tsx +0 -471
  134. package/src/pin-input.tsx +0 -187
  135. package/src/popover.tsx +0 -400
  136. package/src/progress-circle.tsx +0 -180
  137. package/src/progress.tsx +0 -109
  138. package/src/provider.tsx +0 -12
  139. package/src/radio.tsx +0 -175
  140. package/src/rating.tsx +0 -79
  141. package/src/select.tsx +0 -696
  142. package/src/separator.tsx +0 -59
  143. package/src/skeleton.tsx +0 -302
  144. package/src/slider.tsx +0 -152
  145. package/src/switch.tsx +0 -158
  146. package/src/table.tsx +0 -621
  147. package/src/tabs.tsx +0 -354
  148. package/src/tag.tsx +0 -159
  149. package/src/textarea.tsx +0 -60
  150. package/src/toaster.tsx +0 -117
  151. package/src/tokens.css +0 -438
  152. package/src/tooltip.tsx +0 -184
  153. package/src/utils/cn.ts +0 -7
  154. package/src/utils.ts +0 -6
  155. package/tokens.css +0 -438
package/src/table.tsx DELETED
@@ -1,621 +0,0 @@
1
- import { throttle } from 'es-toolkit';
2
- import * as React from 'react';
3
-
4
- import { cn } from './utils';
5
-
6
- import { Link } from './link';
7
-
8
- // Inline east arrow icon
9
- const ArrowIcon = ({ className }: { readonly className?: string }) => (
10
- <svg className={ className } viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
11
- <path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
12
- </svg>
13
- );
14
-
15
- // ---------------------------------------------------------------------------
16
- // Chakra-style prop adapter
17
- // Consumers pass Chakra shorthand style props (width, minW, pr, etc.) directly
18
- // to table components. This helper converts them to a React CSSProperties object
19
- // so we can apply them as inline styles without requiring changes to all callers.
20
- // ---------------------------------------------------------------------------
21
-
22
- interface ChakraStyleProps {
23
- width?: React.CSSProperties['width'];
24
- w?: React.CSSProperties['width'];
25
- minWidth?: React.CSSProperties['minWidth'];
26
- minW?: React.CSSProperties['minWidth'];
27
- maxWidth?: React.CSSProperties['maxWidth'];
28
- maxW?: React.CSSProperties['maxWidth'];
29
- height?: React.CSSProperties['height'];
30
- h?: React.CSSProperties['height'];
31
- textAlign?: React.CSSProperties['textAlign'];
32
- verticalAlign?: React.CSSProperties['verticalAlign'];
33
- whiteSpace?: React.CSSProperties['whiteSpace'];
34
- wordBreak?: React.CSSProperties['wordBreak'];
35
- textTransform?: React.CSSProperties['textTransform'];
36
- fontSize?: React.CSSProperties['fontSize'];
37
- lineHeight?: React.CSSProperties['lineHeight'];
38
- animation?: React.CSSProperties['animation'];
39
- tableLayout?: React.CSSProperties['tableLayout'];
40
- p?: number | string;
41
- px?: number | string;
42
- py?: number | string;
43
- pr?: number | string;
44
- pl?: number | string;
45
- pt?: number | string;
46
- pb?: number | string;
47
- m?: number | string;
48
- mx?: number | string;
49
- my?: number | string;
50
- mr?: number | string;
51
- ml?: number | string;
52
- mt?: number | string;
53
- mb?: number | string;
54
- position?: React.CSSProperties['position'];
55
- top?: number | string;
56
- left?: number | string;
57
- right?: number | string;
58
- bottom?: number | string;
59
- zIndex?: React.CSSProperties['zIndex'];
60
- backgroundColor?: React.CSSProperties['backgroundColor'] | Record<string, string>;
61
- boxShadow?: React.CSSProperties['boxShadow'];
62
- alignItems?: React.CSSProperties['alignItems'];
63
- fontWeight?: React.CSSProperties['fontWeight'];
64
- color?: React.CSSProperties['color'] | string;
65
- overflow?: React.CSSProperties['overflow'];
66
- borderBottomStyle?: React.CSSProperties['borderBottomStyle'];
67
- borderRadius?: React.CSSProperties['borderRadius'];
68
- display?: React.CSSProperties['display'];
69
- // Chakra pseudo-prop pass-throughs (ignored in Tailwind)
70
- _first?: Record<string, unknown>;
71
- _last?: Record<string, unknown>;
72
- }
73
-
74
- const SPACING_SCALE = 4; // 1 unit = 4px (Chakra default)
75
-
76
- function toPixels(value: number | string | undefined): string | undefined {
77
- if (value === undefined) return undefined;
78
- if (typeof value === 'string') return value;
79
- return `${ value * SPACING_SCALE }px`;
80
- }
81
-
82
- function extractStyles(props: Record<string, unknown>): { style: React.CSSProperties; rest: Record<string, unknown> } {
83
- const style: React.CSSProperties = {};
84
- const rest: Record<string, unknown> = {};
85
-
86
- for (const [ key, value ] of Object.entries(props)) {
87
- if (value === undefined) continue;
88
-
89
- switch (key) {
90
- case 'width':
91
- case 'w':
92
- style.width = value as React.CSSProperties['width'];
93
- break;
94
- case 'minWidth':
95
- case 'minW':
96
- style.minWidth = value as React.CSSProperties['minWidth'];
97
- break;
98
- case 'maxWidth':
99
- case 'maxW':
100
- style.maxWidth = value as React.CSSProperties['maxWidth'];
101
- break;
102
- case 'height':
103
- case 'h':
104
- style.height = value as React.CSSProperties['height'];
105
- break;
106
- case 'textAlign':
107
- style.textAlign = value as React.CSSProperties['textAlign'];
108
- break;
109
- case 'verticalAlign':
110
- style.verticalAlign = value as React.CSSProperties['verticalAlign'];
111
- break;
112
- case 'whiteSpace':
113
- style.whiteSpace = value as React.CSSProperties['whiteSpace'];
114
- break;
115
- case 'wordBreak':
116
- style.wordBreak = value as React.CSSProperties['wordBreak'];
117
- break;
118
- case 'textTransform':
119
- style.textTransform = value as React.CSSProperties['textTransform'];
120
- break;
121
- case 'fontSize':
122
- style.fontSize = value as React.CSSProperties['fontSize'];
123
- break;
124
- case 'lineHeight':
125
- style.lineHeight = value as React.CSSProperties['lineHeight'];
126
- break;
127
- case 'animation':
128
- style.animation = value as React.CSSProperties['animation'];
129
- break;
130
- case 'tableLayout':
131
- style.tableLayout = value as React.CSSProperties['tableLayout'];
132
- break;
133
- case 'p':
134
- style.padding = toPixels(value as number | string);
135
- break;
136
- case 'px': {
137
- const px = toPixels(value as number | string);
138
- style.paddingLeft = px;
139
- style.paddingRight = px;
140
- break;
141
- }
142
- case 'py': {
143
- const py = toPixels(value as number | string);
144
- style.paddingTop = py;
145
- style.paddingBottom = py;
146
- break;
147
- }
148
- case 'pr':
149
- style.paddingRight = toPixels(value as number | string);
150
- break;
151
- case 'pl':
152
- style.paddingLeft = toPixels(value as number | string);
153
- break;
154
- case 'pt':
155
- style.paddingTop = toPixels(value as number | string);
156
- break;
157
- case 'pb':
158
- style.paddingBottom = toPixels(value as number | string);
159
- break;
160
- case 'm':
161
- style.margin = toPixels(value as number | string);
162
- break;
163
- case 'mx': {
164
- const mx = toPixels(value as number | string);
165
- style.marginLeft = mx;
166
- style.marginRight = mx;
167
- break;
168
- }
169
- case 'my': {
170
- const my = toPixels(value as number | string);
171
- style.marginTop = my;
172
- style.marginBottom = my;
173
- break;
174
- }
175
- case 'mr':
176
- style.marginRight = toPixels(value as number | string);
177
- break;
178
- case 'ml':
179
- style.marginLeft = toPixels(value as number | string);
180
- break;
181
- case 'mt':
182
- style.marginTop = toPixels(value as number | string);
183
- break;
184
- case 'mb':
185
- style.marginBottom = toPixels(value as number | string);
186
- break;
187
- case 'position':
188
- style.position = value as React.CSSProperties['position'];
189
- break;
190
- case 'top':
191
- style.top = typeof value === 'number' ? `${ value }px` : value as string;
192
- break;
193
- case 'left':
194
- style.left = typeof value === 'number' ? `${ value }px` : value as string;
195
- break;
196
- case 'right':
197
- style.right = typeof value === 'number' ? `${ value }px` : value as string;
198
- break;
199
- case 'bottom':
200
- style.bottom = typeof value === 'number' ? `${ value }px` : value as string;
201
- break;
202
- case 'zIndex':
203
- style.zIndex = value as React.CSSProperties['zIndex'];
204
- break;
205
- case 'backgroundColor':
206
- // Skip Chakra responsive objects like { _light: ..., _dark: ... }
207
- if (typeof value === 'string') {
208
- style.backgroundColor = value;
209
- }
210
- break;
211
- case 'boxShadow':
212
- style.boxShadow = value as React.CSSProperties['boxShadow'];
213
- break;
214
- case 'alignItems':
215
- style.alignItems = value as React.CSSProperties['alignItems'];
216
- break;
217
- case 'fontWeight':
218
- style.fontWeight = value as React.CSSProperties['fontWeight'];
219
- break;
220
- case 'color':
221
- if (typeof value === 'string') {
222
- style.color = value;
223
- }
224
- break;
225
- case 'overflow':
226
- style.overflow = value as React.CSSProperties['overflow'];
227
- break;
228
- case 'borderBottomStyle':
229
- style.borderBottomStyle = value as React.CSSProperties['borderBottomStyle'];
230
- break;
231
- case 'borderRadius':
232
- style.borderRadius = value as React.CSSProperties['borderRadius'];
233
- break;
234
- case 'display':
235
- style.display = value as React.CSSProperties['display'];
236
- break;
237
- // Chakra pseudo-props: silently drop
238
- case '_first':
239
- case '_last':
240
- break;
241
- default:
242
- rest[key] = value;
243
- break;
244
- }
245
- }
246
-
247
- return { style, rest };
248
- }
249
-
250
- // ---------------------------------------------------------------------------
251
- // Responsive prop helper
252
- // Consumers pass Chakra responsive objects like { base: '1200px', lg: '1000px' }.
253
- // Convert them to inline style using the base value (mobile-first).
254
- // ---------------------------------------------------------------------------
255
-
256
- function resolveResponsive(value: unknown): string | undefined {
257
- if (value === undefined || value === null) return undefined;
258
- if (typeof value === 'string') return value;
259
- if (typeof value === 'number') return `${ value }px`;
260
- if (typeof value === 'object' && value !== null && 'base' in value) {
261
- return (value as Record<string, string>).base;
262
- }
263
- return undefined;
264
- }
265
-
266
- // ---------------------------------------------------------------------------
267
- // TableRoot
268
- // ---------------------------------------------------------------------------
269
-
270
- export interface TableRootProps extends Omit<ChakraStyleProps, 'minWidth' | 'minW'>, Omit<React.HTMLAttributes<HTMLTableElement>, 'color'> {
271
- children?: React.ReactNode;
272
- minWidth?: React.CSSProperties['minWidth'] | Record<string, string>;
273
- minW?: React.CSSProperties['minWidth'] | Record<string, string>;
274
- }
275
-
276
- export const TableRoot = React.forwardRef<HTMLTableElement, TableRootProps>(
277
- function TableRoot(props, ref) {
278
- const { className, style: styleProp, children, ...other } = props;
279
-
280
- // Handle responsive minWidth/minW
281
- const rawMinW = other.minWidth ?? other.minW;
282
- const resolvedMinW = resolveResponsive(rawMinW);
283
- if (resolvedMinW) {
284
- other.minWidth = resolvedMinW;
285
- delete other.minW;
286
- }
287
-
288
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
289
- const merged = { ...extracted, ...styleProp };
290
-
291
- return (
292
- <table
293
- ref={ ref }
294
- className={ cn('w-full border-collapse text-sm', className) }
295
- style={ merged }
296
- { ...(rest as React.HTMLAttributes<HTMLTableElement>) }
297
- >
298
- { children }
299
- </table>
300
- );
301
- },
302
- );
303
-
304
- // ---------------------------------------------------------------------------
305
- // TableHeader (thead)
306
- // ---------------------------------------------------------------------------
307
-
308
- export interface TableHeaderProps extends ChakraStyleProps, Omit<React.HTMLAttributes<HTMLTableSectionElement>, 'color'> {
309
- children?: React.ReactNode;
310
- }
311
-
312
- export const TableHeader = React.forwardRef<HTMLTableSectionElement, TableHeaderProps>(
313
- function TableHeader(props, ref) {
314
- const { className, style: styleProp, children, ...other } = props;
315
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
316
- const merged = { ...extracted, ...styleProp };
317
-
318
- return (
319
- <thead
320
- ref={ ref }
321
- className={ cn('', className) }
322
- style={ merged }
323
- { ...(rest as React.HTMLAttributes<HTMLTableSectionElement>) }
324
- >
325
- { children }
326
- </thead>
327
- );
328
- },
329
- );
330
-
331
- // ---------------------------------------------------------------------------
332
- // TableBody (tbody)
333
- // ---------------------------------------------------------------------------
334
-
335
- export interface TableBodyProps extends ChakraStyleProps, Omit<React.HTMLAttributes<HTMLTableSectionElement>, 'color'> {
336
- children?: React.ReactNode;
337
- }
338
-
339
- export const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
340
- function TableBody(props, ref) {
341
- const { className, style: styleProp, children, ...other } = props;
342
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
343
- const merged = { ...extracted, ...styleProp };
344
-
345
- return (
346
- <tbody
347
- ref={ ref }
348
- className={ cn('', className) }
349
- style={ merged }
350
- { ...(rest as React.HTMLAttributes<HTMLTableSectionElement>) }
351
- >
352
- { children }
353
- </tbody>
354
- );
355
- },
356
- );
357
-
358
- // ---------------------------------------------------------------------------
359
- // TableRow (tr)
360
- // ---------------------------------------------------------------------------
361
-
362
- export interface TableRowProps extends ChakraStyleProps, Omit<React.HTMLAttributes<HTMLTableRowElement>, 'color'> {
363
- children?: React.ReactNode;
364
- }
365
-
366
- export const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(
367
- function TableRow(props, ref) {
368
- const { className, style: styleProp, children, ...other } = props;
369
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
370
- const merged = { ...extracted, ...styleProp };
371
-
372
- return (
373
- <tr
374
- ref={ ref }
375
- className={ cn('', className) }
376
- style={ merged }
377
- { ...(rest as React.HTMLAttributes<HTMLTableRowElement>) }
378
- >
379
- { children }
380
- </tr>
381
- );
382
- },
383
- );
384
-
385
- // ---------------------------------------------------------------------------
386
- // TableCell (td)
387
- // ---------------------------------------------------------------------------
388
-
389
- export interface TableCellProps extends Omit<ChakraStyleProps, 'width' | 'height'>, Omit<React.TdHTMLAttributes<HTMLTableCellElement>, 'color'> {
390
- isNumeric?: boolean;
391
- children?: React.ReactNode;
392
- display?: string;
393
- justifyContent?: string;
394
- }
395
-
396
- export const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
397
- function TableCell(props, ref) {
398
- const { isNumeric, className, style: styleProp, children, ...other } = props;
399
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
400
- const merged = {
401
- ...(isNumeric ? { textAlign: 'right' as const } : {}),
402
- ...extracted,
403
- ...styleProp,
404
- };
405
-
406
- return (
407
- <td
408
- ref={ ref }
409
- className={ cn('px-3 py-2.5 align-top text-sm', className) }
410
- style={ merged }
411
- { ...(rest as React.TdHTMLAttributes<HTMLTableCellElement>) }
412
- >
413
- { children }
414
- </td>
415
- );
416
- },
417
- );
418
-
419
- // ---------------------------------------------------------------------------
420
- // TableColumnHeader (th)
421
- // ---------------------------------------------------------------------------
422
-
423
- export interface TableColumnHeaderProps extends ChakraStyleProps, Omit<React.ThHTMLAttributes<HTMLTableCellElement>, 'color'> {
424
- isNumeric?: boolean;
425
- children?: React.ReactNode;
426
- }
427
-
428
- export const TableColumnHeader = React.forwardRef<HTMLTableCellElement, TableColumnHeaderProps>(
429
- function TableColumnHeader(props, ref) {
430
- const { isNumeric, className, style: styleProp, children, ...other } = props;
431
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
432
- const merged = {
433
- ...(isNumeric ? { textAlign: 'right' as const } : {}),
434
- ...extracted,
435
- ...styleProp,
436
- };
437
-
438
- return (
439
- <th
440
- ref={ ref }
441
- className={ cn(
442
- 'px-3 py-2 text-xs font-semibold uppercase tracking-wider',
443
- 'bg-[var(--color-table-header-bg)] text-[var(--color-table-header-fg)]',
444
- className,
445
- ) }
446
- style={ merged }
447
- { ...(rest as React.ThHTMLAttributes<HTMLTableCellElement>) }
448
- >
449
- { children }
450
- </th>
451
- );
452
- },
453
- );
454
-
455
- // ---------------------------------------------------------------------------
456
- // TableColumnHeaderSortable
457
- // ---------------------------------------------------------------------------
458
-
459
- export interface TableColumnHeaderSortableProps<F extends string> extends TableColumnHeaderProps {
460
- sortField: F;
461
- sortValue: string;
462
- onSortToggle: (sortField: F) => void;
463
- disabled?: boolean;
464
- indicatorPosition?: 'left' | 'right';
465
- contentAfter?: React.ReactNode;
466
- }
467
-
468
- export const TableColumnHeaderSortable = <F extends string>(props: TableColumnHeaderSortableProps<F>) => {
469
- const { sortField, sortValue, onSortToggle, children, disabled, indicatorPosition = 'left', contentAfter, ...rest } = props;
470
-
471
- const handleSortToggle = React.useCallback(() => {
472
- onSortToggle(sortField);
473
- }, [ onSortToggle, sortField ]);
474
-
475
- const isActive = sortValue.includes(sortField);
476
- const isAsc = sortValue.toLowerCase().includes('asc');
477
-
478
- return (
479
- <TableColumnHeader { ...rest }>
480
- <Link onClick={ disabled ? undefined : handleSortToggle } className="relative">
481
- { isActive && (
482
- <span
483
- className={ cn(
484
- 'absolute top-0 inline-flex h-full w-4 items-center',
485
- indicatorPosition === 'left' ? '-left-5' : '-right-5',
486
- isAsc ? '-rotate-90' : 'rotate-90',
487
- ) }
488
- >
489
- <ArrowIcon className="h-4 w-4"/>
490
- </span>
491
- ) }
492
- { children }
493
- </Link>
494
- { contentAfter }
495
- </TableColumnHeader>
496
- );
497
- };
498
-
499
- // ---------------------------------------------------------------------------
500
- // TableHeaderSticky
501
- // ---------------------------------------------------------------------------
502
-
503
- const ACTION_BAR_SHADOW = '0 4px 4px -4px rgb(0 0 0 / 10%), 0 2px 4px -4px rgb(0 0 0 / 6%)';
504
-
505
- export const TableHeaderSticky = (props: TableHeaderProps) => {
506
- const { top, children, className, style: styleProp, ...rest } = props;
507
-
508
- const ref = React.useRef<HTMLTableSectionElement>(null);
509
- const [ isStuck, setIsStuck ] = React.useState(false);
510
-
511
- const handleScroll = React.useCallback(() => {
512
- if (Number(ref.current?.getBoundingClientRect().y) <= (Number(top) || 0)) {
513
- setIsStuck(true);
514
- } else {
515
- setIsStuck(false);
516
- }
517
- }, [ top ]);
518
-
519
- React.useEffect(() => {
520
- const throttledHandleScroll = throttle(handleScroll, 300);
521
-
522
- window.addEventListener('scroll', throttledHandleScroll);
523
-
524
- return () => {
525
- window.removeEventListener('scroll', throttledHandleScroll);
526
- };
527
- }, [ handleScroll ]);
528
-
529
- return (
530
- <TableHeader
531
- ref={ ref }
532
- className={ cn('sticky z-[1] bg-white dark:bg-black', className) }
533
- style={{
534
- top: top ? `${ top }px` : 0,
535
- boxShadow: isStuck ? ACTION_BAR_SHADOW : 'none',
536
- ...styleProp,
537
- }}
538
- { ...rest }
539
- >
540
- { children }
541
- </TableHeader>
542
- );
543
- };
544
-
545
- // ---------------------------------------------------------------------------
546
- // TableCaption
547
- // ---------------------------------------------------------------------------
548
-
549
- export interface TableCaptionProps extends ChakraStyleProps, Omit<React.HTMLAttributes<HTMLTableCaptionElement>, 'color'> {
550
- children?: React.ReactNode;
551
- }
552
-
553
- export const TableCaption = React.forwardRef<HTMLTableCaptionElement, TableCaptionProps>(
554
- function TableCaption(props, ref) {
555
- const { className, style: styleProp, children, ...other } = props;
556
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
557
- const merged = { ...extracted, ...styleProp };
558
-
559
- return (
560
- <caption
561
- ref={ ref }
562
- className={ cn('px-3 py-2 text-sm text-[var(--color-table-header-fg)]', className) }
563
- style={ merged }
564
- { ...(rest as React.HTMLAttributes<HTMLTableCaptionElement>) }
565
- >
566
- { children }
567
- </caption>
568
- );
569
- },
570
- );
571
-
572
- // ---------------------------------------------------------------------------
573
- // TableFooter (tfoot)
574
- // ---------------------------------------------------------------------------
575
-
576
- export interface TableFooterProps extends ChakraStyleProps, Omit<React.HTMLAttributes<HTMLTableSectionElement>, 'color'> {
577
- children?: React.ReactNode;
578
- }
579
-
580
- export const TableFooter = React.forwardRef<HTMLTableSectionElement, TableFooterProps>(
581
- function TableFooter(props, ref) {
582
- const { className, style: styleProp, children, ...other } = props;
583
- const { style: extracted, rest } = extractStyles(other as Record<string, unknown>);
584
- const merged = { ...extracted, ...styleProp };
585
-
586
- return (
587
- <tfoot
588
- ref={ ref }
589
- className={ cn('', className) }
590
- style={ merged }
591
- { ...(rest as React.HTMLAttributes<HTMLTableSectionElement>) }
592
- >
593
- { children }
594
- </tfoot>
595
- );
596
- },
597
- );
598
-
599
- // ---------------------------------------------------------------------------
600
- // TableScrollWrapper
601
- // ---------------------------------------------------------------------------
602
-
603
- export interface TableScrollWrapperProps extends React.HTMLAttributes<HTMLDivElement> {
604
- children?: React.ReactNode;
605
- }
606
-
607
- export const TableScrollWrapper = React.forwardRef<HTMLDivElement, TableScrollWrapperProps>(
608
- function TableScrollWrapper(props, ref) {
609
- const { className, children, ...rest } = props;
610
-
611
- return (
612
- <div
613
- ref={ ref }
614
- className={ cn('w-full overflow-x-auto', className) }
615
- { ...rest }
616
- >
617
- { children }
618
- </div>
619
- );
620
- },
621
- );