Skip to content

Commit

Permalink
[duoyun-ui] <dy-table> support auto visible width
Browse files Browse the repository at this point in the history
  • Loading branch information
mantou132 committed Mar 24, 2024
1 parent 0548c03 commit a0ca34a
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 100 deletions.
2 changes: 1 addition & 1 deletion packages/duoyun-ui/src/elements/contextmenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type MenuOptions = {
searchable?: boolean;
};
type MenuObject = MenuOptions & { menu: Menu };
type MenuOrMenuObject = Menu | MenuObject;
export type MenuOrMenuObject = Menu | MenuObject;

export interface ContextMenuItem {
text: string | TemplateResult;
Expand Down
175 changes: 100 additions & 75 deletions packages/duoyun-ui/src/elements/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { icons } from '../lib/icons';
import { commonHandle } from '../lib/hotkeys';
import { focusStyle } from '../lib/styles';

import { ContextMenuItem, ContextMenu } from './contextmenu';
import { ContextMenu, MenuOrMenuObject } from './contextmenu';
import { DuoyunScrollBoxElement } from './scroll-box';
import type { SelectionChange } from './selection-box';

Expand Down Expand Up @@ -136,7 +136,6 @@ export type Column<T> = {
tooltip?: string;
dataIndex?: keyof T | string[];
render?: (record: T) => string | TemplateResult;
getActions?: (record: T, evt: HTMLElement) => ContextMenuItem[];
getColSpan?: (record: T, arr: T[]) => number;
getRowSpan?: (record: T, arr: T[]) => number;
data?: Record<string, unknown>;
Expand Down Expand Up @@ -183,6 +182,7 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
@property rowKey?: string | string[];
@property getKey?: (record: T) => K;
@property expandedRowRender?: (record: T) => undefined | string | TemplateResult;
@property getActions?: (record: T, activeElement: HTMLElement) => MenuOrMenuObject;
@emitter expand: Emitter<T>;

#selectionSet = new Set<K>();
Expand Down Expand Up @@ -245,12 +245,9 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
});
};

#openActions = (evt: PointerEvent, menu: ContextMenuItem[]) => {
ContextMenu.open(menu, {
activeElement: evt.target as HTMLElement,
searchable: menu.length > 20,
maxHeight: '30em',
});
#openActions = (evt: PointerEvent, record: T) => {
const activeElement = evt.target as HTMLElement;
ContextMenu.open(this.getActions!(record, activeElement), { activeElement });
};

