Skip to content

Commit

Permalink
prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
mollykreis committed Feb 28, 2024
1 parent 1a01a4f commit 6ee6e22
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ export class ColumnInternals<TColumnConfig> {
@observable
public minPixelWidth = defaultMinPixelWidth;

/**
* Whether or not resizing the column has been disabled.
*/
@observable
public resizingDisabled = false;

/**
* @internal Do not write to this value directly. It is used by the Table in order to store
* the resolved value of the fractionalWidth after updates programmatic or interactive updates.
Expand Down
17 changes: 11 additions & 6 deletions packages/nimble-components/src/table-column/icon/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,18 @@ declare global {
* Table column that maps values to icons / spinners
*/
export class TableColumnIcon extends mixinGroupableColumnAPI(
mixinFractionalWidthColumnAPI(
TableColumnEnumBase<
TableColumnEnumColumnConfig,
TableColumnIconValidator
>
)
TableColumnEnumBase<
TableColumnEnumColumnConfig,
TableColumnIconValidator
>
) {
public constructor() {
super();
this.columnInternals.resizingDisabled = true;
this.columnInternals.pixelWidth = 32;
this.columnInternals.minPixelWidth = 0;
}

public override createValidator(): TableColumnIconValidator {
return new TableColumnIconValidator(this.columnInternals);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export class TableHeader extends FoundationElement {
@attr({ attribute: 'first-sorted-column', mode: 'boolean' })
public firstSortedColumn = false;

@attr({ attribute: 'decorations-hidden', mode: 'boolean' })
public decorationsHidden = false;

@observable
public isGrouped = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ export const template = html<TableHeader>`
class="sort-indicator"
title="${x => tableColumnHeaderSortedAscendingLabel.getValueFor(x)}"
aria-hidden="true"
?hidden="${x => x.decorationsHidden}"
></${iconArrowUpTag}>
`)}
${when(x => x.sortDirection === TableColumnSortDirection.descending, html<TableHeader>`
<${iconArrowDownTag}
class="sort-indicator"
title="${x => tableColumnHeaderSortedDescendingLabel.getValueFor(x)}"
aria-hidden="true"
?hidden="${x => x.decorationsHidden}"
></${iconArrowDownTag}>
`)}
${when(x => x.isGrouped, html<TableHeader>`
Expand All @@ -39,6 +41,7 @@ export const template = html<TableHeader>`
title="${x => tableColumnHeaderGroupedLabel.getValueFor(x)}"
role="img"
aria-label="${x => tableColumnHeaderGroupedLabel.getValueFor(x)}"
?hidden="${x => x.decorationsHidden}"
></${iconTwoSquaresInBracketsTag}>
`)}
</template>
Expand Down
89 changes: 71 additions & 18 deletions packages/nimble-components/src/table/models/table-layout-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export class TableLayoutManager<TData extends TableRecord> {
private initialColumnWidths: {
initalColumnFractionalWidth: number,
initialPixelWidth: number,
minPixelWidth: number
minPixelWidth: number,
resizingDisabled: boolean
}[] = [];

public constructor(private readonly table: Table<TData>) {}
Expand Down Expand Up @@ -80,6 +81,14 @@ export class TableLayoutManager<TData extends TableRecord> {
document.addEventListener('mouseup', this.onDividerMouseUp);
}

public hasResizableColumnToLeft(columnIndex: number, visibleColumns = this.visibleColumns): boolean {
return this.getFirstLeftResizableColumnIndex(columnIndex, visibleColumns) !== -1;
}

public hasResizableColumnToRight(columnIndex: number, visibleColumns = this.visibleColumns): boolean {
return this.getFirstRightResizableColumnIndex(columnIndex, visibleColumns) !== -1;
}

private readonly onDividerMouseMove = (event: Event): void => {
const mouseEvent = event as MouseEvent;
for (let i = 0; i < this.visibleColumns.length; i++) {
Expand Down Expand Up @@ -135,27 +144,60 @@ export class TableLayoutManager<TData extends TableRecord> {
let availableSpace = 0;
if (requestedResizeAmount > 0) {
// size right
return requestedResizeAmount;
return this.hasResizableColumnToLeft(this.leftColumnIndex!) ? requestedResizeAmount : 0;
}

// size left
let currentIndex = this.leftColumnIndex!;
while (currentIndex >= 0) {
const columnInitialWidths = this.initialColumnWidths[currentIndex]!;
availableSpace
+= columnInitialWidths.initialPixelWidth
- columnInitialWidths.minPixelWidth;
if (!columnInitialWidths.resizingDisabled) {
availableSpace
+= columnInitialWidths.initialPixelWidth
- columnInitialWidths.minPixelWidth;
}
currentIndex -= 1;
}
return Math.max(requestedResizeAmount, -availableSpace);
}

private getFirstLeftResizableColumnIndex(columnIndex: number, visibleColumns = this.visibleColumns): number {
for (let i = columnIndex; i >= 0; i--) {
const column = visibleColumns[i];
if (!column) {
return -1;
}
if (!column.columnInternals.resizingDisabled) {
return i;
}
}
return -1;
}

private getFirstRightResizableColumnIndex(columnIndex: number, visibleColumns = this.visibleColumns): number {
for (let i = columnIndex; i < visibleColumns.length; i++) {
const column = visibleColumns[i];
if (!column) {
return -1;
}
if (!column.columnInternals.resizingDisabled) {
return i;
}
}
return -1;
}

private performCascadeSizeLeft(
leftColumnIndex: number,
delta: number
): void {
const firstLeftResizableColumn = this.getFirstLeftResizableColumnIndex(leftColumnIndex);
if (firstLeftResizableColumn === -1) {
return;
}

let currentDelta = delta;
const leftColumnInitialWidths = this.initialColumnWidths[leftColumnIndex]!;
const leftColumnInitialWidths = this.initialColumnWidths[firstLeftResizableColumn]!;
const allowedDelta = delta < 0
? Math.max(
leftColumnInitialWidths.minPixelWidth
Expand All @@ -164,39 +206,49 @@ export class TableLayoutManager<TData extends TableRecord> {
)
: delta;
const actualDelta = allowedDelta;
const leftColumn = this.visibleColumns[leftColumnIndex]!;
const leftColumn = this.visibleColumns[firstLeftResizableColumn]!;
leftColumn.columnInternals.currentPixelWidth! += actualDelta;

if (actualDelta > currentDelta && leftColumnIndex > 0 && delta < 0) {
if (actualDelta > currentDelta && firstLeftResizableColumn > 0 && delta < 0) {
currentDelta -= allowedDelta;
this.performCascadeSizeLeft(leftColumnIndex - 1, currentDelta);
this.performCascadeSizeLeft(firstLeftResizableColumn - 1, currentDelta);
}
}

private performCascadeSizeRight(
rightColumnIndex: number,
delta: number
): void {
const firstRightResizableColumn = this.getFirstRightResizableColumnIndex(rightColumnIndex);
if (firstRightResizableColumn === -1) {
return;
}

let currentDelta = delta;
const rightColumnInitialWidths = this.initialColumnWidths[rightColumnIndex]!;
const allowedDelta = delta > 0
? Math.min(
const rightColumnInitialWidths = this.initialColumnWidths[firstRightResizableColumn]!;
let allowedDelta: number;
if (rightColumnInitialWidths.resizingDisabled) {
allowedDelta = 0;
} else if (delta > 0) {
allowedDelta = Math.min(
rightColumnInitialWidths.initialPixelWidth
- rightColumnInitialWidths.minPixelWidth,
currentDelta
)
: delta;
);
} else {
allowedDelta = delta;
}
const actualDelta = allowedDelta;
const rightColumn = this.visibleColumns[rightColumnIndex]!;
const rightColumn = this.visibleColumns[firstRightResizableColumn]!;
rightColumn.columnInternals.currentPixelWidth! -= actualDelta;

if (
actualDelta < currentDelta
&& rightColumnIndex < this.visibleColumns.length - 1
&& firstRightResizableColumn < this.visibleColumns.length - 1
&& delta > 0
) {
currentDelta -= allowedDelta;
this.performCascadeSizeRight(rightColumnIndex + 1, currentDelta);
this.performCascadeSizeRight(firstRightResizableColumn + 1, currentDelta);
}
}

Expand All @@ -216,7 +268,8 @@ export class TableLayoutManager<TData extends TableRecord> {
initalColumnFractionalWidth:
column.columnInternals.currentFractionalWidth,
initialPixelWidth: column.columnInternals.currentPixelWidth!,
minPixelWidth: column.columnInternals.minPixelWidth
minPixelWidth: column.columnInternals.minPixelWidth,
resizingDisabled: column.columnInternals.resizingDisabled
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions packages/nimble-components/src/table/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ export const styles = css`
);
}
.column-divider.active {
.column-divider.active.resizable {
display: block;
z-index: ${ZIndexLevels.zIndex1};
}
.header-container:hover .column-divider.left,
.header-container:hover .column-divider.right {
.header-container:hover .column-divider.left.resizable,
.header-container:hover .column-divider.right.resizable {
display: block;
z-index: ${ZIndexLevels.zIndex1};
}
Expand Down
13 changes: 9 additions & 4 deletions packages/nimble-components/src/table/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,27 @@ export const template = html<Table>`
${repeat(x => x.visibleColumns, html<TableColumn, Table>`
<div class="header-container">
${when((_, c) => c.index > 0, html<TableColumn, Table>`
<div class="column-divider left ${(_, c) => `${c.parent.layoutManager.activeColumnIndex === c.index ? 'active' : ''}`}"
@mousedown="${(_, c) => c.parent.onLeftDividerMouseDown(c.event as MouseEvent, c.index)}">
<div
class="column-divider left ${(_, c) => `${c.parent.layoutManager.activeColumnIndex === c.index ? 'active' : ''}`} ${(_, c) => `${c.parent.layoutManager.hasResizableColumnToLeft(c.index - 1, c.parent.visibleColumns) && c.parent.layoutManager.hasResizableColumnToRight(c.index, c.parent.visibleColumns) ? 'resizable' : 'foo'}`}"
@mousedown="${(_, c) => c.parent.onLeftDividerMouseDown(c.event as MouseEvent, c.index)}"
>
</div>
`)}
<${tableHeaderTag}
class="header"
sort-direction="${x => (typeof x.columnInternals.currentSortIndex === 'number' ? x.columnInternals.currentSortDirection : TableColumnSortDirection.none)}"
?first-sorted-column="${(x, c) => x === c.parent.firstSortedColumn}"
?decorations-hidden="${x => x.columnInternals.resizingDisabled}"
@click="${(x, c) => c.parent.toggleColumnSort(x, (c.event as MouseEvent).shiftKey)}"
:isGrouped=${x => (typeof x.columnInternals.groupIndex === 'number' && !x.columnInternals.groupingDisabled)}
>
<slot name="${x => x.slot}"></slot>
</${tableHeaderTag}>
${when((_, c) => c.index < c.length - 1, html<TableColumn, Table>`
<div class="column-divider right ${(_, c) => `${c.parent.layoutManager.activeColumnIndex === c.index ? 'active' : ''}`}"
@mousedown="${(_, c) => c.parent.onRightDividerMouseDown(c.event as MouseEvent, c.index)}">
<div
class="column-divider right ${(_, c) => `${c.parent.layoutManager.activeColumnIndex === c.index ? 'active' : ''}`} ${(_, c) => `${c.parent.layoutManager.hasResizableColumnToLeft(c.index, c.parent.visibleColumns) && c.parent.layoutManager.hasResizableColumnToRight(c.index + 1, c.parent.visibleColumns) ? 'resizable' : 'foo'}`}"
@mousedown="${(_, c) => c.parent.onRightDividerMouseDown(c.event as MouseEvent, c.index)}"
>
</div>
`)}
</div>
Expand Down

0 comments on commit 6ee6e22

Please sign in to comment.