Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/components/Table/GridTable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,23 @@ describe("GridTable", () => {
expect(cellOf(r, "customTestId", 0, 0).textContent).toBe("Name");
expect(row(r, 0, "customTestId").textContent).toBe("NameValue");
});

it("can use __typename for the kid", async () => {
// Given the table with a column that defines the `kind: data` as an empty cell
type AuthorFragment = { __typename: "Author"; id: string; firstName: string };
type Row = { kind: "header" } | AuthorFragment;
const nameColumn: GridColumn<Row> = { header: () => "Name", author: emptyCell };
// And a table where the there is an `emptyCell` style specified
const r = await render(
<GridTable<Row>
columns={[nameColumn]}
rows={[simpleHeader, { __typename: "Author", id: "a:1", firstName: "a" }]}
/>,
);
// Then the cell in this column should actually be empty
expect(cell(r, 1, 0)).toBeEmptyDOMElement();
expect(cell(r, 1, 1).textContent).toBe("1");
});
});

function Collapse({ id }: { id: string }) {
Expand Down
38 changes: 23 additions & 15 deletions src/components/Table/GridTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Css, Margin, Only, Properties, Xss } from "src/Css";
import tinycolor from "tinycolor2";
import { defaultStyle } from ".";

export type Kinded = { kind: string };
export type Kinded = { kind: string } | { __typename: string };
export type GridTableXss = Xss<Margin>;

export const ASC = "ASC" as const;
Expand Down Expand Up @@ -721,11 +721,17 @@ function maybeAddCardColumns(sizes: string[], firstLastColumnWidth: number | und
export type DiscriminateUnion<T, K extends keyof T, V extends T[K]> = T extends Record<K, V> ? T : never;

/** A specific kind of row, including the GridDataRow props. */
type GridRowKind<R extends Kinded, P extends R["kind"]> = DiscriminateUnion<R, "kind", P> & {
type GridRowKind<R extends Kinded, P extends KindOrTypename<R>["kind"]> = DiscriminateUnion<
KindOrTypename<R>,
"kind",
P
> & {
id: string;
children: GridDataRow<R>[];
};

type KindOrTypename<R extends Kinded> = R extends { __typename: infer T } ? { kind: T } : R;

/**
* Defines how a single column will render each given row `kind` in `R`.
*
Expand All @@ -738,9 +744,9 @@ type GridRowKind<R extends Kinded, P extends R["kind"]> = DiscriminateUnion<R, "
* column being sorted, in which case we use the GridCellContent.value.
*/
export type GridColumn<R extends Kinded, S = {}> = {
[K in R["kind"]]:
[K in KindOrTypename<R>["kind"]]:
| string
| (DiscriminateUnion<R, "kind", K> extends { data: infer D }
| (DiscriminateUnion<KindOrTypename<R>, "kind", K> extends { data: infer D }
? (data: D, row: GridRowKind<R, K>) => ReactNode | GridCellContent
: (row: GridRowKind<R, K>) => ReactNode | GridCellContent);
} & {
Expand Down Expand Up @@ -783,7 +789,7 @@ type RenderCellFn<R extends Kinded> = (

/** Defines row-specific styling for each given row `kind` in `R` */
export type GridRowStyles<R extends Kinded> = {
[P in R["kind"]]?: RowStyle<DiscriminateUnion<R, "kind", P>>;
[P in KindOrTypename<R>["kind"]]?: RowStyle<DiscriminateUnion<KindOrTypename<R>, "kind", P>>;
};

export interface RowStyle<R extends Kinded> {
Expand Down Expand Up @@ -852,15 +858,17 @@ type MaybeFn<T> = T | (() => T);
* The presentation concerns instead mainly live in each GridColumn definition, which will format/render
* each kind's data for that specific row+column (i.e. cell) combination.
*/
export type GridDataRow<R extends Kinded> = {
kind: R["kind"];
/** Combined with the `kind` to determine a table wide React key. */
id: string;
/** A list of parent/grand-parent ids for collapsing parent/child rows. */
children?: GridDataRow<R>[];
/** Whether to pin this sort to the first/last of its parent's children. */
pin?: "first" | "last";
} & DiscriminateUnion<R, "kind", R["kind"]>;
export type GridDataRow<R extends Kinded> = R extends { kind: any }
? {
kind: R["kind"];
/** Combined with the `kind` to determine a table wide React key. */
id: string;
/** A list of parent/grand-parent ids for collapsing parent/child rows. */
children?: GridDataRow<R>[];
/** Whether to pin this sort to the first/last of its parent's children. */
pin?: "first" | "last";
} & DiscriminateUnion<R, "kind", R["kind"]>
: never;

interface GridRowProps<R extends Kinded, S> {
as: RenderAs;
Expand Down Expand Up @@ -896,7 +904,7 @@ function GridRow<R extends Kinded, S>(props: GridRowProps<R, S>): ReactElement {

// We treat the "header" kind as special for "good defaults" styling
const isHeader = row.kind === "header";
const rowStyle = rowStyles?.[row.kind];
const rowStyle = rowStyles?.[(row.kind ?? row.__typename) as R];

const rowStyleCellCss = maybeApplyFunction(row, rowStyle?.cellCss);
const rowCss = {
Expand Down