From c8bb2c69e361cfc9277f7a09d4c3368b03ac798b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ula=C5=9F=20Turan?= Date: Sat, 26 Aug 2023 21:36:12 +0300 Subject: [PATCH] Related #4432, #4602 - For DataTable & Column & ColumnGroup & Row --- components/lib/column/column.d.ts | 43 + components/lib/datatable/BodyCell.js | 52 +- components/lib/datatable/BodyRow.js | 30 +- components/lib/datatable/ColumnFilter.js | 42 +- components/lib/datatable/DataTable.js | 10 +- components/lib/datatable/DataTableBase.js | 26 +- components/lib/datatable/FooterCell.js | 17 +- components/lib/datatable/HeaderCell.js | 46 +- components/lib/datatable/HeaderCheckbox.js | 14 +- components/lib/datatable/RowCheckbox.js | 15 +- components/lib/datatable/RowRadioButton.js | 15 +- components/lib/datatable/TableBody.js | 90 +- components/lib/datatable/TableFooter.js | 25 +- components/lib/datatable/TableHeader.js | 44 +- components/lib/datatable/datatable.d.ts | 34 +- package-lock.json | 1033 +++++++++++--------- 16 files changed, 879 insertions(+), 657 deletions(-) diff --git a/components/lib/column/column.d.ts b/components/lib/column/column.d.ts index d94a04fcc5..7970e67c4d 100644 --- a/components/lib/column/column.d.ts +++ b/components/lib/column/column.d.ts @@ -41,6 +41,44 @@ export interface ColumnContext { * @defaultValue false */ disabled: boolean; + /** + * Current index of the column. + */ + index: number; + /** + * Current sort state of the column as a boolean. + * @defaultValue false + */ + sorted: boolean; + /** + * Current resizable state of the column as a boolean. + * @defaultValue false + */ + resizable: boolean; + /** + * Current size state of the table. + */ + size: string; + /** + * Current gridlines state of the table as a boolean. + * @defaultValue false + */ + showGridlines: boolean; + /** + * Current highlighted state of the filter row item as a boolean. + * @defaultValue false + */ + highlighted: boolean; + /** + * Current hidden state of the filter clear button of a column as a boolean. + * @defaultValue false + */ + hidden: boolean; + /** + * Current active state of the filter menu of a column as a boolean. + * @defaultValue false + */ + active: boolean; } /** @@ -64,6 +102,11 @@ export interface ColumnState { * @defaultValue false */ focused: boolean; + /** + * Current visible state of the filter menu of a column as a boolean. + * @defaultValue false + */ + overlayVisible: boolean; /** * Current style of the rowgroup header. */ diff --git a/components/lib/datatable/BodyCell.js b/components/lib/datatable/BodyCell.js index 136c0a19b6..5a5aa7b6a4 100644 --- a/components/lib/datatable/BodyCell.js +++ b/components/lib/datatable/BodyCell.js @@ -24,7 +24,7 @@ export const BodyCell = React.memo((props) => { const selfClick = React.useRef(false); const tabindexTimeout = React.useRef(null); const initFocusTimeout = React.useRef(null); - const { ptmo, cx, sx } = props.ptCallbacks; + const { ptm, ptmo, cx } = props.ptCallbacks; const getColumnProp = (name) => ColumnBase.getCProp(props.column, name); const getColumnProps = (column) => ColumnBase.getCProps(column); @@ -32,15 +32,22 @@ export const BodyCell = React.memo((props) => { const getColumnPTOptions = (key) => { const cProps = getColumnProps(props.column); - return ptmo(getColumnProp('pt'), key, { + const columnMetaData = { props: cProps, parent: props.metaData, state: { styleObject: styleObjectState, editing: editingState, editingRowData: editingRowDataState + }, + context: { + index: props.index, + size: props.metaData.props.size, + showGridlines: props.metaData.props.showGridlines } - }); + }; + + return mergeProps(ptm(`column.${key}`, { column: columnMetaData }), ptm(`column.${key}`, columnMetaData), ptmo(cProps, key, columnMetaData)); }; const field = getColumnProp('field') || `field_${props.index}`; @@ -185,27 +192,27 @@ export const BodyCell = React.memo((props) => { const findNextSelectableCell = (cell) => { const nextCell = cell.nextElementSibling; - return nextCell ? (DomHandler.hasClass(nextCell, 'p-selectable-cell') ? nextCell : findNextSelectableCell(nextCell)) : null; + return nextCell ? (DomHandler.getAttribute(nextCell, 'data-p-selectable-cell') ? nextCell : findNextSelectableCell(nextCell)) : null; }; const findPrevSelectableCell = (cell) => { const prevCell = cell.previousElementSibling; - return prevCell ? (DomHandler.hasClass(prevCell, 'p-selectable-cell') ? prevCell : findPrevSelectableCell(prevCell)) : null; + return prevCell ? (DomHandler.getAttribute(prevCell, 'data-p-selectable-cell') ? prevCell : findPrevSelectableCell(prevCell)) : null; }; const findDownSelectableCell = (cell) => { const downRow = cell.parentElement.nextElementSibling; const downCell = downRow ? downRow.children[props.index] : null; - return downRow && downCell ? (DomHandler.hasClass(downRow, 'p-selectable-row') && DomHandler.hasClass(downCell, 'p-selectable-cell') ? downCell : findDownSelectableCell(downCell)) : null; + return downRow && downCell ? (DomHandler.getAttribute(downRow, 'data-p-selectable-row') && DomHandler.getAttribute(downCell, 'data-p-selectable-cell') ? downCell : findDownSelectableCell(downCell)) : null; }; const findUpSelectableCell = (cell) => { const upRow = cell.parentElement.previousElementSibling; const upCell = upRow ? upRow.children[props.index] : null; - return upRow && upCell ? (DomHandler.hasClass(upRow, 'p-selectable-row') && DomHandler.hasClass(upCell, 'p-selectable-cell') ? upCell : findUpSelectableCell(upCell)) : null; + return upRow && upCell ? (DomHandler.getAttribute(upRow, 'data-p-selectable-row') && DomHandler.getAttribute(upCell, 'data-p-selectable-cell') ? upCell : findUpSelectableCell(upCell)) : null; }; const changeTabIndex = (currentCell, nextCell) => { @@ -219,7 +226,7 @@ export const BodyCell = React.memo((props) => { clearTimeout(tabindexTimeout.current); tabindexTimeout.current = setTimeout(() => { if (editingState) { - const focusableEl = props.editMode === 'cell' ? DomHandler.getFirstFocusableElement(elementRef.current, ':not(.p-cell-editor-key-helper)') : DomHandler.findSingle(elementRef.current, '.p-row-editor-save'); + const focusableEl = props.editMode === 'cell' ? DomHandler.getFirstFocusableElement(elementRef.current, ':not(.p-cell-editor-key-helper)') : DomHandler.findSingle(elementRef.current, '[data-p-row-editor-save="true"]'); focusableEl && focusableEl.focus(); } @@ -231,7 +238,7 @@ export const BodyCell = React.memo((props) => { const focusOnInit = () => { clearTimeout(initFocusTimeout.current); initFocusTimeout.current = setTimeout(() => { - const focusableEl = props.editMode === 'row' ? DomHandler.findSingle(elementRef.current, '.p-row-editor-init') : null; + const focusableEl = props.editMode === 'row' ? DomHandler.findSingle(elementRef.current, '[data-p-row-editor-init="true"]') : null; focusableEl && focusableEl.focus(); }, 1); @@ -680,15 +687,16 @@ export const BodyCell = React.memo((props) => { cancelClassName: cx('rowEditorCancelButton') }; - const rowEditorEditButtonProps = mergeProps( + const rowEditorSaveButtonProps = mergeProps( { type: 'button', name: 'row-save', onClick: rowEditorProps.onSaveClick, className: rowEditorProps.saveClassName, - tabIndex: props.tabIndex + tabIndex: props.tabIndex, + 'data-p-row-editor-save': true }, - getColumnPTOptions('rowEditorSaveButtonProps') + getColumnPTOptions('rowEditorSaveButton') ); const rowEditorCancelButtonProps = mergeProps( @@ -699,12 +707,12 @@ export const BodyCell = React.memo((props) => { className: rowEditorProps.cancelClassName, tabIndex: props.tabIndex }, - getColumnPTOptions('rowEditorCancelButtonProps') + getColumnPTOptions('rowEditorCancelButton') ); content = ( <> - @@ -727,9 +735,10 @@ export const BodyCell = React.memo((props) => { name: 'row-edit', onClick: rowEditorProps.onInitClick, className: rowEditorProps.initClassName, - tabIndex: props.tabIndex + tabIndex: props.tabIndex, + 'data-p-row-editor-init': true }, - getColumnPTOptions('rowEditorInitButtonProps') + getColumnPTOptions('rowEditorInitButton') ); content = ( @@ -794,10 +803,15 @@ export const BodyCell = React.memo((props) => { onKeyDown: (e) => onKeyDown(e), onBlur: (e) => onBlur(e), onMouseDown: (e) => onMouseDown(e), - onMouseUp: (e) => onMouseUp(e) + onMouseUp: (e) => onMouseUp(e), + 'data-p-selectable-cell': props.allowCellSelection && props.isSelectable({ data: getCellParams(), index: props.rowIndex }), + 'data-p-selection-column': getColumnProp('selectionMode') != null, + 'data-p-editable-column': isEditable() != null, + 'data-p-cell-editing': editingState, + 'data-p-frozen-column': frozen }, - getColumnPTOptions('bodyCell'), - getColumnPTOptions('root') + getColumnPTOptions('root'), + getColumnPTOptions('bodyCell') ); return ( diff --git a/components/lib/datatable/BodyRow.js b/components/lib/datatable/BodyRow.js index ec0abb24c4..8be3d79be3 100644 --- a/components/lib/datatable/BodyRow.js +++ b/components/lib/datatable/BodyRow.js @@ -6,20 +6,19 @@ import { BodyCell } from './BodyCell'; export const BodyRow = React.memo((props) => { const [editingState, setEditingState] = React.useState(false); const editing = props.onRowEditChange ? props.editing : editingState; - const getColumnProps = (column) => ColumnBase.getCProps(column); - const { ptm, ptmo, cx } = props.ptCallbacks; + const { ptm, cx } = props.ptCallbacks; - const getColumnPTOptions = (key) => { - const cProps = getColumnProps(props.column); - - return ptmo(cProps, key, { - props, + const getBodyRowPTOptions = (key) => { + return ptm(key, { parent: props.metaData, state: { - editing: editingState + editing: editing }, context: { - index: props.index + index: props.index, + selectable: props.allowRowSelection && props.isSelectable({ data: props.rowData, index: props.rowIndex }), + selected: (!props.allowCellSelection && props.selected) || props.contextMenuSelected, + stripedRows: props.metaData.props.stripedRows } }); }; @@ -62,13 +61,13 @@ export const BodyRow = React.memo((props) => { const findNextSelectableRow = (row) => { const nextRow = row.nextElementSibling; - return nextRow ? (DomHandler.hasClass(nextRow, 'p-selectable-row') ? nextRow : findNextSelectableRow(nextRow)) : null; + return nextRow ? (DomHandler.getAttribute(nextRow, 'data-p-selectable-row') === true ? nextRow : findNextSelectableRow(nextRow)) : null; }; const findPrevSelectableRow = (row) => { const prevRow = row.previousElementSibling; - return prevRow ? (DomHandler.hasClass(prevRow, 'p-selectable-row') ? prevRow : findPrevSelectableRow(prevRow)) : null; + return prevRow ? DomHandler.getAttribute(prevRow, 'data-p-selectable-row') === true : null; }; const shouldRenderBodyCell = (value, column, i) => { @@ -382,7 +381,7 @@ export const BodyRow = React.memo((props) => { { role: 'row', tabIndex: tabIndex, - className: classNames(rowClassName, cx('row', { rowProps: props })), + className: classNames(rowClassName, cx('bodyRow', { rowProps: props })), style: style, onMouseDown: (e) => onMouseDown(e), onMouseUp: (e) => onMouseUp(e), @@ -397,9 +396,12 @@ export const BodyRow = React.memo((props) => { onDragOver: (e) => onDragOver(e), onDragLeave: (e) => onDragLeave(e), onDragEnd: (e) => onDragEnd(e), - onDrop: (e) => onDrop(e) + onDrop: (e) => onDrop(e), + 'data-p-selectable-row': props.allowRowSelection && props.isSelectable({ data: props.rowData, index: props.rowIndex }), + 'data-p-highlight': props.selected, + 'data-p-highlight-contextmenu': props.contextMenuSelected }, - ptm('row') + getBodyRowPTOptions('bodyRow') ); return {content}; diff --git a/components/lib/datatable/ColumnFilter.js b/components/lib/datatable/ColumnFilter.js index 2fc2d8edde..912e70c87e 100644 --- a/components/lib/datatable/ColumnFilter.js +++ b/components/lib/datatable/ColumnFilter.js @@ -24,16 +24,19 @@ export const ColumnFilter = React.memo((props) => { const getColumnProp = (name) => ColumnBase.getCProp(props.column, name); const getColumnProps = () => ColumnBase.getCProps(props.column); const context = React.useContext(PrimeReactContext); - const { ptmo, cx } = props.ptCallbacks; + const { ptm, ptmo, cx } = props.ptCallbacks; - const getColumnPTOptions = (key) => { - return ptmo(getColumnProps(), key, { + const getColumnPTOptions = (key, params) => { + const columnMetadata = { props: getColumnProps(), parent: props.metaData, state: { overlayVisible: overlayVisibleState - } - }); + }, + ...params + }; + + return mergeProps(ptm(`column.${key}`, { column: columnMetadata }), ptm(`column.${key}`, columnMetadata), ptmo(getColumnProps(), key, columnMetadata)); }; const field = getColumnProp('filterField') || getColumnProp('field'); @@ -337,13 +340,13 @@ export const ColumnFilter = React.memo((props) => { const findNextItem = (item) => { const nextItem = item.nextElementSibling; - return nextItem ? (DomHandler.hasClass(nextItem, 'p-column-filter-separator') ? findNextItem(nextItem) : nextItem) : item.parentElement.firstElementChild; + return nextItem ? (DomHandler.getAttribute(nextItem, 'data-p-column-filter-separator') === true ? findNextItem(nextItem) : nextItem) : item.parentElement.firstElementChild; }; const findPrevItem = (item) => { const prevItem = item.previousElementSibling; - return prevItem ? (DomHandler.hasClass(prevItem, 'p-column-filter-separator') ? findPrevItem(prevItem) : prevItem) : item.parentElement.lastElementChild; + return prevItem ? (DomHandler.getAttribute(prevItem, 'data-p-column-filter-separator') === true ? findPrevItem(prevItem) : prevItem) : item.parentElement.lastElementChild; }; const hide = () => { @@ -529,7 +532,11 @@ export const ColumnFilter = React.memo((props) => { onKeyDown: (e) => onToggleButtonKeyDown(e), 'aria-label': label }, - getColumnPTOptions('filterMenuButton') + getColumnPTOptions('filterMenuButton', { + context: { + active: hasFilter() + } + }) ); return ( @@ -562,7 +569,11 @@ export const ColumnFilter = React.memo((props) => { onClick: (e) => clearFilter(e), 'aria-label': clearLabel }, - getColumnPTOptions('headerFilterClearButton') + getColumnPTOptions('headerFilterClearButton', { + context: { + hidden: hasRowFilter() + } + }) ); return ( @@ -582,7 +593,8 @@ export const ColumnFilter = React.memo((props) => { const _noFilterLabel = noFilterLabel(); const filterSeparatorProps = mergeProps( { - className: cx('filterSeparator') + className: cx('filterSeparator'), + 'data-p-column-filter-separator': true }, getColumnPTOptions('filterSeparator') ); @@ -615,7 +627,11 @@ export const ColumnFilter = React.memo((props) => { onKeyDown: (e) => onRowMatchModeKeyDown(e, matchMode), tabIndex }, - getColumnPTOptions('filterRowItem') + getColumnPTOptions('filterRowItem', { + context: { + highlighted: matchMode && isRowMatchModeSelected(value) + } + }) ); return ( @@ -762,7 +778,7 @@ export const ColumnFilter = React.memo((props) => { if (!getColumnProp('filterClear')) { const clearLabel = clearButtonLabel(); - return