table.tsx 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. 'use client';
  2. import { type ComponentRenderProps } from '@json-render/react';
  3. import { useData } from '@json-render/react';
  4. import { getByPath } from '@json-render/core';
  5. export function Table({ element }: ComponentRenderProps) {
  6. const { title, dataPath, columns } = element.props as {
  7. title?: string | null;
  8. dataPath: string;
  9. columns: Array<{ key: string; label: string; format?: string | null }>;
  10. };
  11. const { data } = useData();
  12. const tableData = getByPath(data, dataPath) as Array<Record<string, unknown>> | undefined;
  13. if (!tableData || !Array.isArray(tableData)) {
  14. return <div style={{ padding: 20, color: 'var(--muted)' }}>No data</div>;
  15. }
  16. const formatCell = (value: unknown, format?: string | null) => {
  17. if (value === null || value === undefined) return '-';
  18. if (format === 'currency' && typeof value === 'number') {
  19. return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value);
  20. }
  21. if (format === 'date' && typeof value === 'string') {
  22. return new Date(value).toLocaleDateString();
  23. }
  24. if (format === 'badge') {
  25. return (
  26. <span
  27. style={{
  28. padding: '2px 8px',
  29. borderRadius: 12,
  30. fontSize: 12,
  31. fontWeight: 500,
  32. background: 'var(--border)',
  33. color: 'var(--foreground)',
  34. }}
  35. >
  36. {String(value)}
  37. </span>
  38. );
  39. }
  40. return String(value);
  41. };
  42. return (
  43. <div>
  44. {title && <h4 style={{ margin: '0 0 16px', fontSize: 14, fontWeight: 600 }}>{title}</h4>}
  45. <table style={{ width: '100%', borderCollapse: 'collapse' }}>
  46. <thead>
  47. <tr>
  48. {columns.map((col) => (
  49. <th
  50. key={col.key}
  51. style={{
  52. textAlign: 'left',
  53. padding: '12px 8px',
  54. borderBottom: '1px solid var(--border)',
  55. fontSize: 12,
  56. fontWeight: 500,
  57. color: 'var(--muted)',
  58. textTransform: 'uppercase',
  59. letterSpacing: '0.05em',
  60. }}
  61. >
  62. {col.label}
  63. </th>
  64. ))}
  65. </tr>
  66. </thead>
  67. <tbody>
  68. {tableData.map((row, i) => (
  69. <tr key={i}>
  70. {columns.map((col) => (
  71. <td
  72. key={col.key}
  73. style={{
  74. padding: '12px 8px',
  75. borderBottom: '1px solid var(--border)',
  76. fontSize: 14,
  77. }}
  78. >
  79. {formatCell(row[col.key], col.format)}
  80. </td>
  81. ))}
  82. </tr>
  83. ))}
  84. </tbody>
  85. </table>
  86. </div>
  87. );
  88. }