table.tsx 2.8 KB

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