@trimble-oss/moduswebcomponents
Version:
Modus Web Components is a modern, accessible UI library built with Stencil JS that provides reusable web components following Trimble's Modus design system. This updated version focuses on improved flexibility, enhanced theming options, comprehensive cust
418 lines (415 loc) • 14.4 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
import { action } from "@storybook/addon-actions";
import { html } from "lit";
const meta = {
title: 'Components/Table',
component: 'modus-wc-table',
argTypes: {
columns: {
control: 'object',
description: 'An array of column definitions.',
table: {
type: {
detail: `
Interface: ITableColumn
Properties:
- accessor (string): Key to access data from row object
- cellRenderer? (function): Custom cell renderer (value, row) => string | HTMLElement
- className? (string): Class names for the column
- header (string | HTMLElement): Header content
- id (string): Unique identifier for the column
- width? (string): Width style (e.g., '200px', '50%')
- sortable? (boolean): Whether the column is sortable
- editor? ('text' | 'number' | 'autocomplete' | 'date' | 'custom'): Built-in editor type
- editorProps? (object): Extra props specific to the editor component
- customEditorRenderer? (function): Custom renderer for 'custom' editor
- editorTemplate? (string): Raw HTML string for editor, with \`\${value}\` placeholder
- editorSetup? (function): Runs after the editor element is added to the DOM
`,
},
},
},
data: {
control: 'object',
description: 'An array of data objects.',
table: {
type: {
detail: `
Data should be an array of objects, where each object represents a row and each key matches a column accessor.
Example:
[
{ id: '1', name: 'Alice', email: 'alice@example.com', role: 'Admin' },
{ id: '2', name: 'Bob', email: 'bob@example.com', role: 'User' }
]
- Each property in the object should correspond to a column's accessor value.
- The 'id' property is recommended for row identification and selection.
`,
},
},
},
density: {
control: {
type: 'select',
},
options: ['condensed', 'comfortable', 'relaxed'],
description: 'The density of the table, used to save space or increase readability.',
},
hover: {
control: 'boolean',
description: 'Enable hover effect on table rows.',
defaultValue: true,
},
sortable: {
control: 'boolean',
description: 'Enable sorting functionality for sortable columns.',
defaultValue: true,
},
paginated: {
control: 'boolean',
description: 'Enable pagination for the table.',
defaultValue: false,
},
'show-page-size-selector': {
control: 'boolean',
description: 'Show/hide the page size selector in pagination.',
defaultValue: true,
},
'custom-class': {
control: 'text',
description: 'Custom CSS class to apply to the inner div.',
},
selectable: {
control: {
type: 'select',
},
options: ['none', 'single', 'multi'],
description: "Row selection mode: 'none' for no selection, 'single' for single row, 'multi' for multiple rows.",
defaultValue: 'none',
},
zebra: {
control: 'boolean',
description: 'Zebra striped tables differentiate rows by styling them in an alternating fashion.',
defaultValue: false,
},
'current-page': {
control: 'number',
description: 'The current page number in pagination (1-based index).',
defaultValue: 1,
},
'page-size-options': {
control: 'object',
description: 'Available options for the number of rows per page.',
defaultValue: [5, 10, 15],
},
'selected-row-ids': {
control: 'object',
description: 'Array of selected row IDs. Used for controlled selection state.',
defaultValue: [],
},
editable: {
control: 'boolean',
description: 'Enable cell editing. Either a boolean (all rows) or a predicate per row.',
defaultValue: false,
},
},
};
export default meta;
// Helper functions
const createDemoColumns = () => [
{
id: 'id',
header: 'ID',
accessor: 'id',
width: '60px',
},
{
id: 'name',
header: 'Name',
accessor: 'name',
width: '100px',
},
{
id: 'email',
header: 'Email',
accessor: 'email',
},
{
id: 'role',
header: 'Role',
accessor: 'role',
},
];
const createSortableColumns = () => {
const columns = createDemoColumns();
return columns.map((col) => (Object.assign(Object.assign({}, col), { sortable: true })));
};
const createDemoData = (count = 5) => {
const data = [];
for (let i = 1; i <= count; i++) {
data.push({
id: i.toString(),
name: `User ${i}`,
email: `user${i}@example.com`,
role: i % 2 === 0 ? 'Admin' : 'User',
});
}
return data;
};
export const Default = {
render: (args) => {
const columns = args.columns || createDemoColumns();
const data = args.data || createDemoData();
return html `
<modus-wc-table
.columns=${columns}
.data=${data}
.density=${args.density}
.hover=${args.hover}
.sortable=${args.sortable}
.paginated=${args.paginated}
.showPageSizeSelector=${args['show-page-size-selector']}
.customClass=${args['custom-class']}
.selectable=${args.selectable}
.zebra=${args.zebra}
.currentPage=${args['current-page']}
.pageSizeOptions=${args['page-size-options']}
.selectedRowIds=${args['selected-row-ids']}
.editable=${args.editable}
@rowClick=${action('rowClick')}
@sortChange=${action('sortChange')}
@paginationChange=${action('paginationChange')}
@rowSelectionChange=${action('rowSelectionChange')}
@cellEditStart=${action('cellEditStart')}
@cellEditCommit=${action('cellEditCommit')}
></modus-wc-table>
`;
},
args: {
density: 'comfortable',
hover: false,
sortable: true,
paginated: false,
'show-page-size-selector': true,
'custom-class': '',
selectable: 'none',
zebra: false,
'current-page': 1,
'page-size-options': [5, 10, 15],
'selected-row-ids': [],
editable: false,
},
};
export const Hover = {
render: (args) => {
const columns = args.columns || createDemoColumns();
const data = args.data || createDemoData();
return html `
<modus-wc-table
.columns=${columns}
.data=${data}
.density=${args.density}
.hover=${args.hover}
.sortable=${args.sortable}
.paginated=${args.paginated}
.showPageSizeSelector=${args['show-page-size-selector']}
.customClass=${args['custom-class']}
.selectable=${args.selectable}
.zebra=${args.zebra}
.currentPage=${args['current-page']}
.pageSizeOptions=${args['page-size-options']}
.selectedRowIds=${args['selected-row-ids']}
.editable=${args.editable}
@rowClick=${action('rowClick')}
></modus-wc-table>
`;
},
args: {
density: 'comfortable',
hover: true,
},
};
export const Sorting = {
render: (args) => {
const columns = args.columns || createSortableColumns();
const data = args.data || createDemoData();
return html `
<modus-wc-table
.columns=${columns}
.data=${data}
.density=${args.density}
.hover=${args.hover}
.sortable=${args.sortable}
.paginated=${args.paginated}
.showPageSizeSelector=${args['show-page-size-selector']}
.customClass=${args['custom-class']}
.selectable=${args.selectable}
.zebra=${args.zebra}
.currentPage=${args['current-page']}
.pageSizeOptions=${args['page-size-options']}
.selectedRowIds=${args['selected-row-ids']}
.editable=${args.editable}
@sortChange=${action('sortChange')}
></modus-wc-table>
`;
},
args: {
density: 'comfortable',
sortable: true,
},
};
export const Pagination = {
render: (args) => {
const columns = args.columns || createDemoColumns();
const data = args.data || createDemoData(15);
return html `
<modus-wc-table
.columns=${columns}
.data=${data}
.density=${args.density}
.hover=${args.hover}
.sortable=${args.sortable}
.paginated=${args.paginated}
.showPageSizeSelector=${args['show-page-size-selector']}
.customClass=${args['custom-class']}
.selectable=${args.selectable}
.zebra=${args.zebra}
.currentPage=${args['current-page']}
.pageSizeOptions=${args['page-size-options']}
.selectedRowIds=${args['selected-row-ids']}
.editable=${args.editable}
@paginationChange=${action('paginationChange')}
></modus-wc-table>
`;
},
args: {
density: 'comfortable',
paginated: true,
'show-page-size-selector': true,
},
};
export const CheckBoxRowSelection = {
render: (args) => {
const columns = args.columns || createDemoColumns();
const data = args.data || createDemoData();
return html `
<modus-wc-table
.columns=${columns}
.data=${data}
.density=${args.density}
.hover=${args.hover}
.sortable=${args.sortable}
.paginated=${args.paginated}
.showPageSizeSelector=${args['show-page-size-selector']}
.customClass=${args['custom-class']}
.selectable=${args.selectable}
.zebra=${args.zebra}
.currentPage=${args['current-page']}
.pageSizeOptions=${args['page-size-options']}
.selectedRowIds=${args['selected-row-ids']}
.editable=${args.editable}
@rowSelectionChange=${action('rowSelectionChange')}
></modus-wc-table>
`;
},
args: {
density: 'comfortable',
selectable: 'multi',
},
};
export const InlineEditing = {
render: (args) => {
const columns = [
{
id: 'id',
header: 'ID',
accessor: 'id',
width: '20px',
},
{
id: 'name',
header: 'Name',
accessor: 'name',
editor: 'text',
},
{
id: 'status',
header: 'Status',
accessor: 'status',
editor: 'custom',
customEditorRenderer: (value, onCommit) => {
const container = document.createElement('div');
container.style.width = '100%';
const autocomplete = document.createElement('modus-wc-autocomplete');
autocomplete.items = [
{ label: 'Active', value: 'Active', visibleInMenu: true },
{ label: 'Inactive', value: 'Inactive', visibleInMenu: true },
{ label: 'Pending', value: 'Pending', visibleInMenu: true },
];
autocomplete.value = value;
autocomplete.style.width = '100%';
const handleItemSelect = (e) => {
onCommit(e.detail.value);
};
autocomplete.addEventListener('itemSelect', handleItemSelect);
container.appendChild(autocomplete);
setTimeout(() => {
const input = autocomplete.querySelector('input');
input === null || input === void 0 ? void 0 : input.focus();
}, 0);
return container;
},
cellRenderer: (value) => {
const statusColors = {
Active: 'green',
Inactive: 'gray',
Pending: 'blue',
};
const color = statusColors[value] || 'black';
const span = document.createElement('span');
span.textContent = value;
span.style.color = color;
span.style.fontWeight = 'bold';
return span;
},
},
];
const data = [
{ id: '1', name: 'John Doe', status: 'Active' },
{ id: '2', name: 'Jane Smith', status: 'Inactive' },
{ id: '3', name: 'Bob Johnson', status: 'Pending' },
];
return html `
<modus-wc-table
.columns=${columns}
.data=${data}
.density=${args.density}
.hover=${args.hover}
.sortable=${args.sortable}
.paginated=${args.paginated}
.showPageSizeSelector=${args['show-page-size-selector']}
.customClass=${args['custom-class']}
.selectable=${args.selectable}
.zebra=${args.zebra}
.currentPage=${args['current-page']}
.pageSizeOptions=${args['page-size-options']}
.selectedRowIds=${args['selected-row-ids']}
.editable=${true}
@cellEditStart=${action('cellEditStart')}
@cellEditCommit=${action('cellEditCommit')}
></modus-wc-table>
`;
},
args: {
density: 'comfortable',
hover: true,
sortable: true,
paginated: false,
'show-page-size-selector': true,
'custom-class': '',
selectable: 'none',
zebra: false,
'current-page': 1,
'page-size-options': [5, 10, 15],
'selected-row-ids': [],
},
};