Skip to content

Commit

Permalink
Merge pull request #25 from bryanmylee/plugins/addGridLayout
Browse files Browse the repository at this point in the history
`addGridLayout`
  • Loading branch information
bryanmylee authored May 27, 2022
2 parents 16cb21b + 0dea79b commit d5e0040
Show file tree
Hide file tree
Showing 15 changed files with 667 additions and 90 deletions.
4 changes: 4 additions & 0 deletions src/lib/bodyCells.HeaderCell.render.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class TestHeaderCell<Item> extends HeaderCell<Item> {
id: this.id,
colspan: this.colspan,
label: this.label,
colstart: 1,
});
}
}
Expand All @@ -25,6 +26,7 @@ it('renders string label', () => {
id: '0',
label: 'Name',
colspan: 1,
colstart: 1,
});

expect(actual.render()).toBe('Name');
Expand All @@ -39,6 +41,7 @@ it('renders dynamic label with state', () => {
id: '0',
label: ({ columns }) => `${columns.length} columns`,
colspan: 1,
colstart: 1,
});

actual.injectState(state);
Expand All @@ -51,6 +54,7 @@ it('throws if rendering dynamically without state', () => {
id: '0',
label: ({ columns }) => `${columns.length} columns`,
colspan: 1,
colstart: 1,
});

