Skip to content

SPIKE - Do not merge - Resizable column exploration #2828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,14 @@
"./components/hds/accordion/item/index.js": "./dist/_app_/components/hds/accordion/item/index.js",
"./components/hds/advanced-table/expandable-tr-group.js": "./dist/_app_/components/hds/advanced-table/expandable-tr-group.js",
"./components/hds/advanced-table/index.js": "./dist/_app_/components/hds/advanced-table/index.js",
"./components/hds/advanced-table/models/column.js": "./dist/_app_/components/hds/advanced-table/models/column.js",
"./components/hds/advanced-table/models/row.js": "./dist/_app_/components/hds/advanced-table/models/row.js",
"./components/hds/advanced-table/models/table.js": "./dist/_app_/components/hds/advanced-table/models/table.js",
"./components/hds/advanced-table/td.js": "./dist/_app_/components/hds/advanced-table/td.js",
"./components/hds/advanced-table/th-button-expand.js": "./dist/_app_/components/hds/advanced-table/th-button-expand.js",
"./components/hds/advanced-table/th-button-sort.js": "./dist/_app_/components/hds/advanced-table/th-button-sort.js",
"./components/hds/advanced-table/th-button-tooltip.js": "./dist/_app_/components/hds/advanced-table/th-button-tooltip.js",
"./components/hds/advanced-table/th-resize-handle.js": "./dist/_app_/components/hds/advanced-table/th-resize-handle.js",
"./components/hds/advanced-table/th-selectable.js": "./dist/_app_/components/hds/advanced-table/th-selectable.js",
"./components/hds/advanced-table/th-sort.js": "./dist/_app_/components/hds/advanced-table/th-sort.js",
"./components/hds/advanced-table/th.js": "./dist/_app_/components/hds/advanced-table/th.js",
Expand Down
17 changes: 11 additions & 6 deletions packages/components/src/components/hds/advanced-table/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@
@hasStickyColumn={{@hasStickyFirstColumn}}
@isStickyColumnPinned={{this.isStickyColumnPinned}}
>
{{#each @columns as |column index|}}
{{#each this._tableModel.orderedColumns as |column index|}}
{{#if column.isSortable}}
<Hds::AdvancedTable::ThSort
@sortOrder={{if (eq column.key this._sortBy) this._sortOrder}}
@onClickSort={{fn this.setSortBy column.key}}
@onClickSort={{if column.key (fn this.setSortBy column.key)}}
@align={{column.align}}
@tooltip={{column.tooltip}}
@isStickyColumn={{if (and (eq index 0) @hasStickyFirstColumn) true}}
Expand All @@ -53,6 +53,7 @@
{{else}}
<Hds::AdvancedTable::Th
@align={{column.align}}
@column={{column}}
@tooltip={{column.tooltip}}
@isVisuallyHidden={{column.isVisuallyHidden}}
@isExpandable={{column.isExpandable}}
Expand All @@ -61,6 +62,8 @@
@hasExpandAllButton={{this._tableModel.hasRowsWithChildren}}
@isStickyColumn={{if (and (eq index 0) @hasStickyFirstColumn) true}}
@isStickyColumnPinned={{this.isStickyColumnPinned}}
@onReorderDragStart={{fn (mut this._tableModel.reorderDraggedColumn)}}
@onReorderDrop={{this._tableModel.reorderColumn}}
>
{{column.label}}
</Hds::AdvancedTable::Th>
Expand Down Expand Up @@ -92,6 +95,7 @@
isParentRow=T.isExpandable
depth=T.depth
displayRow=T.shouldDisplayChildRows
data=T.data
)
Th=(component
"hds/advanced-table/th"
Expand All @@ -105,17 +109,16 @@
)
Td=(component "hds/advanced-table/td" align=@align)
data=T.data
columns=@columns
isOpen=T.isExpanded
rowIndex=T.rowIndex
)
to="body"
}}
</Hds::AdvancedTable::ExpandableTrGroup>
{{else}}
{{yield
(hash
Tr=(component
"hds/advanced-table/tr"
{{! @glint-ignore: Temporarily ignore deep type instantiation error }}
{{yield (hash Tr=(component "hds/advanced-table/tr"
selectionScope="row"
isLastRow=(eq this._tableModel.lastVisibleRow.id record.id)
isSelectable=this.isSelectable
Expand All @@ -125,6 +128,7 @@
selectionAriaLabelSuffix=@selectionAriaLabelSuffix
hasStickyColumn=@hasStickyFirstColumn
isStickyColumnPinned=this.isStickyColumnPinned
data=record
)
Th=(component
"hds/advanced-table/th"
Expand All @@ -134,6 +138,7 @@
)
Td=(component "hds/advanced-table/td" align=@align)
data=record
columns=@columns
rowIndex=index
)
to="body"
Expand Down
65 changes: 21 additions & 44 deletions packages/components/src/components/hds/advanced-table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ export interface HdsAdvancedTableSignature {
align?: HdsAdvancedTableHorizontalAlignment;
caption?: string;
columns: HdsAdvancedTableColumn[];
columnOrder?: string[];
density?: HdsAdvancedTableDensities;
identityKey?: string;
isResizable?: boolean;
isSelectable?: boolean;
isStriped?: boolean;
model: HdsAdvancedTableModel;
Expand All @@ -132,13 +134,15 @@ export interface HdsAdvancedTableSignature {
hasStickyHeader?: boolean;
hasStickyFirstColumn?: boolean;
childrenKey?: string;
onReorder?: (columnOrder: string[]) => void;
};
Blocks: {
body?: [
{
Td?: ComponentLike<HdsAdvancedTableTdSignature>;
Tr?: ComponentLike<HdsAdvancedTableTrSignature>;
Th?: ComponentLike<HdsAdvancedTableThSignature>;
columns: HdsAdvancedTableColumn[];
data?: Record<string, unknown>;
rowIndex?: number | string;
isOpen?: HdsAdvancedTableExpandState;
Expand All @@ -158,10 +162,10 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
@tracked private _isSelectAllCheckboxSelected?: boolean = undefined;
private _selectableRows: HdsAdvancedTableSelectableRow[] = [];
private _captionId = 'caption-' + guidFor(this);
private _tableModel!: HdsAdvancedTableTableModel;
private _scrollHandler!: (event: Event) => void;
private _resizeObserver!: ResizeObserver;
private _theadElement!: HTMLDivElement;
private _tableModel: HdsAdvancedTableTableModel;

@tracked scrollIndicatorDimensions = DEFAULT_SCROLL_DIMENSIONS;
@tracked isStickyColumnPinned = false;
Expand All @@ -175,29 +179,17 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
constructor(owner: Owner, args: HdsAdvancedTableSignature['Args']) {
super(owner, args);

const { model, childrenKey, columns, hasStickyFirstColumn } = args;
const { model, childrenKey, columns, columnOrder, hasStickyFirstColumn, isSelectable, onReorder } = this.args;

this._tableModel = new HdsAdvancedTableTableModel({
model,
childrenKey,
columns,
columnOrder,
hasStickyFirstColumn,
isSelectable,
onReorder,
});

if (this._tableModel.hasRowsWithChildren) {
const sortableColumns = columns.filter((column) => column.isSortable);
const sortableColumnLabels = sortableColumns.map(
(column) => column.label
);

assert(
`Cannot have sortable columns if there are nested rows. Sortable columns are ${sortableColumnLabels.toString()}`,
sortableColumns.length === 0
);

assert(
'Cannot have a sticky first column if there are nested rows.',
!hasStickyFirstColumn
);
}
}

get getSortCriteria(): string | HdsAdvancedTableSortingFunction<unknown> {
Expand All @@ -218,24 +210,6 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur
}
}

get columnWidths(): string[] | undefined {
const { columns } = this.args;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const widths: string[] = new Array(columns.length);
let hasCustomColumnWidth = false;

for (let i = 0; i < columns.length; i++) {
const column = columns[i];

if (column?.['width']) {
widths[i] = column.width;
if (!hasCustomColumnWidth) hasCustomColumnWidth = true;
}
}

return hasCustomColumnWidth ? widths : undefined;
}

get identityKey(): string | undefined {
// we have to provide a way for the consumer to pass undefined because Ember tries to interpret undefined as missing an arg and therefore falls back to the default
if (this.args.identityKey === 'none') {
Expand Down Expand Up @@ -326,21 +300,24 @@ export default class HdsAdvancedTable extends Component<HdsAdvancedTableSignatur

// returns the grid-template-columns CSS attribute for the grid
get gridTemplateColumns(): string {
const { isSelectable, columns } = this.args;
const { isSelectable } = this.args;
const { orderedColumns } = this._tableModel;

const DEFAULT_COLUMN_WIDTH = '1fr';

// if there is a select checkbox, the first column has a 'min-content' width to hug the checkbox content
let style = isSelectable ? 'min-content ' : '';

if (!this.columnWidths) {
// if there are no custom column widths, each column is the same width and they take up the available space
style += `repeat(${columns.length}, ${DEFAULT_COLUMN_WIDTH})`;
} else {
const hasCustomColumnWidths = orderedColumns.some(column => column.width !== undefined);

if (hasCustomColumnWidths) {
// check the custom column widths, if the current column has a custom width use the custom width. otherwise take the available space.
for (let i = 0; i < this.columnWidths.length; i++) {
style += ` ${this.columnWidths[i] ? this.columnWidths[i] : DEFAULT_COLUMN_WIDTH}`;
for (let i = 0; i < orderedColumns.length; i++) {
style += ` ${orderedColumns[i]?.width ?? DEFAULT_COLUMN_WIDTH}`;
}
} else {
// if there are no custom column widths, each column is the same width and they take up the available space
style += `repeat(${orderedColumns.length}, ${DEFAULT_COLUMN_WIDTH})`;
}

return style;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { tracked } from '@glimmer/tracking';

import type { HdsAdvancedTableHorizontalAlignment } from "../types";

export default class HdsAdvancedTableColumn {
@tracked label: string = '';

@tracked align?: HdsAdvancedTableHorizontalAlignment = 'left';
@tracked isExpandable?: boolean = false;
@tracked isReorderable?: boolean = false;
@tracked isResizable?: boolean = false;
@tracked isSortable?: boolean = false;
@tracked isVisuallyHidden?: boolean = false;
@tracked key?: string = undefined;
@tracked sortingFunction?: (a: unknown, b: unknown) => number = undefined;
@tracked tooltip?: string = undefined;
@tracked width?: string = undefined;

constructor(args: HdsAdvancedTableColumn) {
this.label = args.label;

this.align = args.align ?? 'left';
this.isExpandable = args.isExpandable ?? false;
this.isReorderable = args.isReorderable ?? false;
this.isResizable = args.isResizable ?? false;
this.isSortable = args.isSortable ?? false;
this.isVisuallyHidden = args.isVisuallyHidden ?? false;
this.key = args.key;
this.sortingFunction = args.sortingFunction;
this.tooltip = args.tooltip;
this.width = args.width;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { guidFor } from '@ember/object/internals';

import type { HdsAdvancedTableColumn, HdsAdvancedTableCell } from '../types';

interface HdsAdvancedTableRowArgs {
[key: string]: unknown;
columns: HdsAdvancedTableColumn[];
id?: string;
childrenKey?: string;
columnOrder?: string[];
}

export default class HdsAdvancedTableRow {
Expand All @@ -20,6 +24,21 @@ export default class HdsAdvancedTableRow {
[key: string]: unknown;

@tracked isOpen: boolean = false;
@tracked cells: HdsAdvancedTableCell[] = [];
@tracked columnOrder: string[] = [];

get orderedCells() {
return this.columnOrder.reduce((acc, key) => {
const cell = this.cells.find((cell) => cell.columnKey === key);

if (cell) {
acc.push(cell);
}

return acc;
}
, [] as HdsAdvancedTableCell[]);
}

children: HdsAdvancedTableRow[] = [];
childrenKey: string;
Expand All @@ -33,6 +52,18 @@ export default class HdsAdvancedTableRow {
}

constructor(args: HdsAdvancedTableRowArgs) {
const { columns } = args;

this.cells = columns.map((column) => {
const cell = args[column.key ?? ''];

return {
columnKey: column.key ?? '',
value: cell,
};
});
this.columnOrder = args.columnOrder ?? this.cells.map((cell) => cell.columnKey);

// set row data
Object.assign(this, args);

Expand All @@ -48,6 +79,15 @@ export default class HdsAdvancedTableRow {
}
}

@action
updateColumnOrder(columnOrder: string[]) {
this.columnOrder = columnOrder;

for (const child of this.children) {
child.updateColumnOrder(columnOrder);
}
}

@action
openAll() {
this.isOpen = true;
Expand Down
Loading
Loading