#shouldRenderTd = (spanMemo: number[], index: number) => {
Expand Down Expand Up @@ -297,10 +294,94 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
`,
};

#actionsColumn: Column<T> = {
title: '',
width: this.#iconColWidth,
render: (record) => html`
<dy-use
class="action"
tabindex="0"
role="button"
aria-label="Actions"
.element=${icons.more}
@keydown=${commonHandle}
@click=${(evt: PointerEvent) => this.#openActions(evt, record)}
></dy-use>
`,
};

#getDefaultStyle = (width?: string): StyleObject => {
return width?.startsWith('0') ? { fontSize: '0' } : {};
};

#columns?: Column<T>[];
#sidePart?: TemplateResult;
#headerPart?: TemplateResult;
willMount = () => {
this.memo(
() => {
this.#columns = this.expandedRowRender && this.columns ? [this.#expandedColumn, ...this.columns] : this.columns;
if (!this.#columns) return;
if (this.getActions) this.#columns.push(this.#actionsColumn);

this.#headerPart = html`
<colgroup>
${this.#columns.map(({ width = 'auto' }) => html`<col style=${styleMap({ width })} /> `)}
</colgroup>
${this.headless
? ''
: html`
<thead>
<tr>
${this.#columns.map(
({ title = '', width, style = this.#getDefaultStyle(width), tooltip }) => html`
<th part=${DuoyunTableElement.th} style=${styleMap(style)}>
<dy-space size="small">
${title}
${tooltip
? html`
<dy-tooltip .content=${tooltip}>
<dy-use class="tooltip" .element=${icons.help}></dy-use>
</dy-tooltip>
`
: ''}
</dy-space>
</th>
`,
)}
</tr>
</thead>
`}
`;

let sum = this.#columns
.filter(({ visibleWidth }) => visibleWidth !== 'auto')
.map(({ width }) => width || '15em')
.join(' + ');

this.#sidePart = html`
${this.#columns.map(({ visibleWidth, width }, index) => {
if (!visibleWidth) return '';
sum = `${sum} + ${width}`;
// `visibility: collapse;` 不完美
return html`
<style>
@container (width <= ${visibleWidth === 'auto' ? `calc(${sum})` : visibleWidth}) {
:where(th, td, col):nth-of-type(${index + 1}) {
width: 0 !important;
font-size: 0;
}
}
</style>
`;
})}
`;
},
() => [this.columns, this.headless, this.getActions, this.expandedRowRender],
);
};

mounted = () => {
this.memo(
() => {
Expand All @@ -311,28 +392,11 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
};

render = () => {
if (!this.columns) return html``;
const columns = this.expandedRowRender ? [this.#expandedColumn, ...this.columns] : this.columns;
const columns = this.#columns;
if (!columns) return html``;

const rowSpanMemo = columns.map(() => 0);
return html`
${this.selectable
? html`<dy-selection-box class="selection" @change=${this.#onSelectionBoxChange}></dy-selection-box>`
: ''}
${columns.map(({ visibleWidth }, index) =>
// `visibility: collapse;` 不完美
visibleWidth
? html`
<style>
@container (width <= ${visibleWidth}) {
:where(th, td, col):nth-of-type(${index + 1}) {
width: 0 !important;
font-size: 0;
}
}
</style>
`
: '',
)}
<table part=${DuoyunTableElement.table}>
${this.caption
? html`
Expand All @@ -341,36 +405,7 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
</caption>
`
: ''}
<colgroup>
${columns.map(
({ width = 'auto', getActions }) =>
html`<col style=${styleMap({ width: getActions ? this.#iconColWidth : width })} /> `,
)}
</colgroup>
${this.headless
? ''
: html`
<thead>
<tr>
${columns.map(
({ title = '', width, style = this.#getDefaultStyle(width), tooltip }) => html`
<th part=${DuoyunTableElement.th} style=${styleMap(style)}>
<dy-space size="small">
${title}
${tooltip
? html`
<dy-tooltip .content=${tooltip}>
<dy-use class="tooltip" .element=${icons.help}></dy-use>
</dy-tooltip>
`
: ''}
</dy-space>
</th>
`,
)}
</tr>
</thead>
`}
${this.#headerPart}
<tbody>
${this.data?.map(
(record, _rowIndex, _data, colSpanMemo = [0]) => html`
Expand All @@ -386,7 +421,6 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
{
dataIndex,
render,
getActions,
width,
style = this.#getDefaultStyle(width),
getRowSpan,
Expand Down Expand Up @@ -417,22 +451,9 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
? html`<dy-placeholder ?center=${style.textAlign === 'center'}></dy-placeholder>`
: render
? render(record)
: getActions
? html`
<dy-use
class="action"
tabindex="0"
role="button"
aria-label="Actions"
.element=${icons.more}
@keydown=${commonHandle}
@click=${(evt: PointerEvent) =>
this.#openActions(evt, getActions(record, evt.target as HTMLElement))}
></dy-use>
`
: dataIndex
? readProp(record, dataIndex)
: ''}
: dataIndex
? readProp(record, dataIndex)
: ''}
</td>
`
: '',
Expand All @@ -451,6 +472,10 @@ export class DuoyunTableElement<T = any, K = any> extends DuoyunScrollBoxElement
)}
</tbody>
</table>
${this.#sidePart}
${this.selectable
? html`<dy-selection-box class="selection" @change=${this.#onSelectionBoxChange}></dy-selection-box>`
: ''}
${!this.data
? html`<div class="side" part=${DuoyunTableElement.side}><dy-loading></dy-loading></div>`
: this.data.length === 0
Expand Down
8 changes: 5 additions & 3 deletions packages/duoyun-ui/src/patterns/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,11 @@ export class DyPatTableElement<T = any> extends GemElement<State> {
// 如果不在 dy-pat-console 中,则需要提供 `locationStore`
@property locationStore?: LocationStore;

@property rowKey?: string | string[];
@property getRowStyle?: (record: T) => Partial<CSSStyleDeclaration>;
@property rowKey?: DuoyunTableElement['rowKey'];
@property getRowStyle?: DuoyunTableElement['getRowStyle'];
@property expandedRowRender?: DuoyunTableElement['expandedRowRender'];
@property getActions?: DuoyunTableElement['getActions'];
@property getSelectedActions?: (selections: any[]) => ContextMenuItem[];
@property expandedRowRender?: (record: T) => undefined | string | TemplateResult;

@emitter expand: Emitter<T>;

Expand Down Expand Up @@ -689,6 +690,7 @@ export class DyPatTableElement<T = any> extends GemElement<State> {
part="table-wrap"
exportparts="table,tr,td,th"
.getRowStyle=${this.getRowStyle}
.getActions=${this.getActions}
.expandedRowRender=${this.expandedRowRender}
.data=${data}
.columns=${this.#columns}
Expand Down
8 changes: 7 additions & 1 deletion packages/gem-examples/src/console/item-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ export class ConsolePageItemClientElement extends ConsolePageItemElement {
}
render = () => {
return html`
<dy-pat-table filterable .columns=${this.columns} .pagesize=${5} .data=${store.getData()}>
<dy-pat-table
filterable
.getActions=${this.getActions}
.columns=${this.columns}
.pagesize=${5}
.data=${store.getData()}
>
<dy-button @click=${this.onCreate}>Add</dy-button>
</dy-pat-table>
Expand Down
39 changes: 19 additions & 20 deletions packages/gem-examples/src/console/item.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { html, GemElement } from '@mantou/gem/lib/element';
import { customElement } from '@mantou/gem/lib/decorators';
import { Time } from 'duoyun-ui/lib/time';
import { ContextMenu } from 'duoyun-ui/elements/contextmenu';
import { ContextMenu, ContextMenuItem } from 'duoyun-ui/elements/contextmenu';
import { FormItem, createForm } from 'duoyun-ui/patterns/form';
import { sleep } from 'duoyun-ui/lib/timer';
import { createPaginationStore } from 'duoyun-ui/helper/store';
Expand Down Expand Up @@ -72,12 +72,12 @@ export class ConsolePageItemElement extends GemElement {
title: 'Address',
dataIndex: ['address', 'street'],
width: '15em',
visibleWidth: '58em',
visibleWidth: 'auto',
},
{
title: 'Company',
width: '10em',
visibleWidth: '68em',
visibleWidth: 'auto',
render: (r) => r.company.name,
filterOptions: {
field: ['company', 'name'],
Expand All @@ -101,30 +101,28 @@ export class ConsolePageItemElement extends GemElement {
{
title: 'Updated',
width: '8em',
visibleWidth: '76em',
visibleWidth: 'auto',
render: (r) => new Time().relativeTimeFormat(new Time(r.updated)),
filterOptions: {
field: 'updated',
type: 'date-time',
},
},
];

getActions = (r: Item, activeElement: HTMLElement): ContextMenuItem[] => [
{
title: '',
getActions: (r, activeElement) => [
{
text: 'Edit',
handle: () => this.onUpdate(r),
},
{ text: '---' },
{
text: 'Delete',
danger: true,
handle: async () => {
await ContextMenu.confirm(`Confirm delete ${r.username}?`, { activeElement, danger: true });
console.log('Delete: ', r);
},
},
],
text: 'Edit',
handle: () => this.onUpdate(r),
},
{ text: '---' },
{
text: 'Delete',
danger: true,
handle: async () => {
await ContextMenu.confirm(`Confirm delete ${r.username}?`, { activeElement, danger: true });
console.log('Delete: ', r);
},
},
];

Expand Down Expand Up @@ -249,6 +247,7 @@ export class ConsolePageItemElement extends GemElement {
filterable
.columns=${this.columns}
.paginationStore=${this.state.pagination.store}
.getActions=${this.getActions}
@fetch=${this.#onFetch}
>
<dy-button @click=${this.onCreate}>Add</dy-button>
Expand Down

0 comments on commit a0ca34a

Please sign in to comment.