expect(() => {
Expand Down
88 changes: 77 additions & 11 deletions src/lib/createViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,38 @@ import type {
AnyPlugins,
DeriveFlatColumnsFn,
DeriveRowsFn,
DeriveFn,
PluginStates,
} from './types/TablePlugin';
import { finalizeAttributes } from './utils/attributes';
import { nonUndefined } from './utils/filter';

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type TableAttributes<Item, Plugins extends AnyPlugins = AnyPlugins> = {
export type TableAttributes<Item, Plugins extends AnyPlugins = AnyPlugins> = Record<
string,
unknown
> & {
role: 'table';
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type TableBodyAttributes<Item, Plugins extends AnyPlugins = AnyPlugins> = {
export type TableHeadAttributes<Item, Plugins extends AnyPlugins = AnyPlugins> = Record<
string,
unknown
>;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type TableBodyAttributes<Item, Plugins extends AnyPlugins = AnyPlugins> = Record<
string,
unknown
> & {
role: 'rowgroup';
};

export interface TableViewModel<Item, Plugins extends AnyPlugins = AnyPlugins> {
flatColumns: FlatColumn<Item, Plugins>[];
tableAttrs: Readable<TableAttributes<Item, Plugins>>;
tableHeadAttrs: Readable<TableHeadAttributes<Item, Plugins>>;
tableBodyAttrs: Readable<TableBodyAttributes<Item, Plugins>>;
visibleColumns: Readable<FlatColumn<Item, Plugins>[]>;
headerRows: Readable<HeaderRow<Item, Plugins>[]>;
Expand Down Expand Up @@ -64,18 +79,20 @@ export const createViewModel = <Item, Plugins extends AnyPlugins = AnyPlugins>(
const _headerRows = writable<HeaderRow<Item, Plugins>[]>();
const _rows = writable<BodyRow<Item, Plugins>[]>([]);
const _pageRows = writable<BodyRow<Item, Plugins>[]>([]);
const tableAttrs = readable({
const _tableAttrs = writable<TableAttributes<Item>>({
role: 'table' as const,
});
const tableBodyAttrs = readable({
const _tableHeadAttrs = writable<TableHeadAttributes<Item>>({});
const _tableBodyAttrs = writable<TableBodyAttributes<Item>>({
role: 'rowgroup' as const,
});
const pluginInitTableState: PluginInitTableState<Item, Plugins> = {
data,
columns,
tableAttrs,
tableBodyAttrs,
flatColumns: $flatColumns,
tableAttrs: _tableAttrs,
tableHeadAttrs: _tableHeadAttrs,
tableBodyAttrs: _tableBodyAttrs,
visibleColumns: _visibleColumns,
headerRows: _headerRows,
originalRows,
Expand Down Expand Up @@ -110,9 +127,10 @@ export const createViewModel = <Item, Plugins extends AnyPlugins = AnyPlugins>(
const tableState: TableState<Item, Plugins> = {
data,
columns,
tableAttrs,
tableBodyAttrs,
flatColumns: $flatColumns,
tableAttrs: _tableAttrs,
tableHeadAttrs: _tableHeadAttrs,
tableBodyAttrs: _tableBodyAttrs,
visibleColumns: _visibleColumns,
headerRows: _headerRows,
originalRows,
Expand All @@ -121,6 +139,53 @@ export const createViewModel = <Item, Plugins extends AnyPlugins = AnyPlugins>(
pluginStates,
};

const deriveTableAttrsFns: DeriveFn<TableAttributes<Item>>[] = Object.values(pluginInstances)
.map((pluginInstance) => pluginInstance.deriveTableAttrs)
.filter(nonUndefined);
let tableAttrs = readable<TableAttributes<Item>>({
role: 'table',
});
deriveTableAttrsFns.forEach((fn) => {
tableAttrs = fn(tableAttrs);
});
const finalizedTableAttrs = derived(tableAttrs, ($tableAttrs) => {
const $finalizedAttrs = finalizeAttributes($tableAttrs) as TableAttributes<Item>;
_tableAttrs.set($finalizedAttrs);
return $finalizedAttrs;
});

const deriveTableHeadAttrsFns: DeriveFn<TableHeadAttributes<Item>>[] = Object.values(
pluginInstances
)
.map((pluginInstance) => pluginInstance.deriveTableBodyAttrs)
.filter(nonUndefined);
let tableHeadAttrs = readable<TableHeadAttributes<Item>>({});
deriveTableHeadAttrsFns.forEach((fn) => {
tableHeadAttrs = fn(tableHeadAttrs);
});
const finalizedTableHeadAttrs = derived(tableHeadAttrs, ($tableHeadAttrs) => {
const $finalizedAttrs = finalizeAttributes($tableHeadAttrs) as TableHeadAttributes<Item>;
_tableHeadAttrs.set($finalizedAttrs);
return $finalizedAttrs;
});

const deriveTableBodyAttrsFns: DeriveFn<TableBodyAttributes<Item>>[] = Object.values(
pluginInstances
)
.map((pluginInstance) => pluginInstance.deriveTableBodyAttrs)
.filter(nonUndefined);
let tableBodyAttrs = readable<TableBodyAttributes<Item>>({
role: 'rowgroup',
});
deriveTableBodyAttrsFns.forEach((fn) => {
tableBodyAttrs = fn(tableBodyAttrs);
});
const finalizedTableBodyAttrs = derived(tableBodyAttrs, ($tableBodyAttrs) => {
const $finalizedAttrs = finalizeAttributes($tableBodyAttrs) as TableBodyAttributes<Item>;
_tableBodyAttrs.set($finalizedAttrs);
return $finalizedAttrs;
});

const deriveFlatColumnsFns: DeriveFlatColumnsFn<Item>[] = Object.values(pluginInstances)
.map((pluginInstance) => pluginInstance.deriveFlatColumns)
.filter(nonUndefined);
Expand Down Expand Up @@ -246,10 +311,11 @@ export const createViewModel = <Item, Plugins extends AnyPlugins = AnyPlugins>(
});

return {
tableAttrs,
tableBodyAttrs,
flatColumns: $flatColumns,
tableAttrs: finalizedTableAttrs,
tableHeadAttrs: finalizedTableHeadAttrs,
tableBodyAttrs: finalizedTableBodyAttrs,
visibleColumns: injectedColumns,
flatColumns: $flatColumns,
headerRows,
originalRows,
rows: injectedRows,
Expand Down
36 changes: 23 additions & 13 deletions src/lib/headerCells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,27 @@ export type HeaderCellInit<Item, Plugins extends AnyPlugins = AnyPlugins> = {
id: string;
label: HeaderLabel<Item>;
colspan: number;
colstart: number;
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type HeaderCellAttributes<Item, Plugins extends AnyPlugins = AnyPlugins> = {
role: 'columnheader';
colspan: number;
};

export abstract class HeaderCell<
Item,
Plugins extends AnyPlugins = AnyPlugins
> extends TableComponent<Item, Plugins, 'thead.tr.th'> {
label: HeaderLabel<Item>;
colspan: number;
constructor({ id, label, colspan }: HeaderCellInit<Item>) {
colstart: number;
constructor({ id, label, colspan, colstart }: HeaderCellInit<Item>) {
super({ id });
this.label = label;
this.colspan = colspan;
this.colstart = colstart;
}

render(): RenderConfig {
Expand Down Expand Up @@ -68,14 +72,15 @@ export class FlatHeaderCell<Item, Plugins extends AnyPlugins = AnyPlugins> exten
Item,
Plugins
> {
constructor({ id, label }: FlatHeaderCellInit<Item, Plugins>) {
super({ id, label, colspan: 1 });
constructor({ id, label, colstart }: FlatHeaderCellInit<Item, Plugins>) {
super({ id, label, colspan: 1, colstart });
}

clone(): FlatHeaderCell<Item, Plugins> {
return new FlatHeaderCell({
id: this.id,
label: this.label,
colstart: this.colstart,
});
}
}
Expand All @@ -94,8 +99,8 @@ export class DataHeaderCell<Item, Plugins extends AnyPlugins = AnyPlugins> exten
> {
accessorKey?: keyof Item;
accessorFn?: (item: Item) => unknown;
constructor({ id, label, accessorKey, accessorFn }: DataHeaderCellInit<Item, Plugins>) {
super({ id, label });
constructor({ id, label, accessorKey, accessorFn, colstart }: DataHeaderCellInit<Item, Plugins>) {
super({ id, label, colstart });
this.accessorKey = accessorKey;
this.accessorFn = accessorFn;
}
Expand All @@ -106,6 +111,7 @@ export class DataHeaderCell<Item, Plugins extends AnyPlugins = AnyPlugins> exten
label: this.label,
accessorFn: this.accessorFn,
accessorKey: this.accessorKey,
colstart: this.colstart,
});
}
}
Expand All @@ -121,14 +127,15 @@ export class FlatDisplayHeaderCell<
Item,
Plugins extends AnyPlugins = AnyPlugins
> extends FlatHeaderCell<Item, Plugins> {
constructor({ id, label = NBSP }: FlatDisplayHeaderCellInit<Item, Plugins>) {
super({ id, label });
constructor({ id, label = NBSP, colstart }: FlatDisplayHeaderCellInit<Item, Plugins>) {
super({ id, label, colstart });
}

clone(): FlatDisplayHeaderCell<Item, Plugins> {
return new FlatDisplayHeaderCell({
id: this.id,
label: this.label,
colstart: this.colstart,
});
}
}
Expand All @@ -148,8 +155,8 @@ export class GroupHeaderCell<Item, Plugins extends AnyPlugins = AnyPlugins> exte
ids: string[];
allId: string;
allIds: string[];
constructor({ label, colspan, ids, allIds }: GroupHeaderCellInit<Item, Plugins>) {
super({ id: `[${ids.join(',')}]`, label, colspan });
constructor({ label, ids, allIds, colspan, colstart }: GroupHeaderCellInit<Item, Plugins>) {
super({ id: `[${ids.join(',')}]`, label, colspan, colstart });
this.ids = ids;
this.allId = `[${allIds.join(',')}]`;
this.allIds = allIds;
Expand All @@ -168,9 +175,10 @@ export class GroupHeaderCell<Item, Plugins extends AnyPlugins = AnyPlugins> exte
clone(): GroupHeaderCell<Item, Plugins> {
return new GroupHeaderCell({
label: this.label,
colspan: this.colspan,
ids: this.ids,
allIds: this.allIds,
colspan: this.colspan,
colstart: this.colstart,
});
}
}
Expand All @@ -189,19 +197,21 @@ export class GroupDisplayHeaderCell<
> extends GroupHeaderCell<Item, Plugins> {
constructor({
label = NBSP,
colspan = 1,
ids,
allIds,
colspan = 1,
colstart,
}: GroupDisplayHeaderCellInit<Item, Plugins>) {
super({ label, colspan, ids, allIds });
super({ label, ids, allIds, colspan, colstart });
}

clone(): GroupDisplayHeaderCell<Item, Plugins> {
return new GroupDisplayHeaderCell({
label: this.label,
colspan: this.colspan,
ids: this.ids,
allIds: this.allIds,
colspan: this.colspan,
colstart: this.colstart,
});
}
}
Loading

0 comments on commit d5e0040

Please sign in to comment.