@nest-ui/table
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -13,2 +13,10 @@ # CHANGELOG | ||
<!-- Start of Current Changelog --> | ||
## 1.0.1 `2023-09-05` | ||
### General Changes | ||
#### Table | ||
- :star2: Optimized internal scripts & reorganized several files [#225](https://github.com/tokopedia/nest/pull/225) | ||
Milestone: https://github.com/tokopedia/nest/milestone/42?closed=1 | ||
<!-- End of Current Changelog --> | ||
## 1.0.0 `2023-05-11` | ||
@@ -18,3 +26,2 @@ ### Stable Release | ||
- :rocket: Nest Table | ||
<!-- End of Current Changelog --> | ||
@@ -21,0 +28,0 @@ ## 0.0.5 `2023-04-06` |
declare type ResponsiveValue = Array<number | string | undefined>; | ||
export interface TableTheme { | ||
'table-borderColor'?: string; | ||
'table-color'?: string; | ||
'table-fontSize'?: ResponsiveValue; | ||
'table-lineHeight'?: ResponsiveValue; | ||
'table>head-background'?: string; | ||
'table>head-color'?: string; | ||
'table>row-background'?: string; | ||
'table>row:hover-background'?: string; | ||
'table>cell-padding'?: ResponsiveValue; | ||
'table>expand-background'?: string; | ||
[key: string]: unknown; | ||
'table-borderColor'?: string; | ||
'table-color'?: string; | ||
'table-fontSize'?: ResponsiveValue; | ||
'table-lineHeight'?: ResponsiveValue; | ||
'table>head-background'?: string; | ||
'table>head-color'?: string; | ||
'table>row-background'?: string; | ||
'table>row:hover-background'?: string; | ||
'table>cell-padding'?: ResponsiveValue; | ||
'table>expand-background'?: string; | ||
[key: string]: unknown; | ||
} | ||
export {}; |
@@ -1,160 +0,204 @@ | ||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "@emotion/react/jsx-runtime"; | ||
import { useEffect, useRef, Fragment, memo, forwardRef } from "react"; | ||
import { calcColSpan, calcMaxRow, initStickyCell } from "./utils"; | ||
import { cssTable, cssWrapper } from "./style"; | ||
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from '@emotion/react/jsx-runtime'; | ||
import { useEffect, useRef, Fragment, memo, forwardRef } from 'react'; | ||
import { calcColSpan, calcMaxRow, initStickyCell } from './utils'; | ||
import { cssTable, cssWrapper } from './style'; | ||
// recursive to render column children from column group | ||
const renderColGroup = (columns)=>/*#__PURE__*/ _jsx(_Fragment, { | ||
children: columns.map((column)=>{ | ||
if (column.children) return /*#__PURE__*/ _jsx(Fragment, { | ||
children: renderColGroup(column.children) | ||
}, column.key); | ||
return /*#__PURE__*/ _jsx("col", { | ||
style: { | ||
width: column.width | ||
} | ||
}, column.key); | ||
}) | ||
}); | ||
const renderColGroup = columns => | ||
/*#__PURE__*/ _jsx(_Fragment, { | ||
children: columns.map(column => { | ||
if (column.children) | ||
return /*#__PURE__*/ _jsx( | ||
Fragment, | ||
{ | ||
children: renderColGroup(column.children), | ||
}, | ||
column.key, | ||
); | ||
return /*#__PURE__*/ _jsx( | ||
'col', | ||
{ | ||
style: { | ||
width: column.width, | ||
}, | ||
}, | ||
column.key, | ||
); | ||
}), | ||
}); | ||
// recursive to render headerRow for column group | ||
const renderHeader = (columns, headerRowProps, maxRow = 0, row = 0)=>{ | ||
const currMaxRow = maxRow || calcMaxRow(columns); | ||
const nextRowArr = []; | ||
return /*#__PURE__*/ _jsxs(Fragment, { | ||
children: [ | ||
/*#__PURE__*/ _jsx("tr", { | ||
...headerRowProps ? headerRowProps(columns, row) : {}, | ||
children: columns.map((column)=>{ | ||
let align = column.align; | ||
if (column.children) { | ||
nextRowArr.push(...column.children); | ||
align = align || 'center'; | ||
} | ||
return /*#__PURE__*/ _jsx("th", { | ||
colSpan: calcColSpan(column), | ||
"data-n-align": align, | ||
"data-n-sticky": column.sticky || undefined, | ||
rowSpan: column.children ? 1 : currMaxRow - row, | ||
...column.headerCellProps, | ||
children: column.title | ||
}, column.key); | ||
}) | ||
}), | ||
nextRowArr.length > 0 && renderHeader(nextRowArr, headerRowProps, currMaxRow, row + 1) | ||
] | ||
}); | ||
const renderHeader = (columns, headerRowProps, maxRow = 0, row = 0) => { | ||
const currMaxRow = maxRow || calcMaxRow(columns); | ||
const nextRowArr = []; | ||
return /*#__PURE__*/ _jsxs(Fragment, { | ||
children: [ | ||
/*#__PURE__*/ _jsx('tr', { | ||
...(headerRowProps ? headerRowProps(columns, row) : {}), | ||
children: columns.map(column => { | ||
let align = column.align; | ||
if (column.children) { | ||
nextRowArr.push(...column.children); | ||
align = align || 'center'; | ||
} | ||
return /*#__PURE__*/ _jsx( | ||
'th', | ||
{ | ||
colSpan: calcColSpan(column), | ||
'data-n-align': align, | ||
'data-n-sticky': column.sticky || undefined, | ||
rowSpan: column.children ? 1 : currMaxRow - row, | ||
...column.headerCellProps, | ||
children: column.title, | ||
}, | ||
column.key, | ||
); | ||
}), | ||
}), | ||
nextRowArr.length > 0 && renderHeader(nextRowArr, headerRowProps, currMaxRow, row + 1), | ||
], | ||
}); | ||
}; | ||
// recursive to render column children from column group | ||
const renderColumns = (columns, rowData, rowIdx, treeLevel)=>/*#__PURE__*/ _jsx(_Fragment, { | ||
children: columns.map((column)=>{ | ||
const { cellProps , children , dataKey , key , render , treeIndent } = column; | ||
if (children) return /*#__PURE__*/ _jsx(Fragment, { | ||
children: renderColumns(children, rowData, rowIdx, treeLevel) | ||
}, key); | ||
return /*#__PURE__*/ _jsxs("td", { | ||
"data-n-align": column.align || undefined, | ||
"data-n-sticky": column.sticky || undefined, | ||
...cellProps ? cellProps(rowData, rowIdx) : {}, | ||
children: [ | ||
Boolean(treeLevel) && treeIndent && /*#__PURE__*/ _jsx("span", { | ||
style: { | ||
paddingLeft: `${treeLevel * treeIndent}px` | ||
} | ||
}), | ||
render ? render(rowData[dataKey || key], rowData) : `${rowData[dataKey || key]}` | ||
] | ||
}, key); | ||
}) | ||
}); | ||
const renderColumns = (columns, rowData, rowIdx, treeLevel) => | ||
/*#__PURE__*/ _jsx(_Fragment, { | ||
children: columns.map(column => { | ||
const { cellProps, children, dataKey, key, render, treeIndent } = column; | ||
if (children) | ||
return /*#__PURE__*/ _jsx( | ||
Fragment, | ||
{ | ||
children: renderColumns(children, rowData, rowIdx, treeLevel), | ||
}, | ||
key, | ||
); | ||
return /*#__PURE__*/ _jsxs( | ||
'td', | ||
{ | ||
'data-n-align': column.align || undefined, | ||
'data-n-sticky': column.sticky || undefined, | ||
...(cellProps ? cellProps(rowData, rowIdx) : {}), | ||
children: [ | ||
Boolean(treeLevel) && | ||
treeIndent && | ||
/*#__PURE__*/ _jsx('span', { | ||
style: { | ||
paddingLeft: `${treeLevel * treeIndent}px`, | ||
}, | ||
}), | ||
render ? render(rowData[dataKey || key], rowData) : `${rowData[dataKey || key]}`, | ||
], | ||
}, | ||
key, | ||
); | ||
}), | ||
}); | ||
// recursive to render row children for data tree | ||
const renderRow = ({ columns , columnsLength =0 , data , dataTree , expandable , rowKey , rowProps , treeLevel =0 })=>{ | ||
const currColumnsLength = columnsLength || columns.reduce((prev, column)=>calcColSpan(column, prev), 0); | ||
return /*#__PURE__*/ _jsx(_Fragment, { | ||
children: data.map((rowData, idx)=>{ | ||
let expandableJsx; | ||
if (expandable && (expandable.expanded ? expandable.expanded(rowData, idx) : true)) { | ||
expandableJsx = expandable.render(rowData, idx); | ||
expandableJsx = expandableJsx && /*#__PURE__*/ _jsxs("tr", { | ||
"data-n-expand": true, | ||
...expandable.rowProps ? expandable.rowProps(rowData, idx) : {}, | ||
children: [ | ||
expandable.startAfterCol && /*#__PURE__*/ _jsx("td", { | ||
colSpan: expandable.startAfterCol | ||
}), | ||
/*#__PURE__*/ _jsx("td", { | ||
colSpan: currColumnsLength - (expandable.startAfterCol || 0), | ||
...expandable.cellProps ? expandable.cellProps(rowData, idx) : {}, | ||
children: expandableJsx | ||
}) | ||
] | ||
}); | ||
} | ||
return /*#__PURE__*/ _jsxs(Fragment, { | ||
children: [ | ||
/*#__PURE__*/ _jsx("tr", { | ||
...rowProps ? rowProps(rowData, idx) : {}, | ||
children: renderColumns(columns, rowData, idx, treeLevel) | ||
}), | ||
expandableJsx, | ||
dataTree && (dataTree.expanded ? dataTree.expanded(rowData, idx) : true) && renderRow({ | ||
columns, | ||
columnsLength: currColumnsLength, | ||
data: rowData[dataTree.childKey] || [], | ||
dataTree, | ||
expandable, | ||
rowKey, | ||
rowProps, | ||
treeLevel: treeLevel + 1 | ||
}) | ||
] | ||
}, rowData[rowKey]); | ||
}) | ||
}); | ||
const renderRow = ({ columns, columnsLength = 0, data, dataTree, expandable, rowKey, rowProps, treeLevel = 0 }) => { | ||
const currColumnsLength = columnsLength || columns.reduce((prev, column) => calcColSpan(column, prev), 0); | ||
return /*#__PURE__*/ _jsx(_Fragment, { | ||
children: data.map((rowData, idx) => { | ||
let expandableJsx; | ||
if (expandable && (expandable.expanded ? expandable.expanded(rowData, idx) : true)) { | ||
expandableJsx = expandable.render(rowData, idx); | ||
expandableJsx = | ||
expandableJsx && | ||
/*#__PURE__*/ _jsxs('tr', { | ||
'data-n-expand': true, | ||
...(expandable.rowProps ? expandable.rowProps(rowData, idx) : {}), | ||
children: [ | ||
expandable.startAfterCol && | ||
/*#__PURE__*/ _jsx('td', { | ||
colSpan: expandable.startAfterCol, | ||
}), | ||
/*#__PURE__*/ _jsx('td', { | ||
colSpan: currColumnsLength - (expandable.startAfterCol || 0), | ||
...(expandable.cellProps ? expandable.cellProps(rowData, idx) : {}), | ||
children: expandableJsx, | ||
}), | ||
], | ||
}); | ||
} | ||
return /*#__PURE__*/ _jsxs( | ||
Fragment, | ||
{ | ||
children: [ | ||
/*#__PURE__*/ _jsx('tr', { | ||
...(rowProps ? rowProps(rowData, idx) : {}), | ||
children: renderColumns(columns, rowData, idx, treeLevel), | ||
}), | ||
expandableJsx, | ||
dataTree && | ||
(dataTree.expanded ? dataTree.expanded(rowData, idx) : true) && | ||
renderRow({ | ||
columns, | ||
columnsLength: currColumnsLength, | ||
data: rowData[dataTree.childKey] || [], | ||
dataTree, | ||
expandable, | ||
rowKey, | ||
rowProps, | ||
treeLevel: treeLevel + 1, | ||
}), | ||
], | ||
}, | ||
rowData[rowKey], | ||
); | ||
}), | ||
}); | ||
}; | ||
const _Table = /*#__PURE__*/ forwardRef((props, ref)=>{ | ||
const { bordered =false , columns =[] , data =[] , dataTree , expandable , headerRowProps , rowKey ='key' , rowProps , scrollArea ={} , sticky , tableProps , ...restProps } = props; | ||
const table = useRef(null); | ||
useEffect(()=>{ | ||
const tableDOM = table.current; | ||
if (tableDOM) { | ||
const stickyCell = initStickyCell(tableDOM); | ||
return stickyCell.destroy; | ||
} | ||
return; | ||
const _Table = /*#__PURE__*/ forwardRef((props, ref) => { | ||
const { | ||
bordered = false, | ||
columns = [], | ||
data = [], | ||
dataTree, | ||
expandable, | ||
headerRowProps, | ||
rowKey = 'key', | ||
rowProps, | ||
scrollArea = {}, | ||
sticky, | ||
tableProps, | ||
...restProps | ||
} = props; | ||
const table = useRef(null); | ||
useEffect(() => { | ||
const tableDOM = table.current; | ||
if (tableDOM) { | ||
const stickyCell = initStickyCell(tableDOM); | ||
return stickyCell.destroy; | ||
} | ||
return; | ||
// reinitiate when table config updates | ||
}, [ | ||
data, | ||
columns, | ||
scrollArea | ||
]); | ||
return /*#__PURE__*/ _jsx("div", { | ||
ref: ref, | ||
css: cssWrapper(scrollArea, bordered), | ||
...restProps, | ||
children: /*#__PURE__*/ _jsxs("table", { | ||
ref: table, | ||
css: cssTable(scrollArea, bordered), | ||
...tableProps, | ||
children: [ | ||
/*#__PURE__*/ _jsx("colgroup", { | ||
children: renderColGroup(columns) | ||
}), | ||
/*#__PURE__*/ _jsx("thead", { | ||
"data-n-sticky": sticky ? '' : undefined, | ||
children: renderHeader(columns, headerRowProps) | ||
}), | ||
/*#__PURE__*/ _jsx("tbody", { | ||
children: renderRow({ | ||
data, | ||
columns, | ||
rowKey, | ||
rowProps, | ||
expandable, | ||
dataTree | ||
}) | ||
}) | ||
] | ||
}) | ||
}); | ||
}, [data, columns, scrollArea]); | ||
return /*#__PURE__*/ _jsx('div', { | ||
ref: ref, | ||
css: cssWrapper(scrollArea, bordered), | ||
...restProps, | ||
children: /*#__PURE__*/ _jsxs('table', { | ||
ref: table, | ||
css: cssTable(scrollArea, bordered), | ||
...tableProps, | ||
children: [ | ||
/*#__PURE__*/ _jsx('colgroup', { | ||
children: renderColGroup(columns), | ||
}), | ||
/*#__PURE__*/ _jsx('thead', { | ||
'data-n-sticky': sticky ? '' : undefined, | ||
children: renderHeader(columns, headerRowProps), | ||
}), | ||
/*#__PURE__*/ _jsx('tbody', { | ||
children: renderRow({ | ||
data, | ||
columns, | ||
rowKey, | ||
rowProps, | ||
expandable, | ||
dataTree, | ||
}), | ||
}), | ||
], | ||
}), | ||
}); | ||
}); | ||
const Table = /*#__PURE__*/ memo(_Table); | ||
export default Table; |
import type { Theme } from '@emotion/react'; | ||
import type { TableScrollArea } from './type'; | ||
export declare const cssWrapper: (scrollArea: TableScrollArea, bordered: boolean) => (theme: Theme) => import("@emotion/react").SerializedStyles; | ||
export declare const cssTable: (scrollArea: TableScrollArea, bordered: boolean) => (theme: Theme) => import("@emotion/react").SerializedStyles; | ||
export declare const cssWrapper: ( | ||
scrollArea: TableScrollArea, | ||
bordered: boolean, | ||
) => (theme: Theme) => import('@emotion/react').SerializedStyles; | ||
export declare const cssTable: ( | ||
scrollArea: TableScrollArea, | ||
bordered: boolean, | ||
) => (theme: Theme) => import('@emotion/react').SerializedStyles; |
@@ -1,103 +0,102 @@ | ||
import { css } from "@emotion/react"; | ||
import { cssScreen, cssHover } from "@nest-ui/core"; | ||
export const cssWrapper = (scrollArea, bordered)=>(theme)=>{ | ||
const borderColor = theme['table-borderColor'] || '#E4EBF5'; | ||
return css({ | ||
overflow: 'auto', | ||
maxHeight: scrollArea.y, | ||
borderInlineStart: bordered ? `1px solid ${borderColor}` : undefined | ||
}); | ||
}; | ||
export const cssTable = (scrollArea, bordered)=>(theme)=>{ | ||
const breakpoints = theme['base-breakpoints'] || [ | ||
0 | ||
]; | ||
const fontSize = theme['table-fontSize'] || []; | ||
const lineHeight = theme['table-lineHeight'] || []; | ||
const cellPadding = theme['table>cell-padding'] || [ | ||
16 | ||
]; | ||
const borderColor = theme['table-borderColor'] || '#E4EBF5'; | ||
const background = theme['table>row-background'] || '#fff'; | ||
const backgroundHover = theme['table>row:hover-background']; | ||
const expandBackground = theme['table>expand-background']; | ||
const headBackground = theme['table>head-background']; | ||
const headFontColor = theme['table>head-color'] || '#212121'; | ||
const fontColor = theme['table-color']; | ||
return css({ | ||
color: fontColor, | ||
width: scrollArea.x, | ||
minWidth: '100%', | ||
position: 'relative', | ||
borderCollapse: 'separate', | ||
borderSpacing: 0, | ||
'>thead, >tbody': { | ||
'>tr': { | ||
'>th, >td': { | ||
background, | ||
textAlign: 'left', | ||
borderBottom: `1px solid ${borderColor}`, | ||
borderInlineEnd: bordered ? `1px solid ${borderColor}` : undefined, | ||
'&[colspan="0"], &[rowspan="0"]': { | ||
display: 'none' | ||
}, | ||
'&[data-n-align="left"]': { | ||
textAlign: 'left' | ||
}, | ||
'&[data-n-align="center"]': { | ||
textAlign: 'center' | ||
}, | ||
'&[data-n-align="right"]': { | ||
textAlign: 'right' | ||
}, | ||
'&[data-n-sticky]': { | ||
// column sticky | ||
position: 'sticky', | ||
zIndex: 1, | ||
transition: 'box-shadow .2s ease-out', | ||
'&[data-n-lshadow="true"]': { | ||
boxShadow: '8px 0px 8px 0px rgb(5 5 5 / 6%)' | ||
}, | ||
'&[data-n-rshadow="true"]': { | ||
boxShadow: '-8px 0px 8px 0px rgb(5 5 5 / 6%)' | ||
} | ||
} | ||
} | ||
} | ||
import { css } from '@emotion/react'; | ||
import { cssScreen, cssHover } from '@nest-ui/core'; | ||
export const cssWrapper = (scrollArea, bordered) => theme => { | ||
const borderColor = theme['table-borderColor'] || '#E4EBF5'; | ||
return css({ | ||
overflow: 'auto', | ||
maxHeight: scrollArea.y, | ||
borderInlineStart: bordered ? `1px solid ${borderColor}` : undefined, | ||
}); | ||
}; | ||
export const cssTable = (scrollArea, bordered) => theme => { | ||
const breakpoints = theme['base-breakpoints'] || [0]; | ||
const fontSize = theme['table-fontSize'] || []; | ||
const lineHeight = theme['table-lineHeight'] || []; | ||
const cellPadding = theme['table>cell-padding'] || [16]; | ||
const borderColor = theme['table-borderColor'] || '#E4EBF5'; | ||
const background = theme['table>row-background'] || '#fff'; | ||
const backgroundHover = theme['table>row:hover-background']; | ||
const expandBackground = theme['table>expand-background']; | ||
const headBackground = theme['table>head-background']; | ||
const headFontColor = theme['table>head-color'] || '#212121'; | ||
const fontColor = theme['table-color']; | ||
return css( | ||
{ | ||
color: fontColor, | ||
width: scrollArea.x, | ||
minWidth: '100%', | ||
position: 'relative', | ||
borderCollapse: 'separate', | ||
borderSpacing: 0, | ||
'>thead, >tbody': { | ||
'>tr': { | ||
'>th, >td': { | ||
background, | ||
textAlign: 'left', | ||
borderBottom: `1px solid ${borderColor}`, | ||
borderInlineEnd: bordered ? `1px solid ${borderColor}` : undefined, | ||
'&[colspan="0"], &[rowspan="0"]': { | ||
display: 'none', | ||
}, | ||
'>thead': { | ||
color: headFontColor, | ||
'>tr >th': { | ||
background: headBackground | ||
}, | ||
'&[data-n-sticky]': { | ||
top: 0, | ||
position: 'sticky', | ||
zIndex: 2 | ||
}, | ||
'>tr:first-of-type >th': { | ||
borderTop: `1px solid ${borderColor}` | ||
} | ||
'&[data-n-align="left"]': { | ||
textAlign: 'left', | ||
}, | ||
'>tbody': { | ||
'>tr[data-n-expand] >td': { | ||
background: expandBackground | ||
}, | ||
'>tr': cssHover({ | ||
'>td': { | ||
background: backgroundHover | ||
} | ||
}) | ||
} | ||
}, ...cssScreen(breakpoints, (idx)=>({ | ||
fontSize: fontSize[idx], | ||
lineHeight: lineHeight[idx], | ||
'>thead, >tbody': { | ||
'>tr': { | ||
'>th, >td': { | ||
padding: cellPadding[idx] | ||
} | ||
} | ||
} | ||
}))); | ||
}; | ||
'&[data-n-align="center"]': { | ||
textAlign: 'center', | ||
}, | ||
'&[data-n-align="right"]': { | ||
textAlign: 'right', | ||
}, | ||
'&[data-n-sticky]': { | ||
// column sticky | ||
position: 'sticky', | ||
zIndex: 1, | ||
transition: 'box-shadow .2s ease-out', | ||
'&[data-n-lshadow="true"]': { | ||
boxShadow: '8px 0px 8px 0px rgb(5 5 5 / 6%)', | ||
}, | ||
'&[data-n-rshadow="true"]': { | ||
boxShadow: '-8px 0px 8px 0px rgb(5 5 5 / 6%)', | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
'>thead': { | ||
color: headFontColor, | ||
'>tr >th': { | ||
background: headBackground, | ||
}, | ||
'&[data-n-sticky]': { | ||
top: 0, | ||
position: 'sticky', | ||
zIndex: 2, | ||
}, | ||
'>tr:first-of-type >th': { | ||
borderTop: `1px solid ${borderColor}`, | ||
}, | ||
}, | ||
'>tbody': { | ||
'>tr[data-n-expand] >td': { | ||
background: expandBackground, | ||
}, | ||
'>tr': cssHover({ | ||
'>td': { | ||
background: backgroundHover, | ||
}, | ||
}), | ||
}, | ||
}, | ||
...cssScreen(breakpoints, idx => ({ | ||
fontSize: fontSize[idx], | ||
lineHeight: lineHeight[idx], | ||
'>thead, >tbody': { | ||
'>tr': { | ||
'>th, >td': { | ||
padding: cellPadding[idx], | ||
}, | ||
}, | ||
}, | ||
})), | ||
); | ||
}; |
import type { HTMLAttributes, ReactElement, ReactNode, Ref, TdHTMLAttributes, ThHTMLAttributes } from 'react'; | ||
export declare type TableHeaderRowProps<Data> = (columns: Array<TableColumnsProps<Data>>, rowIndex: number) => HTMLAttributes<HTMLTableRowElement>; | ||
export declare type TableHeaderRowProps<Data> = ( | ||
columns: Array<TableColumnsProps<Data>>, | ||
rowIndex: number, | ||
) => HTMLAttributes<HTMLTableRowElement>; | ||
export declare type TableRowProps<Data> = (rowData: Data, rowIndex: number) => HTMLAttributes<HTMLTableRowElement>; | ||
export interface RenderRowParams<Data> { | ||
columns: Array<TableColumnsProps<Data>>; | ||
columnsLength?: number; | ||
data: Data[]; | ||
dataTree?: TableDataTree<Data>; | ||
expandable?: TableExpandable<Data>; | ||
rowKey: string; | ||
rowProps?: TableRowProps<Data>; | ||
treeLevel?: number; | ||
columns: Array<TableColumnsProps<Data>>; | ||
columnsLength?: number; | ||
data: Data[]; | ||
dataTree?: TableDataTree<Data>; | ||
expandable?: TableExpandable<Data>; | ||
rowKey: string; | ||
rowProps?: TableRowProps<Data>; | ||
treeLevel?: number; | ||
} | ||
export interface TableColumnsProps<Data> { | ||
align?: 'left' | 'center' | 'right'; | ||
cellProps?: (rowData: Data, rowIndex: number) => TdHTMLAttributes<HTMLTableCellElement>; | ||
children?: Array<TableColumnsProps<Data>>; | ||
dataKey?: string; | ||
sticky?: 'left' | 'right'; | ||
headerCellProps?: ThHTMLAttributes<HTMLTableCellElement>; | ||
key: string; | ||
render?: (colData: any, rowData: Data) => ReactNode; | ||
title?: ReactNode; | ||
treeIndent?: number; | ||
width?: number | string; | ||
align?: 'left' | 'center' | 'right'; | ||
cellProps?: (rowData: Data, rowIndex: number) => TdHTMLAttributes<HTMLTableCellElement>; | ||
children?: Array<TableColumnsProps<Data>>; | ||
dataKey?: string; | ||
sticky?: 'left' | 'right'; | ||
headerCellProps?: ThHTMLAttributes<HTMLTableCellElement>; | ||
key: string; | ||
render?: (colData: any, rowData: Data) => ReactNode; | ||
title?: ReactNode; | ||
treeIndent?: number; | ||
width?: number | string; | ||
} | ||
export interface TableExpandable<Data> { | ||
cellProps?: (rowData: Data, rowIndex: number) => TdHTMLAttributes<HTMLTableCellElement>; | ||
expanded?: (rowData: Data, rowIndex: number) => boolean; | ||
render: (rowData: Data, rowIndex: number) => ReactNode; | ||
rowProps?: TableRowProps<Data>; | ||
startAfterCol?: number; | ||
cellProps?: (rowData: Data, rowIndex: number) => TdHTMLAttributes<HTMLTableCellElement>; | ||
expanded?: (rowData: Data, rowIndex: number) => boolean; | ||
render: (rowData: Data, rowIndex: number) => ReactNode; | ||
rowProps?: TableRowProps<Data>; | ||
startAfterCol?: number; | ||
} | ||
export interface TableScrollArea { | ||
x?: number | string; | ||
y?: number | string; | ||
x?: number | string; | ||
y?: number | string; | ||
} | ||
export interface TableDataTree<Data> { | ||
childKey: string; | ||
expanded?: (rowData: Data, rowIndex: number) => boolean; | ||
childKey: string; | ||
expanded?: (rowData: Data, rowIndex: number) => boolean; | ||
} | ||
export interface TableProps<Data> extends HTMLAttributes<HTMLDivElement> { | ||
bordered?: boolean; | ||
columns?: Array<TableColumnsProps<Data>>; | ||
data?: Data[]; | ||
dataTree?: TableDataTree<Data>; | ||
expandable?: TableExpandable<Data>; | ||
headerRowProps?: TableHeaderRowProps<Data>; | ||
rowKey?: string; | ||
rowProps?: TableRowProps<Data>; | ||
scrollArea?: TableScrollArea; | ||
sticky?: boolean; | ||
tableProps?: HTMLAttributes<HTMLTableElement>; | ||
bordered?: boolean; | ||
columns?: Array<TableColumnsProps<Data>>; | ||
data?: Data[]; | ||
dataTree?: TableDataTree<Data>; | ||
expandable?: TableExpandable<Data>; | ||
headerRowProps?: TableHeaderRowProps<Data>; | ||
rowKey?: string; | ||
rowProps?: TableRowProps<Data>; | ||
scrollArea?: TableScrollArea; | ||
sticky?: boolean; | ||
tableProps?: HTMLAttributes<HTMLTableElement>; | ||
} | ||
export declare type TableComponent = <Data>(props: TableProps<Data> & { | ||
export declare type TableComponent = <Data>( | ||
props: TableProps<Data> & { | ||
ref?: Ref<HTMLDivElement>; | ||
}) => ReactElement | null; | ||
}, | ||
) => ReactElement | null; |
import type { TableColumnsProps } from './type'; | ||
export declare const calcStickyShadow: (wrapperDOM: HTMLElement) => { | ||
shadowLeft: boolean; | ||
shadowRight: boolean; | ||
shadowLeft: boolean; | ||
shadowRight: boolean; | ||
}; | ||
export declare const calcStickyCell: (wrapperDOM: HTMLElement, tableDOM: HTMLTableElement) => void; | ||
export declare const initStickyCell: (tableDOM: HTMLTableElement) => { | ||
destroy: () => void; | ||
destroy: () => void; | ||
}; | ||
export declare const calcColSpan: <Data>(column: TableColumnsProps<Data>, span?: number) => number; | ||
export declare const calcMaxRow: <Data>(columns: TableColumnsProps<Data>[], row?: number) => number; |
@@ -1,83 +0,91 @@ | ||
export const calcStickyShadow = (wrapperDOM)=>{ | ||
const { scrollLeft , offsetWidth , scrollWidth } = wrapperDOM; | ||
let shadowLeft = false; | ||
let shadowRight = false; | ||
if (scrollLeft > 0) shadowLeft = true; | ||
if (scrollLeft < scrollWidth - offsetWidth) shadowRight = true; | ||
return { | ||
shadowLeft, | ||
shadowRight | ||
}; | ||
export const calcStickyShadow = wrapperDOM => { | ||
const { scrollLeft, offsetWidth, scrollWidth } = wrapperDOM; | ||
let shadowLeft = false; | ||
let shadowRight = false; | ||
if (scrollLeft > 0) shadowLeft = true; | ||
if (scrollLeft < scrollWidth - offsetWidth) shadowRight = true; | ||
return { | ||
shadowLeft, | ||
shadowRight, | ||
}; | ||
}; | ||
export const calcStickyCell = (wrapperDOM, tableDOM)=>{ | ||
const { shadowLeft , shadowRight } = calcStickyShadow(wrapperDOM); | ||
const { left: tableLeft , right: tableRight } = tableDOM.getBoundingClientRect(); | ||
const tableRows = tableDOM.querySelectorAll(':scope > thead > tr, :scope > tbody > tr'); | ||
tableRows.forEach((tableRow)=>{ | ||
const leftStickyCells = tableRow.querySelectorAll(':scope > th[data-n-sticky="left"], :scope > td[data-n-sticky="left"]'); | ||
for(let i = 0; i < leftStickyCells.length; i++){ | ||
const cell = leftStickyCells[i]; | ||
cell.style.position = 'static'; | ||
const { left: cellLeft } = cell.getBoundingClientRect(); | ||
cell.style.left = `${cellLeft - tableLeft}px`; | ||
cell.style.position = ''; | ||
if (i === leftStickyCells.length - 1) cell.setAttribute('data-n-lshadow', shadowLeft ? 'true' : ''); | ||
} | ||
const rightStickyCells = tableRow.querySelectorAll(':scope > th[data-n-sticky="right"], :scope > td[data-n-sticky="right"]'); | ||
for(let i1 = rightStickyCells.length - 1; i1 >= 0; i1--){ | ||
const cell1 = rightStickyCells[i1]; | ||
cell1.style.position = 'static'; | ||
const { right: cellRight } = cell1.getBoundingClientRect(); | ||
cell1.style.right = `${tableRight - cellRight}px`; | ||
cell1.style.position = ''; | ||
if (i1 === 0) cell1.setAttribute('data-n-rshadow', shadowRight ? 'true' : ''); | ||
} | ||
export const calcStickyCell = (wrapperDOM, tableDOM) => { | ||
const { shadowLeft, shadowRight } = calcStickyShadow(wrapperDOM); | ||
const { left: tableLeft, right: tableRight } = tableDOM.getBoundingClientRect(); | ||
const tableRows = tableDOM.querySelectorAll(':scope > thead > tr, :scope > tbody > tr'); | ||
tableRows.forEach(tableRow => { | ||
const leftStickyCells = tableRow.querySelectorAll( | ||
':scope > th[data-n-sticky="left"], :scope > td[data-n-sticky="left"]', | ||
); | ||
for (let i = 0; i < leftStickyCells.length; i++) { | ||
const cell = leftStickyCells[i]; | ||
cell.style.position = 'static'; | ||
const { left: cellLeft } = cell.getBoundingClientRect(); | ||
cell.style.left = `${cellLeft - tableLeft}px`; | ||
cell.style.position = ''; | ||
if (i === leftStickyCells.length - 1) cell.setAttribute('data-n-lshadow', shadowLeft ? 'true' : ''); | ||
} | ||
const rightStickyCells = tableRow.querySelectorAll( | ||
':scope > th[data-n-sticky="right"], :scope > td[data-n-sticky="right"]', | ||
); | ||
for (let i1 = rightStickyCells.length - 1; i1 >= 0; i1--) { | ||
const cell1 = rightStickyCells[i1]; | ||
cell1.style.position = 'static'; | ||
const { right: cellRight } = cell1.getBoundingClientRect(); | ||
cell1.style.right = `${tableRight - cellRight}px`; | ||
cell1.style.position = ''; | ||
if (i1 === 0) cell1.setAttribute('data-n-rshadow', shadowRight ? 'true' : ''); | ||
} | ||
}); | ||
}; | ||
export const initStickyCell = tableDOM => { | ||
const wrapperDOM = tableDOM.parentElement; | ||
// resize debounce | ||
let timeout; | ||
const handleResize = () => { | ||
clearTimeout(timeout); | ||
timeout = setTimeout(() => { | ||
calcStickyCell(wrapperDOM, tableDOM); | ||
}, 100); | ||
}; | ||
const handleScroll = e => { | ||
const leftStickyCells = tableDOM.querySelectorAll( | ||
':scope > thead > tr > th[data-n-lshadow], :scope > tbody > tr > td[data-n-lshadow]', | ||
); | ||
const rightStickyCells = tableDOM.querySelectorAll( | ||
':scope > thead > tr > th[data-n-rshadow], :scope > tbody > tr > td[data-n-rshadow]', | ||
); | ||
const { shadowLeft, shadowRight } = calcStickyShadow(e.currentTarget); | ||
leftStickyCells.forEach(cell => { | ||
cell.setAttribute('data-n-lshadow', shadowLeft ? 'true' : ''); | ||
}); | ||
rightStickyCells.forEach(cell => { | ||
cell.setAttribute('data-n-rshadow', shadowRight ? 'true' : ''); | ||
}); | ||
}; | ||
// initialization | ||
calcStickyCell(wrapperDOM, tableDOM); | ||
window.addEventListener('resize', handleResize); | ||
wrapperDOM.addEventListener('scroll', handleScroll); | ||
// cleanup | ||
return { | ||
destroy: () => { | ||
clearTimeout(timeout); | ||
window.removeEventListener('resize', handleResize); | ||
wrapperDOM.removeEventListener('scroll', handleScroll); | ||
}, | ||
}; | ||
}; | ||
export const initStickyCell = (tableDOM)=>{ | ||
const wrapperDOM = tableDOM.parentElement; | ||
// resize debounce | ||
let timeout; | ||
const handleResize = ()=>{ | ||
clearTimeout(timeout); | ||
timeout = setTimeout(()=>{ | ||
calcStickyCell(wrapperDOM, tableDOM); | ||
}, 100); | ||
}; | ||
const handleScroll = (e)=>{ | ||
const leftStickyCells = tableDOM.querySelectorAll(':scope > thead > tr > th[data-n-lshadow], :scope > tbody > tr > td[data-n-lshadow]'); | ||
const rightStickyCells = tableDOM.querySelectorAll(':scope > thead > tr > th[data-n-rshadow], :scope > tbody > tr > td[data-n-rshadow]'); | ||
const { shadowLeft , shadowRight } = calcStickyShadow(e.currentTarget); | ||
leftStickyCells.forEach((cell)=>{ | ||
cell.setAttribute('data-n-lshadow', shadowLeft ? 'true' : ''); | ||
}); | ||
rightStickyCells.forEach((cell)=>{ | ||
cell.setAttribute('data-n-rshadow', shadowRight ? 'true' : ''); | ||
}); | ||
}; | ||
// initialization | ||
calcStickyCell(wrapperDOM, tableDOM); | ||
window.addEventListener('resize', handleResize); | ||
wrapperDOM.addEventListener('scroll', handleScroll); | ||
// cleanup | ||
return { | ||
destroy: ()=>{ | ||
clearTimeout(timeout); | ||
window.removeEventListener('resize', handleResize); | ||
wrapperDOM.removeEventListener('scroll', handleScroll); | ||
} | ||
}; | ||
}; | ||
// recursive loop ancestor to get col Span | ||
export const calcColSpan = (column, span = 0)=>{ | ||
if (column.children) return column.children.reduce((prev, each)=>calcColSpan(each, prev), span); | ||
return span + 1; | ||
export const calcColSpan = (column, span = 0) => { | ||
if (column.children) return column.children.reduce((prev, each) => calcColSpan(each, prev), span); | ||
return span + 1; | ||
}; | ||
// recursive loop each column tree to get maximum row | ||
export const calcMaxRow = (columns, row = 1)=>{ | ||
let maxRow = row; | ||
columns.forEach((column)=>{ | ||
if (column.children) maxRow = Math.max(maxRow, calcMaxRow(column.children, row + 1)); | ||
}); | ||
return maxRow; | ||
export const calcMaxRow = (columns, row = 1) => { | ||
let maxRow = row; | ||
columns.forEach(column => { | ||
if (column.children) maxRow = Math.max(maxRow, calcMaxRow(column.children, row + 1)); | ||
}); | ||
return maxRow; | ||
}; |
{ | ||
"name": "@nest-ui/table", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "NEST Table", | ||
"license": "ISC", | ||
"author": "Tokopedia WPE Nest", | ||
"main": "index.js", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"build": "sh ../../scripts/build/prebuild-single.sh --packageName table --dirName dist", | ||
"build": "sh ../../scripts/build/prebuild.sh --dirName dist", | ||
"build:clean": "pnpm run clean && pnpm run build && pnpm run typecheck", | ||
"build:clean:debug": "pnpm run clean && pnpm run build:debug && pnpm run typecheck", | ||
"build:debug": "sh ../../scripts/build/prebuild-single.sh --packageName table --dirName dist --sourceMap true", | ||
"build:debug": "sh ../../scripts/build/prebuild.sh --dirName dist --sourceMap true", | ||
"build:dev": "pnpm run clean && pnpm run build", | ||
@@ -18,3 +18,3 @@ "clean": "rm -rf dist index.js index.d.ts style.js style.d.ts type.d.ts", | ||
"dev": "watch 'pnpm run dupe' src", | ||
"dupe": "sh ../../scripts/build/prebuild-single.sh --packageName table --dirName dupe --syncFile true", | ||
"dupe": "sh ../../scripts/build/prebuild.sh --dirName dupe --syncFile true", | ||
"movepack": "sh ../../scripts/build/movepack.sh", | ||
@@ -33,3 +33,3 @@ "movepack:debug": "sh ../../scripts/build/movepack.sh --sourceMap true", | ||
"@emotion/react": "^11.10.4", | ||
"@nest-ui/core": "^0.6.1", | ||
"@nest-ui/core": "^1.5.0", | ||
"react": "^17.0.2 || ^18.0.0", | ||
@@ -36,0 +36,0 @@ "react-dom": "^17.0.2 || ^18.0.0" |
517
22534
14