According to our #1660 we want to abstract the rendering of the OnyxDataGrid. We implement this TableRenderLayer via the OnyxDataGridRenderer support component.
The TableRenderLayer must be stateless.
Its main purpose is to create an HTML compliant table structure.
The table should be rendered according to the following rules:
columns describes the horizontal layout of the table, every entry MUST result in a column and <th>element
rows describe the vertical layout of the table, every entry MUST result in a row and a <tr> element
so there should not be any "unused" entries in either column or row
extensions should only follow table concepts that are supported/specified by the HTML spec
the entry keys of a row must match the specified columns or colgroups
the content of the table data cells (<td>...</td>) in a row can be any content
The following is the code used by the PoC of #1660.
@JoCa96 - I would consider making the id key dynamic. Column and row grouping, as well as styling was not yet considered.
import type { FunctionalComponent, HTMLAttributes, TdHTMLAttributes } from "vue";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type AnyKey = keyof any;
export type TableEntry = {
id: string | number;
[key: AnyKey]: unknown;
};
export type Metadata = Record<string, unknown>;
export type CellRenderFunc<
TEntry extends TableEntry,
TMetadata extends Metadata,
> = FunctionalComponent<RenderCellProps<TEntry, TMetadata>>;
/**
* Props of the TableRenderLayer
*/
export type RendererProps<TEntry extends TableEntry, TMetadata extends Metadata> = {
theadProps?: HTMLAttributes;
tbodyProps?: HTMLAttributes;
columns: RenderHeader<TEntry>[];
rows: RenderRow<TEntry, TMetadata>[];
};
export type RenderHeader<
TEntry extends TableEntry,
TKey extends keyof TEntry = keyof TEntry,
TProps extends object = object,
> = {
/**
* Key of the column - usually a key of the tabledata.
* But can also be used for custom columns.
*/
key: TKey;
/**
* Attributes and data that is provided to the component using `v-bind`.
*/
headerProps: HTMLAttributes & TProps;
/**
* The component that renders the header content.
*/
header: FunctionalComponent<TProps>;
};
export type RenderRow<TEntry extends TableEntry, TMetadata extends Metadata> = {
/**
* Unique id of the row.
*/
id: TableEntry["id"];
trProps?: HTMLAttributes;
cells: Record<keyof TEntry, RenderCell<TEntry, TMetadata> | undefined>;
};
export type RenderCell<TEntry extends TableEntry, TMetadata extends Metadata> = {
props: RenderCellProps<TEntry, TMetadata>;
tdProps?: TdHTMLAttributes;
/**
* The component that renders the actual cell content.
*/
is: CellRenderFunc<TEntry, TMetadata>;
};
export type RenderCellProps<TEntry extends TableEntry, TMetadata extends Metadata> = {
/**
* Complete row data
*/
row: TEntry;
/**
* Data that is provided to the component via the `metadata` prop
*/
metadata?: TMetadata;
/**
* table data that is provided to the component via the `modelValue` prop
*/
modelValue: TEntry[keyof TEntry];
};
Why?
According to our #1660 we want to abstract the rendering of the OnyxDataGrid. We implement this TableRenderLayer via the
OnyxDataGridRenderer
support component.It encompasses a minimal API that renders an HTML compliant table with only permitted content elements: