UNPKG

3.73 kBTypeScriptView Raw
1import React, { forwardRef, memo, type ReactNode, type CSSProperties } from "react";
2import { assert } from "tsafe/assert";
3import type { Equals } from "tsafe";
4import { fr } from "./fr";
5import { cx } from "./tools/cx";
6import { symToStr } from "tsafe/symToStr";
7import type { FrClassName } from "./fr/generatedFromCss/classNames";
8import { useAnalyticsId } from "./tools/useAnalyticsId";
9
10export type TableProps = {
11 id?: string;
12 data: ReactNode[][];
13 className?: string;
14 caption?: ReactNode;
15 headers?: ReactNode[];
16 /** Default: false */
17 fixed?: boolean;
18 /** Default: false */
19 noScroll?: boolean;
20 /** Default: false */
21 bordered?: boolean;
22 /** Default: false */
23 noCaption?: boolean;
24 /** Default: false */
25 bottomCaption?: boolean;
26 style?: CSSProperties;
27 colorVariant?: TableProps.ColorVariant;
28};
29
30export namespace TableProps {
31 type ExtractColorVariant<FrClassName> = FrClassName extends `fr-table--${infer AccentColor}`
32 ? Exclude<
33 AccentColor,
34 "no-scroll" | "no-caption" | "caption-bottom" | "layout-fixed" | "bordered"
35 >
36 : never;
37
38 export type ColorVariant = ExtractColorVariant<FrClassName>;
39}
40
41/** @see <https://components.react-dsfr.codegouv.studio/?path=/docs/tableau> */
42export const Table = memo(
43 forwardRef<HTMLDivElement, TableProps>((props, ref) => {
44 const {
45 id: id_props,
46 data,
47 headers,
48 caption,
49 bordered = false,
50 noScroll = false,
51 fixed = false,
52 noCaption = false,
53 bottomCaption = false,
54 colorVariant,
55 className,
56 style,
57 ...rest
58 } = props;
59
60 assert<Equals<keyof typeof rest, never>>();
61
62 const id = useAnalyticsId({
63 "defaultIdPrefix": "fr-table",
64 "explicitlyProvidedId": id_props
65 });
66
67 return (
68 <div
69 id={id}
70 ref={ref}
71 style={style}
72 className={cx(
73 fr.cx(
74 "fr-table",
75 {
76 "fr-table--bordered": bordered,
77 "fr-table--no-scroll": noScroll,
78 "fr-table--layout-fixed": fixed,
79 "fr-table--no-caption": noCaption,
80 "fr-table--caption-bottom": bottomCaption
81 },
82 colorVariant !== undefined && `fr-table--${colorVariant}`
83 ),
84 className
85 )}
86 >
87 <table>
88 {caption !== undefined && <caption>{caption}</caption>}
89 {headers !== undefined && (
90 <thead>
91 <tr>
92 {headers.map((header, i) => (
93 <th key={i} scope="col">
94 {header}
95 </th>
96 ))}
97 </tr>
98 </thead>
99 )}
100 <tbody>
101 {data.map((row, i) => (
102 <tr key={i}>
103 {row.map((col, j) => (
104 <td key={j}>{col}</td>
105 ))}
106 </tr>
107 ))}
108 </tbody>
109 </table>
110 </div>
111 );
112 })
113);
114
115Table.displayName = symToStr({ Table });
116
117export default Table;
118
\No newline at end of file