From 17fd02901fbe1f972d6cc69afa392a2ede5736f6 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Fri, 1 Nov 2024 15:52:20 +0200 Subject: [PATCH 01/16] [DataTable]: added column groups. --- .../demo/tables/editableTable/TableMode.tsx | 3 +- app/src/demo/tables/editableTable/columns.tsx | 11 +- .../src/table/DataTableCellContainer.tsx | 6 +- .../src/table/DataTableHeaderRow.tsx | 16 ++ .../table/DataTableRowContainer.module.scss | 10 ++ .../src/table/DataTableRowContainer.tsx | 46 +++++- .../columnsGroupsUtils.ts | 40 +++++ uui-core/src/constants/selectors.ts | 7 + uui-core/src/hooks/index.ts | 1 + uui-core/src/hooks/useColumnGroups.ts | 22 +++ uui-core/src/types/tables.ts | 44 ++++++ uui/components/tables/DataTable.tsx | 6 + .../tables/DataTableHeaderCell.module.scss | 2 +- .../DataTableHeaderGroupCell.module.scss | 97 ++++++++++++ .../tables/DataTableHeaderGroupCell.tsx | 138 ++++++++++++++++++ uui/components/tables/DataTableHeaderRow.tsx | 10 ++ uui/settings.ts | 19 +++ uui/settings.types.ts | 14 ++ 18 files changed, 479 insertions(+), 13 deletions(-) create mode 100644 uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts create mode 100644 uui-core/src/hooks/useColumnGroups.ts create mode 100644 uui/components/tables/DataTableHeaderGroupCell.module.scss create mode 100644 uui/components/tables/DataTableHeaderGroupCell.tsx diff --git a/app/src/demo/tables/editableTable/TableMode.tsx b/app/src/demo/tables/editableTable/TableMode.tsx index e7b8b3f6aa..f4ba0be40c 100644 --- a/app/src/demo/tables/editableTable/TableMode.tsx +++ b/app/src/demo/tables/editableTable/TableMode.tsx @@ -3,7 +3,7 @@ import { DataTable } from '@epam/uui'; import { DataRowProps, DataSourceListProps, DataTableState, IControlled } from '@epam/uui-core'; import { DataTableFocusManager } from '@epam/uui-components'; import { ColumnsProps, Task } from './types'; -import { getColumnsTableMode } from './columns'; +import { getColumnsTableMode, groups } from './columns'; export interface TableModeProps extends ColumnsProps { rows: DataRowProps[]; @@ -25,6 +25,7 @@ export function TableMode({ >[] = [ { @@ -35,6 +42,7 @@ export function getColumnsTableMode(columnsProps: ColumnsProps) { }, { key: 'estimate', + group: 'general', textAlign: 'right', caption: 'Estimate', info: 'Estimate in man/days', @@ -62,6 +70,7 @@ export function getColumnsTableMode(columnsProps: ColumnsProps) { }, { key: 'status', + group: 'general', caption: 'Status', width: 160, minWidth: 150, diff --git a/uui-components/src/table/DataTableCellContainer.tsx b/uui-components/src/table/DataTableCellContainer.tsx index de49ccd56f..98a51dd34b 100644 --- a/uui-components/src/table/DataTableCellContainer.tsx +++ b/uui-components/src/table/DataTableCellContainer.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DataColumnProps, IClickable, IHasCX, IHasRawProps } from '@epam/uui-core'; +import { DataColumnGroupProps, DataColumnProps, IClickable, IHasCX, IHasRawProps } from '@epam/uui-core'; import { FlexCell } from '../layout'; import css from './DataTableCellContainer.module.scss'; @@ -15,7 +15,7 @@ export interface DataTableCellContainerProps extends /** * DataTable column configuration. */ - column: DataColumnProps; + column: DataColumnProps | DataColumnGroupProps; /** * CSS text-align property. */ @@ -38,7 +38,7 @@ export const DataTableCellContainer = React.forwardRef extends React.Component { + const isFirstCell = firstColumnIdx === 0; + const isLastCell = lastColumnIdx === this.props.columns.length - 1; + return this.props.renderGroupCell({ + key: `${group.key}-${idx}`, + group, + isFirstCell, + isLastCell, + value: this.props.value, + onValueChange: this.props.onValueChange, + }); + }; + render() { return ( diff --git a/uui-components/src/table/DataTableRowContainer.module.scss b/uui-components/src/table/DataTableRowContainer.module.scss index e403dda49b..5ad53b770e 100644 --- a/uui-components/src/table/DataTableRowContainer.module.scss +++ b/uui-components/src/table/DataTableRowContainer.module.scss @@ -76,3 +76,13 @@ :global(.uui-scroll-shadow-right) { @include scroll-shadow('inset-inline-end'); } + +.groupColumnsWrapper { + display: flex; + flex-direction: row; +} + +.groupWrapper { + display: flex; + flex-direction: column; +} \ No newline at end of file diff --git a/uui-components/src/table/DataTableRowContainer.tsx b/uui-components/src/table/DataTableRowContainer.tsx index e1fe8326cb..e8b7d82b62 100644 --- a/uui-components/src/table/DataTableRowContainer.tsx +++ b/uui-components/src/table/DataTableRowContainer.tsx @@ -2,17 +2,21 @@ import React from 'react'; import { DataColumnProps, IClickable, IHasCX, IHasRawProps, uuiMarkers, Link, cx, DndEventHandlers, + DataColumnGroupProps, } from '@epam/uui-core'; import { FlexRow } from '../layout'; import { Anchor } from '../navigation'; import css from './DataTableRowContainer.module.scss'; +import { getGroupsWithColumns, isGroupOfColumns } from './columnsConfigurationModal/columnsGroupsUtils'; export interface DataTableRowContainerProps extends IClickable, IHasCX, IHasRawProps> { + groups?: DataColumnGroupProps[]; columns?: DataColumnProps[]; renderCell?(column: DataColumnProps, idx: number, eventHandlers?: DndEventHandlers): React.ReactNode; + renderGroupCell?(group: DataColumnGroupProps, idx: number, firstColumnIdx: number, lastColumnIdx: number): React.ReactNode; renderConfigButton?(): React.ReactNode; overlays?: React.ReactNode; link?: Link; @@ -52,8 +56,8 @@ function getSectionStyle(columns: DataColumnProps[], minGrow = 0) { grow = Math.max(grow, minGrow); return { - flex: `${grow} 0 ${width}px`, - minWidth: `${width}px`, + flex: `${grow} 0 ${width + 1}px`, + minWidth: `${width + 1}px`, '--uui-dt-cell-border-width': `${CELL_BORDER_WIDTH}px`, }; } @@ -61,12 +65,40 @@ function getSectionStyle(columns: DataColumnProps[], minGrow = 0) { export const DataTableRowContainer = React.forwardRef( (props: DataTableRowContainerProps, ref: React.ForwardedRef) => { const { onPointerDown, onTouchStart, ...restRawProps } = props.rawProps ?? {}; + function renderCells(columns: DataColumnProps[]) { - return columns.reduce((cells, column) => { - const idx = props.columns?.indexOf(column) || 0; - cells.push(props.renderCell(column, idx, { onPointerDown, onTouchStart })); - return cells; - }, []); + if (!props.groups) { + return columns.map((column) => { + const idx = props.columns?.indexOf(column) || 0; + return props.renderCell(column, idx, { onPointerDown, onTouchStart }); + }); + } + + const columnsWithGroups = getGroupsWithColumns(props.groups, columns); + return columnsWithGroups.map((item, index) => { + if (isGroupOfColumns(item)) { + const firstColumnIdx = props.columns?.indexOf(item.columns[0]) || 0; + const lastColumnIdx = props.columns?.indexOf(item.columns[item.columns.length - 1]) || 0; + + return ( +
+ +
{props.renderGroupCell(item.group, index, firstColumnIdx, lastColumnIdx)}
+
+ { + item.columns.map((column) => { + const idx = props.columns?.indexOf(column) || 0; + return props.renderCell(column, idx, { onPointerDown, onTouchStart }); + }) + } +
+
+ ); + } + + const idx = props.columns?.indexOf(item) || 0; + return props.renderCell(item, idx, { onPointerDown, onTouchStart }); + }); } function wrapFixedSection(columns: DataColumnProps[], direction: 'left' | 'right', hasScrollingSection: boolean) { diff --git a/uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts b/uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts new file mode 100644 index 0000000000..8225c5b84c --- /dev/null +++ b/uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts @@ -0,0 +1,40 @@ +import { DataColumnGroupProps, DataColumnProps } from '@epam/uui-core'; + +interface GroupOfColumns { + type: 'group'; + group: DataColumnGroupProps; + columns: DataColumnProps[]; +} + +const getGroupsByKey = (groups: DataColumnGroupProps[]) => { + if (!groups) { + return null; + } + const gRec = groups.reduce>( + (g, group) => ({ ...g, [group.key]: group }), + {}, + ); + return !Object.keys(gRec).length ? null : gRec; +}; + +export const isGroupOfColumns = ( + item: GroupOfColumns | DataColumnProps, +): item is GroupOfColumns => 'type' in item && item.type === 'group'; + +export const getGroupsWithColumns = (groups: DataColumnGroupProps[], columns: DataColumnProps[]) => { + const groupsByKey = getGroupsByKey(groups); + return columns.reduce | DataColumnProps>>((columnsAndGroups, column) => { + if (column.group) { + const lastItem = columnsAndGroups[columnsAndGroups.length - 1]; + if (lastItem && isGroupOfColumns(lastItem) && lastItem.group.key === column.group) { + lastItem.columns.push(column); + return columnsAndGroups; + } + columnsAndGroups.push({ type: 'group', group: groupsByKey[column.group], columns: [column] }); + return columnsAndGroups; + } + + columnsAndGroups.push(column); + return columnsAndGroups; + }, []); +}; diff --git a/uui-core/src/constants/selectors.ts b/uui-core/src/constants/selectors.ts index 23385f347f..4343066f83 100644 --- a/uui-core/src/constants/selectors.ts +++ b/uui-core/src/constants/selectors.ts @@ -82,6 +82,13 @@ export const uuiDataTableHeaderCell = { uuiTableHeaderFoldAllIcon: 'uui-table-header-fold-all-icon', } as const; +export const uuiDataTableHeaderGroupCell = { + uuiTableHeaderGroupCell: 'uui-table-header-group-cell', + uuiTableHeaderGroupCaption: 'uui-table-header-group-caption', + uuiTableHeaderGroupCaptionWrapper: 'uui-table-header-group-caption-wrapper', + uuiTableHeaderGroupCaptionTooltip: 'uui-table-header-group-caption-tooltip', +} as const; + export const uuiScrollShadows = { top: 'uui-scroll-shadow-top', topVisible: 'uui-scroll-shadow-top-visible', diff --git a/uui-core/src/hooks/index.ts b/uui-core/src/hooks/index.ts index bada89fe8d..084ad4fe7b 100644 --- a/uui-core/src/hooks/index.ts +++ b/uui-core/src/hooks/index.ts @@ -9,3 +9,4 @@ export * from './useLayer'; export * from './usePrevious'; export * from './useResizeObserver'; export * from './useDocumentDir'; +export * from './useColumnGroups'; diff --git a/uui-core/src/hooks/useColumnGroups.ts b/uui-core/src/hooks/useColumnGroups.ts new file mode 100644 index 0000000000..83b55b1d6d --- /dev/null +++ b/uui-core/src/hooks/useColumnGroups.ts @@ -0,0 +1,22 @@ +import { useMemo } from 'react'; +import { DataColumnGroupProps, DataColumnProps } from '../types'; + +export function useColumnGroups(groups: DataColumnGroupProps[], columns: DataColumnProps[]) { + const groupsRecord = useMemo(() => (groups ?? []) + .reduce>( + (groupsRec, group) => ({ ...groupsRec, [group.key]: group }), + {}, + ), [groups]); + + const visiblGroups = useMemo(() => Object.values( + columns.reduce>((vGroups, column) => { + if (column.group) { + vGroups[column.group] = groupsRecord[column.group]; + return vGroups; + } + return vGroups; + }, {}), + ), [groupsRecord, columns]); + + return { groups: visiblGroups }; +} diff --git a/uui-core/src/types/tables.ts b/uui-core/src/types/tables.ts index a26cc490f2..9312169d3d 100644 --- a/uui-core/src/types/tables.ts +++ b/uui-core/src/types/tables.ts @@ -31,6 +31,39 @@ export type ICanBeFixed = { fix?: 'left' | 'right'; }; +export interface DataColumnGroupProps extends IHasCX, IClickable { + /** + * Unique key to identify the column. Used to reference columns, e.g. in ColumnsConfig. + * Also, used as React key for cells, header cells, and other components inside tables. + */ + key: string; + + /** Column caption. Can be a plain text, or any React Component */ + caption?: React.ReactNode; + + /** Aligns cell and header content horizontally */ + textAlign?: 'left' | 'center' | 'right'; + + /** Info tooltip displayed in the table header */ + info?: React.ReactNode; + + /** Overrides rendering of the whole cell */ + renderCell?(column: DataColumnGroupProps): any; + + /** Render callback for column header tooltip. + * This tooltip will appear on cell hover with 600ms delay. + * + * If omitted, default implementation with column.caption + column.info will be rendered. + * Pass `() => null` to disable tooltip rendering. + */ + renderTooltip?(column: DataColumnGroupProps): React.ReactNode; + + /** + * Overrides rendering of the whole header cell. + */ + renderHeaderCell?(cellProps: DataTableHeaderGroupCellProps): any; +} + export interface DataColumnProps extends ICanBeFixed, IHasCX, IClickable, IHasRawProps, Attributes { /** * Unique key to identify the column. Used to reference columns, e.g. in ColumnsConfig. @@ -38,6 +71,8 @@ export interface DataColumnProps extends */ key: string; + group?: string; + /** Column caption. Can be a plain text, or any React Component */ caption?: React.ReactNode; @@ -159,6 +194,13 @@ export interface DataTableHeaderCellProps extends IEdita renderFilter?: (dropdownProps: IDropdownBodyProps) => React.ReactNode; } +export interface DataTableHeaderGroupCellProps extends IHasCX, IEditable { + key: string; + group: DataColumnGroupProps; + isFirstCell: boolean; + isLastCell: boolean; +} + export type DataTableConfigModalParams = IEditable & { /** Array of all table columns */ columns: DataColumnProps[]; @@ -166,6 +208,7 @@ export type DataTableConfigModalParams = IEditable & { export interface DataTableHeaderRowProps extends IEditable, IHasCX, DataTableColumnsConfigOptions { columns: DataColumnProps[]; + groups?: DataColumnGroupProps[]; selectAll?: ICheckable; /** * Enables collapse/expand all functionality. @@ -173,6 +216,7 @@ export interface DataTableHeaderRowProps extends IEditab showFoldAll?: boolean; onConfigButtonClick?: (params: DataTableConfigModalParams) => any; renderCell?: (props: DataTableHeaderCellProps) => React.ReactNode; + renderGroupCell?: (props: DataTableHeaderGroupCellProps) => React.ReactNode; renderConfigButton?: () => React.ReactNode; } diff --git a/uui/components/tables/DataTable.tsx b/uui/components/tables/DataTable.tsx index 70e91ea85d..d3fb8482a3 100644 --- a/uui/components/tables/DataTable.tsx +++ b/uui/components/tables/DataTable.tsx @@ -4,6 +4,8 @@ import { useColumnsWithFilters } from '../../helpers'; import { ColumnsConfig, DataRowProps, useUuiContext, uuiScrollShadows, useColumnsConfig, IEditable, DataTableState, DataTableColumnsConfigOptions, DataSourceListProps, DataColumnProps, cx, TableFiltersConfig, DataTableRowProps, DataTableSelectedCellData, Overwrite, + DataColumnGroupProps, + useColumnGroups, } from '@epam/uui-core'; import { DataTableHeaderRow, DataTableHeaderRowProps } from './DataTableHeaderRow'; import { DataTableRow, DataTableRowProps as UuiDataTableRowProps } from './DataTableRow'; @@ -26,6 +28,8 @@ export interface DataTableProps extends IEditable[]; + groups?: DataColumnGroupProps[]; + /** Array of all possible columns for the table */ columns: DataColumnProps[]; @@ -73,6 +77,7 @@ export function DataTable(props: React.PropsWithChildren(); const columnsWithFilters = useColumnsWithFilters(props.columns, props.filters); const { columns, config, defaultConfig } = useColumnsConfig(columnsWithFilters, props.value?.columnsConfig); + const { groups } = useColumnGroups(props.groups, columns); const defaultRenderRow = React.useCallback((rowProps: DataRowProps & DataTableRowMods) => { return ( @@ -140,6 +145,7 @@ export function DataTable(props: React.PropsWithChildren + > { + getTooltipContent = (column: DataColumnGroupProps) => ( +
+ + { column.caption } + + { column.info && ( + + { column.info } + + ) } +
+ ); + + getColumnCaption = () => { + const renderTooltip = this.props.group.renderTooltip || this.getTooltipContent; + const captionCx = [ + css.caption, + this.props.textCase === 'upper' && css.upperCase, + uuiDataTableHeaderGroupCell.uuiTableHeaderGroupCaption, + settings.sizes.dataTable.header.row.groupCell.truncate.includes(this.props.size) && css.truncate, + ]; + + return ( +
+ + + { this.props.group.caption } + + +
+ ); + }; + + getLeftPadding = () => { + const { columnsGap, isFirstCell } = this.props; + + if (columnsGap) return isFirstCell ? columnsGap : +columnsGap / 2; + return isFirstCell ? settings.sizes.dataTable.header.row.groupCell.defaults.paddingEdge : settings.sizes.dataTable.header.row.groupCell.defaults.padding; + }; + + getRightPadding = () => { + const { columnsGap, isLastCell } = this.props; + + if (columnsGap) return isLastCell ? columnsGap : +columnsGap / 2; + return isLastCell ? settings.sizes.dataTable.header.row.groupCell.defaults.paddingEdge : settings.sizes.dataTable.header.row.groupCell.defaults.padding; + }; + + renderCellContent = (props: HeaderCellContentProps) => { + const computeStyles = { + '--uui-dt-header-group-cell-padding-start': `${this.getLeftPadding()}px`, + '--uui-dt-header-group-cell-padding-end': `${this.getRightPadding()}px`, + } as React.CSSProperties; + + return ( + { + (props.ref as React.RefCallback)(ref); + } } + cx={ cx( + uuiDataTableHeaderGroupCell.uuiTableHeaderGroupCell, + css.root, + `uui-size-${this.props.size || settings.sizes.dataTable.header.row.groupCell.defaults.size}`, + this.props.isFirstCell && 'uui-dt-header-first-column', + this.props.isLastCell && 'uui-dt-header-last-column', + ) } + rawProps={ { + role: 'columnheader', + ...props.eventHandlers, + } } + style={ computeStyles } + > + { this.getColumnCaption() } + + ); + }; + + render() { + if (this.props.group.renderHeaderCell) { + return this.props.group.renderHeaderCell(this.props); + } + + const computeStyles = { + '--uui-dt-header-group-cell-padding-start': `${this.getLeftPadding()}px`, + '--uui-dt-header-group-cell-padding-end': `${this.getRightPadding()}px`, + width: '100%', + } as React.CSSProperties; + + return ( + + { this.getColumnCaption() } + + ); + } +} diff --git a/uui/components/tables/DataTableHeaderRow.tsx b/uui/components/tables/DataTableHeaderRow.tsx index e7afd97939..e842bf748a 100644 --- a/uui/components/tables/DataTableHeaderRow.tsx +++ b/uui/components/tables/DataTableHeaderRow.tsx @@ -9,6 +9,7 @@ import { settings } from '../../settings'; import './variables.scss'; import css from './DataTableHeaderRow.module.scss'; +import { DataTableHeaderGroupCell } from './DataTableHeaderGroupCell'; export type DataTableHeaderRowProps = CoreDataTableHeaderRowProps & DataTableHeaderRowMods; export const DataTableHeaderRow = withMods( @@ -24,6 +25,15 @@ export const DataTableHeaderRow = withMods ), + renderGroupCell: (props) => ( + + ), renderConfigButton: () => ( Date: Fri, 1 Nov 2024 16:07:09 +0200 Subject: [PATCH 02/16] [DataTable]: fixed tests. --- uui-components/src/table/DataTableRowContainer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uui-components/src/table/DataTableRowContainer.tsx b/uui-components/src/table/DataTableRowContainer.tsx index e8b7d82b62..faa35ceb96 100644 --- a/uui-components/src/table/DataTableRowContainer.tsx +++ b/uui-components/src/table/DataTableRowContainer.tsx @@ -56,8 +56,8 @@ function getSectionStyle(columns: DataColumnProps[], minGrow = 0) { grow = Math.max(grow, minGrow); return { - flex: `${grow} 0 ${width + 1}px`, - minWidth: `${width + 1}px`, + flex: `${grow} 0 ${width}px`, + minWidth: `${width}px`, '--uui-dt-cell-border-width': `${CELL_BORDER_WIDTH}px`, }; } From b389ebf6a203ae91ef416a5a4cffe4a1fef00b8f Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Fri, 1 Nov 2024 16:32:21 +0200 Subject: [PATCH 03/16] [DataTable]: changelog updated. --- changelog.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 817f4e8830..8dc39bde93 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ * [TabButton][VerticalTabButton]: decreased paddings, added gaps `3px` between internal items for all sizes according to design * [Tag]: changed layout - added gaps between internal items, changed padding * [Data Sources]: cursor-based pagination support. More details [here](http://uui.epam.com/documents?id=dataSources-lazy-dataSource&mode=doc&category=dataSources&theme=loveship#using_cursor-based_pagination) +* [DataTable]: groups of columns. **What's Fixed** * [VirtualList]: fixed estimatedHeight calculations in components with pagination @@ -35,9 +36,9 @@ **What's New** * [DataTable]: * [Breaking change]: reworked `isAwaysVisible` column configuration prop. Now it's not make column fixed by default and doesn't forbid to unpin or reorder, it's only disallow to hide this column from table. If you need previous behavior, please use `isLocked` prop. - * Added `isLocked` prop for column configuration. If `true` value provided, makes this column locked, which means that you can't hide, unpin or reorder this column. This column should always be pined. + * Added `isLocked` prop for column configuration. If `true` value provided, makes this column locked, which means that you can't hide, unpin or reorder this column. This column should always be pined. * [DataTable]: `ColumnsConfigurationModal` updated modal width from 420px to 560px according design, 'disabled' state for locked columns is changed to 'readonly', added vertical paddings to multiline column names. -* [PickerInput]: +* [PickerInput]: * Added support of `minCharsToSearch` > 0 with `searchPosition = 'body'`. * Added renderEmpty prop to render custom empty block for depends on various reasons. * `renderNotFonud` prop is deprecated, please use `renderEmpty` instead From 987e8e60cb8a14dae7a4735ebaf86654ab6691ac Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Mon, 4 Nov 2024 17:30:54 +0200 Subject: [PATCH 04/16] [DataTable]: refactored. --- .../demo/tables/editableTable/TableMode.tsx | 4 ++-- app/src/demo/tables/editableTable/columns.tsx | 11 +--------- .../src/table/DataTableHeaderRow.tsx | 2 +- .../src/table/DataTableRowContainer.tsx | 8 ++++--- .../columnsGroupsUtils.ts | 15 ++++++++++--- uui-core/src/hooks/index.ts | 1 - uui-core/src/hooks/useColumnGroups.ts | 22 ------------------- uui-core/src/types/tables.ts | 17 +++++++------- uui/components/tables/DataTable.tsx | 7 +++--- .../DataTableHeaderGroupCell.module.scss | 4 ---- 10 files changed, 32 insertions(+), 59 deletions(-) delete mode 100644 uui-core/src/hooks/useColumnGroups.ts diff --git a/app/src/demo/tables/editableTable/TableMode.tsx b/app/src/demo/tables/editableTable/TableMode.tsx index f4ba0be40c..c2b17ad729 100644 --- a/app/src/demo/tables/editableTable/TableMode.tsx +++ b/app/src/demo/tables/editableTable/TableMode.tsx @@ -3,7 +3,7 @@ import { DataTable } from '@epam/uui'; import { DataRowProps, DataSourceListProps, DataTableState, IControlled } from '@epam/uui-core'; import { DataTableFocusManager } from '@epam/uui-components'; import { ColumnsProps, Task } from './types'; -import { getColumnsTableMode, groups } from './columns'; +import { getColumnsTableMode, columnGroups } from './columns'; export interface TableModeProps extends ColumnsProps { rows: DataRowProps[]; @@ -25,7 +25,7 @@ export function TableMode({ >[] = [ { @@ -42,7 +35,6 @@ export function getColumnsTableMode(columnsProps: ColumnsProps) { }, { key: 'estimate', - group: 'general', textAlign: 'right', caption: 'Estimate', info: 'Estimate in man/days', @@ -70,7 +62,6 @@ export function getColumnsTableMode(columnsProps: ColumnsProps) { }, { key: 'status', - group: 'general', caption: 'Status', width: 160, minWidth: 150, diff --git a/uui-components/src/table/DataTableHeaderRow.tsx b/uui-components/src/table/DataTableHeaderRow.tsx index 40cc6a31d9..c7a72b2043 100644 --- a/uui-components/src/table/DataTableHeaderRow.tsx +++ b/uui-components/src/table/DataTableHeaderRow.tsx @@ -99,7 +99,7 @@ export class DataTableHeaderRow extends React.Component extends IClickable, IHasCX, IHasRawProps> { - groups?: DataColumnGroupProps[]; + /** Columns groups configuration */ + columnGroups?: DataColumnGroupProps[]; columns?: DataColumnProps[]; renderCell?(column: DataColumnProps, idx: number, eventHandlers?: DndEventHandlers): React.ReactNode; + /** Columns group cell render function. */ renderGroupCell?(group: DataColumnGroupProps, idx: number, firstColumnIdx: number, lastColumnIdx: number): React.ReactNode; renderConfigButton?(): React.ReactNode; overlays?: React.ReactNode; @@ -67,14 +69,14 @@ export const DataTableRowContainer = React.forwardRef( const { onPointerDown, onTouchStart, ...restRawProps } = props.rawProps ?? {}; function renderCells(columns: DataColumnProps[]) { - if (!props.groups) { + if (!props.columnGroups) { return columns.map((column) => { const idx = props.columns?.indexOf(column) || 0; return props.renderCell(column, idx, { onPointerDown, onTouchStart }); }); } - const columnsWithGroups = getGroupsWithColumns(props.groups, columns); + const columnsWithGroups = getGroupsWithColumns(props.columnGroups, columns); return columnsWithGroups.map((item, index) => { if (isGroupOfColumns(item)) { const firstColumnIdx = props.columns?.indexOf(item.columns[0]) || 0; diff --git a/uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts b/uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts index 8225c5b84c..4ce1a4186e 100644 --- a/uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts +++ b/uui-components/src/table/columnsConfigurationModal/columnsGroupsUtils.ts @@ -21,16 +21,25 @@ export const isGroupOfColumns = ( item: GroupOfColumns | DataColumnProps, ): item is GroupOfColumns => 'type' in item && item.type === 'group'; -export const getGroupsWithColumns = (groups: DataColumnGroupProps[], columns: DataColumnProps[]) => { - const groupsByKey = getGroupsByKey(groups); +export const getGroupsWithColumns = (columnGroups: DataColumnGroupProps[], columns: DataColumnProps[]) => { + const columnGroupsByKey = getGroupsByKey(columnGroups); + if (!columnGroupsByKey) { + return columns; + } + return columns.reduce | DataColumnProps>>((columnsAndGroups, column) => { if (column.group) { + const group = columnGroupsByKey[column.group]; + if (!group) { + throw new Error(`The '${column.group}' group mentioned in the '${column.key}' column is undefined.`); + } const lastItem = columnsAndGroups[columnsAndGroups.length - 1]; if (lastItem && isGroupOfColumns(lastItem) && lastItem.group.key === column.group) { lastItem.columns.push(column); return columnsAndGroups; } - columnsAndGroups.push({ type: 'group', group: groupsByKey[column.group], columns: [column] }); + + columnsAndGroups.push({ type: 'group', group: columnGroupsByKey[column.group], columns: [column] }); return columnsAndGroups; } diff --git a/uui-core/src/hooks/index.ts b/uui-core/src/hooks/index.ts index 084ad4fe7b..bada89fe8d 100644 --- a/uui-core/src/hooks/index.ts +++ b/uui-core/src/hooks/index.ts @@ -9,4 +9,3 @@ export * from './useLayer'; export * from './usePrevious'; export * from './useResizeObserver'; export * from './useDocumentDir'; -export * from './useColumnGroups'; diff --git a/uui-core/src/hooks/useColumnGroups.ts b/uui-core/src/hooks/useColumnGroups.ts deleted file mode 100644 index 83b55b1d6d..0000000000 --- a/uui-core/src/hooks/useColumnGroups.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { useMemo } from 'react'; -import { DataColumnGroupProps, DataColumnProps } from '../types'; - -export function useColumnGroups(groups: DataColumnGroupProps[], columns: DataColumnProps[]) { - const groupsRecord = useMemo(() => (groups ?? []) - .reduce>( - (groupsRec, group) => ({ ...groupsRec, [group.key]: group }), - {}, - ), [groups]); - - const visiblGroups = useMemo(() => Object.values( - columns.reduce>((vGroups, column) => { - if (column.group) { - vGroups[column.group] = groupsRecord[column.group]; - return vGroups; - } - return vGroups; - }, {}), - ), [groupsRecord, columns]); - - return { groups: visiblGroups }; -} diff --git a/uui-core/src/types/tables.ts b/uui-core/src/types/tables.ts index 9312169d3d..a2163e9ab2 100644 --- a/uui-core/src/types/tables.ts +++ b/uui-core/src/types/tables.ts @@ -33,33 +33,32 @@ export type ICanBeFixed = { export interface DataColumnGroupProps extends IHasCX, IClickable { /** - * Unique key to identify the column. Used to reference columns, e.g. in ColumnsConfig. - * Also, used as React key for cells, header cells, and other components inside tables. + * Unique key to identify the columns group. Used to reference columns group. */ key: string; - /** Column caption. Can be a plain text, or any React Component */ + /** Columns group caption. Can be a plain text, or any React Component */ caption?: React.ReactNode; - /** Aligns cell and header content horizontally */ + /** Aligns columns group header content horizontally */ textAlign?: 'left' | 'center' | 'right'; /** Info tooltip displayed in the table header */ info?: React.ReactNode; - /** Overrides rendering of the whole cell */ + /** Overrides rendering of the whole columns group cell */ renderCell?(column: DataColumnGroupProps): any; - /** Render callback for column header tooltip. + /** Render callback for columns group header tooltip. * This tooltip will appear on cell hover with 600ms delay. * - * If omitted, default implementation with column.caption + column.info will be rendered. + * If omitted, default implementation with columnGroup.caption + columnGroup.info will be rendered. * Pass `() => null` to disable tooltip rendering. */ renderTooltip?(column: DataColumnGroupProps): React.ReactNode; /** - * Overrides rendering of the whole header cell. + * Overrides rendering of the whole columns group header cell. */ renderHeaderCell?(cellProps: DataTableHeaderGroupCellProps): any; } @@ -208,7 +207,7 @@ export type DataTableConfigModalParams = IEditable & { export interface DataTableHeaderRowProps extends IEditable, IHasCX, DataTableColumnsConfigOptions { columns: DataColumnProps[]; - groups?: DataColumnGroupProps[]; + columnGroups?: DataColumnGroupProps[]; selectAll?: ICheckable; /** * Enables collapse/expand all functionality. diff --git a/uui/components/tables/DataTable.tsx b/uui/components/tables/DataTable.tsx index d3fb8482a3..4909482a4a 100644 --- a/uui/components/tables/DataTable.tsx +++ b/uui/components/tables/DataTable.tsx @@ -5,7 +5,6 @@ import { ColumnsConfig, DataRowProps, useUuiContext, uuiScrollShadows, useColumnsConfig, IEditable, DataTableState, DataTableColumnsConfigOptions, DataSourceListProps, DataColumnProps, cx, TableFiltersConfig, DataTableRowProps, DataTableSelectedCellData, Overwrite, DataColumnGroupProps, - useColumnGroups, } from '@epam/uui-core'; import { DataTableHeaderRow, DataTableHeaderRowProps } from './DataTableHeaderRow'; import { DataTableRow, DataTableRowProps as UuiDataTableRowProps } from './DataTableRow'; @@ -28,7 +27,8 @@ export interface DataTableProps extends IEditable[]; - groups?: DataColumnGroupProps[]; + /** Array of all possible column groups for the table */ + columnGroups?: DataColumnGroupProps[]; /** Array of all possible columns for the table */ columns: DataColumnProps[]; @@ -77,7 +77,6 @@ export function DataTable(props: React.PropsWithChildren(); const columnsWithFilters = useColumnsWithFilters(props.columns, props.filters); const { columns, config, defaultConfig } = useColumnsConfig(columnsWithFilters, props.value?.columnsConfig); - const { groups } = useColumnGroups(props.groups, columns); const defaultRenderRow = React.useCallback((rowProps: DataRowProps & DataTableRowMods) => { return ( @@ -145,7 +144,7 @@ export function DataTable(props: React.PropsWithChildren Date: Mon, 4 Nov 2024 17:32:17 +0200 Subject: [PATCH 05/16] [DataTable]: one more fix. --- app/src/demo/tables/editableTable/TableMode.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/demo/tables/editableTable/TableMode.tsx b/app/src/demo/tables/editableTable/TableMode.tsx index c2b17ad729..e7b8b3f6aa 100644 --- a/app/src/demo/tables/editableTable/TableMode.tsx +++ b/app/src/demo/tables/editableTable/TableMode.tsx @@ -3,7 +3,7 @@ import { DataTable } from '@epam/uui'; import { DataRowProps, DataSourceListProps, DataTableState, IControlled } from '@epam/uui-core'; import { DataTableFocusManager } from '@epam/uui-components'; import { ColumnsProps, Task } from './types'; -import { getColumnsTableMode, columnGroups } from './columns'; +import { getColumnsTableMode } from './columns'; export interface TableModeProps extends ColumnsProps { rows: DataRowProps[]; @@ -25,7 +25,6 @@ export function TableMode({ Date: Mon, 4 Nov 2024 17:40:49 +0200 Subject: [PATCH 06/16] [DataTable]: added docs. --- uui-core/src/types/tables.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/uui-core/src/types/tables.ts b/uui-core/src/types/tables.ts index a2163e9ab2..7253c54a56 100644 --- a/uui-core/src/types/tables.ts +++ b/uui-core/src/types/tables.ts @@ -31,6 +31,9 @@ export type ICanBeFixed = { fix?: 'left' | 'right'; }; +/** + * Columns group configuration. + */ export interface DataColumnGroupProps extends IHasCX, IClickable { /** * Unique key to identify the columns group. Used to reference columns group. @@ -70,6 +73,9 @@ export interface DataColumnProps extends */ key: string; + /** + * A unique identifier for a group of columns that establishes a connection between the column and the group of columns. + */ group?: string; /** Column caption. Can be a plain text, or any React Component */ @@ -193,10 +199,26 @@ export interface DataTableHeaderCellProps extends IEdita renderFilter?: (dropdownProps: IDropdownBodyProps) => React.ReactNode; } +/** + * DataTable columns group header cell props. + */ export interface DataTableHeaderGroupCellProps extends IHasCX, IEditable { + /** + * A unique identifier for a group. + */ key: string; + /** + * Columns group configuration. + */ group: DataColumnGroupProps; + /** + * Defines if first column of the group is the first one in the table header. + */ isFirstCell: boolean; + + /** + * Defines if last column of the group is the last one in the table header. + */ isLastCell: boolean; } @@ -207,6 +229,9 @@ export type DataTableConfigModalParams = IEditable & { export interface DataTableHeaderRowProps extends IEditable, IHasCX, DataTableColumnsConfigOptions { columns: DataColumnProps[]; + /** + * Columns group configuration. + */ columnGroups?: DataColumnGroupProps[]; selectAll?: ICheckable; /** @@ -215,6 +240,9 @@ export interface DataTableHeaderRowProps extends IEditab showFoldAll?: boolean; onConfigButtonClick?: (params: DataTableConfigModalParams) => any; renderCell?: (props: DataTableHeaderCellProps) => React.ReactNode; + /** + * Columns group cell render function. + */ renderGroupCell?: (props: DataTableHeaderGroupCellProps) => React.ReactNode; renderConfigButton?: () => React.ReactNode; } From 049f99fa5d7309a6ce3de890a9683a99f87a1858 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Tue, 5 Nov 2024 14:43:49 +0100 Subject: [PATCH 07/16] v5.12.0-rc.0 --- app/package.json | 26 ++++++++++++------------- draft-rte/package.json | 10 +++++----- epam-assets/package.json | 2 +- epam-electric/package.json | 8 ++++---- epam-promo/package.json | 10 +++++----- extra/package.json | 8 ++++---- lerna.json | 2 +- loveship/package.json | 10 +++++----- templates/uui-cra-template/package.json | 2 +- test-utils/package.json | 4 ++-- uui-build/package.json | 2 +- uui-components/package.json | 4 ++-- uui-core/package.json | 2 +- uui-db/package.json | 4 ++-- uui-docs/package.json | 12 ++++++------ uui-e2e-tests/package.json | 2 +- uui-editor/package.json | 10 +++++----- uui-timeline/package.json | 6 +++--- uui/package.json | 8 ++++---- 19 files changed, 66 insertions(+), 66 deletions(-) diff --git a/app/package.json b/app/package.json index e52d74e60b..ec21a344fa 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "@epam/app", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM Unified UI landing", "author": "EPAM", "license": "MIT", @@ -17,19 +17,19 @@ "dependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.11", "@elastic/apm-rum": "^5.14.0", - "@epam/assets": "5.11.0-rc.0", - "@epam/draft-rte": "5.11.0-rc.0", - "@epam/electric": "5.11.0-rc.0", + "@epam/assets": "5.12.0-rc.0", + "@epam/draft-rte": "5.12.0-rc.0", + "@epam/electric": "5.12.0-rc.0", "@epam/internal": "0.0.2", - "@epam/loveship": "5.11.0-rc.0", - "@epam/promo": "5.11.0-rc.0", - "@epam/uui": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", - "@epam/uui-db": "5.11.0-rc.0", - "@epam/uui-docs": "5.11.0-rc.0", - "@epam/uui-editor": "5.11.0-rc.0", - "@epam/uui-timeline": "5.11.0-rc.0", + "@epam/loveship": "5.12.0-rc.0", + "@epam/promo": "5.12.0-rc.0", + "@epam/uui": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", + "@epam/uui-db": "5.12.0-rc.0", + "@epam/uui-docs": "5.12.0-rc.0", + "@epam/uui-editor": "5.12.0-rc.0", + "@epam/uui-timeline": "5.12.0-rc.0", "@tanstack/react-query": "^5.17.19", "@udecode/plate-common": "31.3.2", "amplitude-js": "8.9.1", diff --git a/draft-rte/package.json b/draft-rte/package.json index 8e9b3a57e2..7b63b41a9b 100644 --- a/draft-rte/package.json +++ b/draft-rte/package.json @@ -1,6 +1,6 @@ { "name": "@epam/draft-rte", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "author": "EPAM", "license": "MIT", "main": "index.js", @@ -11,10 +11,10 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.11.0-rc.0", - "@epam/loveship": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/assets": "5.12.0-rc.0", + "@epam/loveship": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@types/draft-js": "0.10.23", "classnames": "^2.2.6", "draft-convert": "^2.1.2", diff --git a/epam-assets/package.json b/epam-assets/package.json index 050c45850e..2c5f2fb12d 100644 --- a/epam-assets/package.json +++ b/epam-assets/package.json @@ -1,6 +1,6 @@ { "name": "@epam/assets", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM Assets Library", "author": "EPAM", "license": "MIT", diff --git a/epam-electric/package.json b/epam-electric/package.json index 94dec3a0c1..fdc3c18ab6 100644 --- a/epam-electric/package.json +++ b/epam-electric/package.json @@ -1,6 +1,6 @@ { "name": "@epam/electric", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI components set branded with 'electric' style", "author": "EPAM", "license": "MIT", @@ -12,9 +12,9 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0" + "@epam/uui": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0" }, "devDependencies": { "mockdate": "^3.0.5" diff --git a/epam-promo/package.json b/epam-promo/package.json index 5b253ace82..2a3d044524 100644 --- a/epam-promo/package.json +++ b/epam-promo/package.json @@ -1,6 +1,6 @@ { "name": "@epam/promo", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI4 components set", "author": "EPAM", "license": "MIT", @@ -12,10 +12,10 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.11.0-rc.0", - "@epam/uui": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/assets": "5.12.0-rc.0", + "@epam/uui": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@types/classnames": "2.2.6", "classnames": "2.2.6" }, diff --git a/extra/package.json b/extra/package.json index 2f6ddc298c..1b17826710 100644 --- a/extra/package.json +++ b/extra/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-extra", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI components set branded with 'loveship' style", "author": "EPAM", "license": "MIT", @@ -11,9 +11,9 @@ "build": "ts-node ../uui-build/ts/scripts/buildUuiModule.ts" }, "dependencies": { - "@epam/loveship": "5.11.0-rc.0", - "@epam/promo": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/loveship": "5.12.0-rc.0", + "@epam/promo": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "immutable": "3.8.2" }, "peerDependencies": { diff --git a/lerna.json b/lerna.json index cf1fba6396..d624413ea2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "npmClient": "yarn", "useWorkspaces": true, "exact": true diff --git a/loveship/package.json b/loveship/package.json index 02611668d9..aedaad1cc8 100644 --- a/loveship/package.json +++ b/loveship/package.json @@ -1,6 +1,6 @@ { "name": "@epam/loveship", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI components set branded with 'loveship' style", "author": "EPAM", "license": "MIT", @@ -12,10 +12,10 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.11.0-rc.0", - "@epam/uui": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/assets": "5.12.0-rc.0", + "@epam/uui": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@types/classnames": "2.2.6", "classnames": "2.2.6" }, diff --git a/templates/uui-cra-template/package.json b/templates/uui-cra-template/package.json index 4229573370..fda8d56f5c 100644 --- a/templates/uui-cra-template/package.json +++ b/templates/uui-cra-template/package.json @@ -1,6 +1,6 @@ { "name": "@epam/cra-template-uui", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "keywords": [ "UUI", "react", diff --git a/test-utils/package.json b/test-utils/package.json index 1d742451e3..3e7f1dfbec 100644 --- a/test-utils/package.json +++ b/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-test-utils", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "author": "EPAM", "license": "MIT", "private": false, @@ -11,7 +11,7 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-core": "5.11.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@testing-library/react": "14.0.0", "@testing-library/user-event": "14.4.3", "@types/react-test-renderer": "18.0.0", diff --git a/uui-build/package.json b/uui-build/package.json index 8a3bd99bae..e56591d4ee 100644 --- a/uui-build/package.json +++ b/uui-build/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-build", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "bin": { "epam-uui-build": "./bin/cli.js" }, diff --git a/uui-components/package.json b/uui-components/package.json index f3490cb64c..af2ee45fa0 100644 --- a/uui-components/package.json +++ b/uui-components/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-components", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI Components", "author": "EPAM", "license": "MIT", @@ -13,7 +13,7 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-core": "5.11.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@popperjs/core": "2.9.0", "@types/classnames": "2.2.6", "@types/react-measure": "2.0.8", diff --git a/uui-core/package.json b/uui-core/package.json index e5a2a65440..cdb9cc06ad 100644 --- a/uui-core/package.json +++ b/uui-core/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-core", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI Core", "author": "EPAM", "license": "MIT", diff --git a/uui-db/package.json b/uui-db/package.json index f69ae515f6..e343229fd3 100644 --- a/uui-db/package.json +++ b/uui-db/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-db", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "UUI - client-side relational state cache", "author": "EPAM", "license": "MIT", @@ -14,7 +14,7 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-core": "5.11.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@types/lodash.countby": "4.6.6", "@types/lodash.filter": "4.6.6", "@types/lodash.foreach": "4.5.6", diff --git a/uui-docs/package.json b/uui-docs/package.json index 5e097174ee..52eaaa1262 100644 --- a/uui-docs/package.json +++ b/uui-docs/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-docs", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI Documentation infrastructure", "author": "EPAM", "license": "MIT", @@ -12,11 +12,11 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.11.0-rc.0", - "@epam/promo": "5.11.0-rc.0", - "@epam/uui": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/assets": "5.12.0-rc.0", + "@epam/promo": "5.12.0-rc.0", + "@epam/uui": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@types/classnames": "2.2.6", "classnames": "^2.2.6" }, diff --git a/uui-e2e-tests/package.json b/uui-e2e-tests/package.json index e279b04ee3..d657256790 100644 --- a/uui-e2e-tests/package.json +++ b/uui-e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-e2e-tests", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "", "author": "EPAM", "license": "MIT", diff --git a/uui-editor/package.json b/uui-editor/package.json index 56ef54b393..3af63e429d 100644 --- a/uui-editor/package.json +++ b/uui-editor/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-editor", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "author": "EPAM", "license": "MIT", "main": "index.js", @@ -12,10 +12,10 @@ }, "dependencies": { "@braintree/sanitize-url": "7.0.0", - "@epam/assets": "5.11.0-rc.0", - "@epam/uui": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/assets": "5.12.0-rc.0", + "@epam/uui": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@udecode/plate-autoformat": "31.0.0", "@udecode/plate-basic-marks": "31.0.0", "@udecode/plate-block-quote": "31.0.0", diff --git a/uui-timeline/package.json b/uui-timeline/package.json index 80c9a830c9..8ca62a63e0 100644 --- a/uui-timeline/package.json +++ b/uui-timeline/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-timeline", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "author": "EPAM", "license": "MIT", "main": "index.js", @@ -11,8 +11,8 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@types/lodash.sortedindex": "^4.1.9", "classnames": "^2.2.6", "lodash.sortedindex": "^4.1.0" diff --git a/uui/package.json b/uui/package.json index ca99433d55..4d267dfab5 100644 --- a/uui/package.json +++ b/uui/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui", - "version": "5.11.0-rc.0", + "version": "5.12.0-rc.0", "description": "EPAM UUI components set", "author": "EPAM", "license": "MIT", @@ -12,9 +12,9 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.11.0-rc.0", - "@epam/uui-components": "5.11.0-rc.0", - "@epam/uui-core": "5.11.0-rc.0", + "@epam/assets": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.0", "@popperjs/core": "2.9.0", "classnames": "2.2.6", "dayjs": "1.11.12", From 8c1e76d95829e1d8445266fc62a75a3f02dbfa21 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Wed, 6 Nov 2024 22:27:13 +0200 Subject: [PATCH 08/16] [TimelineScale]: draft version. --- .../tables/editableTable/TimelineHeader.tsx | 1 + .../src/table/DataTableHeaderRow.module.scss | 1 + uui-timeline/src/TimelineScale.module.scss | 4 +- uui-timeline/src/TimelineScale.tsx | 13 ++++-- uui-timeline/src/draw/scale.ts | 42 ++++++++++++++++--- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/app/src/demo/tables/editableTable/TimelineHeader.tsx b/app/src/demo/tables/editableTable/TimelineHeader.tsx index 838c52c5b6..6bf83a4e28 100644 --- a/app/src/demo/tables/editableTable/TimelineHeader.tsx +++ b/app/src/demo/tables/editableTable/TimelineHeader.tsx @@ -42,6 +42,7 @@ export function TimelineHeader({ timelineController }: TimelineHeaderProps) { diff --git a/uui-components/src/table/DataTableHeaderRow.module.scss b/uui-components/src/table/DataTableHeaderRow.module.scss index dee0188493..2dc57bc261 100644 --- a/uui-components/src/table/DataTableHeaderRow.module.scss +++ b/uui-components/src/table/DataTableHeaderRow.module.scss @@ -1,4 +1,5 @@ .root { --uui-dt-row-border-width: 1px; z-index: 5; + height: 100px; } diff --git a/uui-timeline/src/TimelineScale.module.scss b/uui-timeline/src/TimelineScale.module.scss index ddbe91c54d..5b91f8b4a6 100644 --- a/uui-timeline/src/TimelineScale.module.scss +++ b/uui-timeline/src/TimelineScale.module.scss @@ -5,7 +5,7 @@ canvas { .timelineHeader { position: relative; - height: 61px; + // height: 61px; background-color: #FFF; border-top: 1px solid #EEE; // temp } @@ -23,11 +23,9 @@ canvas { .arrow { display: inline-block; width: 36px; - height: 60px; position: absolute; text-align: center; vertical-align: middle; - line-height: 60px; margin: auto; color: rgba(102, 102, 102, 0.7); cursor: pointer; diff --git a/uui-timeline/src/TimelineScale.tsx b/uui-timeline/src/TimelineScale.tsx index 8a949836ff..8c59fcd5ea 100644 --- a/uui-timeline/src/TimelineScale.tsx +++ b/uui-timeline/src/TimelineScale.tsx @@ -180,7 +180,8 @@ export function TimelineScale({ ...props }: TimelineScaleProps) { const [isMouseDown, setIsMouseDown] = useState(false); - + const canvasHeight = props.canvasHeight ?? 60; + const handleWindowMouseUp = useCallback(() => { if (isMouseDown) { setIsMouseDown(false); @@ -211,6 +212,10 @@ export function TimelineScale({ return (
{(props.renderArrowIcon ?? renderArrowIcon)(direction)} @@ -219,7 +224,6 @@ export function TimelineScale({ }; const draw = (context: CanvasRenderingContext2D, t: TimelineTransform) => { - const canvasHeight = 60; context.clearRect(0, 0, t.widthMs, canvasHeight); const fonts = { currentPeriodFont, periodFont, meridiemFont }; @@ -227,8 +231,8 @@ export function TimelineScale({ context, timelineTransform: t, periodTextColor, - canvasHeight, cellBackgroundColor, + canvasHeight, ...fonts, }; @@ -279,7 +283,7 @@ export function TimelineScale({ }, [handleWindowMouseUp]); return ( -
+
{!isMouseDown && (props.renderArrow ?? renderArrow)('left')} {!isMouseDown && (props.renderArrow ?? renderArrow)('right')}
diff --git a/uui-timeline/src/draw/scale.ts b/uui-timeline/src/draw/scale.ts index a4f27e5828..e01a3c66d0 100644 --- a/uui-timeline/src/draw/scale.ts +++ b/uui-timeline/src/draw/scale.ts @@ -16,6 +16,7 @@ import { CanvasDrawWeekendHoursCell, CanvasDrawBottomMonthProps, CanvasDrawTopMonthProps, + CanvasDrawProps, } from './types'; const defaultFonts = { @@ -46,7 +47,7 @@ const topLineMoveAmount = 0.8; const isCurrentPeriod = (leftDate: Date, rightDate: Date) => new Date() >= leftDate && new Date() <= rightDate; -const getCanvasVerticalCenter = (canvasHeight: number) => canvasHeight / 2 - 1; +const getCanvasVerticalCenter = (canvasHeight: number) => canvasHeight / 2; const getBottomCellY = (canvasHeight: number) => getCanvasVerticalCenter(canvasHeight); const getTopMonth = (month: number) => months[month]?.toUpperCase() ?? ''; const getBottomMonth = (month: number) => months[month] ?? ''; @@ -130,6 +131,21 @@ const drawPeriod = ( context.restore(); }; +const calculateTextLine = ({ + context, + text, + canvasHeight, + line, +}: CanvasDrawProps & { canvasHeight: number, line: number, text: string }) => { + const { actualBoundingBoxAscent, actualBoundingBoxDescent } = context.measureText(text); + const headerTextHeight = Math.abs(actualBoundingBoxAscent) + Math.abs(actualBoundingBoxDescent); + + const lineHeight = canvasHeight / 2; + const textCenter = lineHeight / 2; + const baseTextLine = textCenter + headerTextHeight / 2; + return baseTextLine + lineHeight * (line - 1); +}; + const drawPeriodText = ({ context, timelineTransform, @@ -137,6 +153,7 @@ const drawPeriodText = ({ x, width, line, + canvasHeight, isCurPeriod, textColor = defaultColors.periodTextColor, superscript, @@ -148,7 +165,8 @@ const drawPeriodText = ({ context.fillStyle = textColor; const padding = 12; - const headerTextWidth = context.measureText(text).width; + const { width: headerTextWidth } = context.measureText(text); + const textWidth = headerTextWidth + padding * 2; const center = x + width / 2; let left = center - textWidth / 2; @@ -175,16 +193,19 @@ const drawPeriodText = ({ } } - context.fillText(text, left + padding, line * 24); + const textLine = calculateTextLine({ context, text, canvasHeight, line }); + + context.fillText(text, left + padding, textLine); if (superscript) { context.font = meridiemFont; - context.fillText(superscript, left + padding + headerTextWidth + (text.length === 1 ? 3 : 4), line * 24); + const superscriptTextLine = calculateTextLine({ context, text: superscript, canvasHeight, line }); + context.fillText(superscript, left + padding + headerTextWidth + (text.length === 1 ? 3 : 4), superscriptTextLine); } }; -const getBottomLine = (visibility: number) => 2 + (1 - visibility) * moveAmount; -const getTopLine = (visibility: number) => visibility * topLineMoveAmount; +const getBottomLine = (visibility: number) => 2 + (1 - visibility) * 1; +const getTopLine = (visibility: number) => visibility * 1; const drawMinutes = ({ context, @@ -214,6 +235,7 @@ const drawMinutes = ({ line: getBottomLine(visibility), isCurPeriod, textColor: periodTextColor, + canvasHeight, ...restProps, }); drawBottomGridLine({ context, canvasHeight, scaleBar: w, width: cellBorderWidth, color: cellBorderColor }); @@ -333,6 +355,7 @@ const drawRemainingHours = ({ isCurPeriod, textColor: periodTextColor, superscript, + canvasHeight, ...restProps, }); }); @@ -375,6 +398,7 @@ const drawHours = ({ isCurPeriod, textColor: periodTextColor, superscript, + canvasHeight, ...restProps, }); }); @@ -427,6 +451,7 @@ const drawTopDays = ({ line: getTopLine(visibility), isCurPeriod, textColor, + canvasHeight, ...restProps, }); (customDrawToday ?? drawToday)({ context, scaleBar: w, todayLineColor, todayLineHeight, canvasHeight }); @@ -471,6 +496,7 @@ const drawDays = ({ width: w.right - w.left, line: getBottomLine(visibility), isCurPeriod, + canvasHeight, ...restProps, }); }); @@ -508,6 +534,7 @@ const drawTopMonths = ({ line: getTopLine(visibility), isCurPeriod, textColor: periodTextColor, + canvasHeight, ...restProps, }); }); @@ -544,6 +571,7 @@ const drawWeeks = ({ line: getBottomLine(visibility), isCurPeriod, textColor: periodTextColor, + canvasHeight, ...restProps, }); }); @@ -578,6 +606,7 @@ const drawBottomMonths = ({ line: getBottomLine(visibility), isCurPeriod, textColor: periodTextColor, + canvasHeight, ...restProps, }); (customDrawToday ?? drawToday)({ context, scaleBar: w, todayLineColor, todayLineHeight, canvasHeight }); @@ -631,6 +660,7 @@ const drawYears = ({ line, isCurPeriod, textColor: periodTextColor, + canvasHeight, ...restProps, }); }); From 6a4592eb59168bf1d816cdd9d6db668afe830556 Mon Sep 17 00:00:00 2001 From: Yakov Zhmurov Date: Thu, 7 Nov 2024 00:25:20 +0300 Subject: [PATCH 09/16] DataTable - headers grouping - fixed 1px mismatches in horizontal layout --- app/src/sandbox/tables/PersonsTableDemo.tsx | 5 +- app/src/sandbox/tables/columns.tsx | 50 +++++++++++++++---- .../table/DataTableRowContainer.module.scss | 3 +- .../src/table/DataTableRowContainer.tsx | 42 +++++++++++++--- .../DataTableHeaderGroupCell.module.scss | 2 +- .../tables/DataTableHeaderGroupCell.tsx | 1 - 6 files changed, 80 insertions(+), 23 deletions(-) diff --git a/app/src/sandbox/tables/PersonsTableDemo.tsx b/app/src/sandbox/tables/PersonsTableDemo.tsx index 8a08495b39..c8f1eab076 100644 --- a/app/src/sandbox/tables/PersonsTableDemo.tsx +++ b/app/src/sandbox/tables/PersonsTableDemo.tsx @@ -18,7 +18,7 @@ const formatCurrency = (value: number) => { }; export function PersonsTableDemo() { - const { personColumns, summaryColumns } = React.useMemo(() => getColumns(), []); + const { personColumns, summaryColumns, personColumnsGroups } = React.useMemo(() => getColumns(), []); const [summary, setSummary] = React.useState>({ totalCount: undefined, @@ -161,7 +161,7 @@ export function PersonsTableDemo() { [value.filter?.groupBy], ); const { rows, listProps } = useDataRows(tree); - + return (
@@ -189,6 +189,7 @@ export function PersonsTableDemo() { [] } + columnGroups={ personColumnsGroups } value={ value } onValueChange={ onValueChange } filters={ getFilters() } diff --git a/app/src/sandbox/tables/columns.tsx b/app/src/sandbox/tables/columns.tsx index 9807ade643..dabbf1ed24 100644 --- a/app/src/sandbox/tables/columns.tsx +++ b/app/src/sandbox/tables/columns.tsx @@ -1,60 +1,93 @@ import * as React from 'react'; import { Text, FlexRow } from '@epam/loveship'; -import { DataQueryFilter, DataColumnProps } from '@epam/uui-core'; +import { DataQueryFilter, DataColumnProps, DataColumnGroupProps } from '@epam/uui-core'; import type { Person } from '@epam/uui-docs'; import type { PersonTableRecordId } from './types'; import type { PersonsSummary } from './types'; export function getColumns() { + const personColumnsGroups: DataColumnGroupProps[] = [ + { + key: 'name', + caption: 'Name', + }, + { + key: 'position', + caption: 'Position', + }, + { + key: 'amounts', + caption: 'Amounts', + textAlign: 'right', + }, + ]; + const personColumns: DataColumnProps>[] = [ { key: 'name', + group: 'name', caption: 'Name', render: (p) => {p.name}, width: 250, - grow: 1, fix: 'left', + allowResizing: true, + isSortable: true, + }, { + key: 'name2', + group: 'name', + caption: 'Name2', + render: (p) => {p.name}, + width: 250, + fix: 'left', + allowResizing: true, isSortable: true, }, { key: 'jobTitle', + group: 'position', caption: 'Job Title', render: (r) => {r.jobTitle}, width: 200, - grow: 1, + allowResizing: true, isSortable: true, isFilterActive: (f) => !!f.jobTitle, }, { key: 'departmentName', + group: 'position', caption: 'Department', render: (p) => {p.departmentName}, width: 200, - grow: 1, + allowResizing: true, isSortable: true, isFilterActive: (f) => !!f.departmentId, }, { key: 'birthDate', + group: 'position', caption: 'Birth Date', render: (p) => p?.birthDate && {new Date(p.birthDate).toLocaleDateString()}, width: 120, + allowResizing: true, isSortable: true, }, { key: 'hireDate', caption: 'Hire Date', render: (p) => p?.hireDate && {new Date(p.hireDate).toLocaleDateString()}, width: 120, + allowResizing: true, isSortable: true, }, { key: 'locationName', caption: 'Location', render: (p) => {p.locationName}, width: 180, - grow: 1, + allowResizing: true, isSortable: true, }, { key: 'salary', + group: 'amounts', caption: 'Salary', render: (p) => {p.salary}, width: 150, + allowResizing: true, isSortable: true, textAlign: 'right', }, { @@ -72,7 +105,6 @@ export function getColumns() { fix: 'left', textAlign: 'right', width: 250, - grow: 1, render: (p) => ( @@ -87,13 +119,13 @@ export function getColumns() { ), }, { key: 'jobTitle', + group: 'position', width: 200, - grow: 1, render: () => -, }, { key: 'departmentName', + group: 'position', width: 200, - grow: 1, render: () => ( - @@ -111,7 +143,6 @@ export function getColumns() { key: 'locationName', render: () => -, width: 180, - grow: 1, }, { key: 'salary', caption: 'Total Salary', @@ -133,5 +164,6 @@ export function getColumns() { return { personColumns, summaryColumns, + personColumnsGroups, }; } diff --git a/uui-components/src/table/DataTableRowContainer.module.scss b/uui-components/src/table/DataTableRowContainer.module.scss index 5ad53b770e..45ae748e9f 100644 --- a/uui-components/src/table/DataTableRowContainer.module.scss +++ b/uui-components/src/table/DataTableRowContainer.module.scss @@ -50,8 +50,7 @@ // Compensate negative padding of cells to overlap borders // W/o this, we'll have additional --uui-cell-border-width pixels at the right - // We don't have access to the --uui-cell-border-width var. Hard-coded 1px for now. - border-inline-end: 1px solid transparent; + border-inline-end: var(--uui-dt-cell-border-width) solid transparent; } .fixed-columns-section-right { diff --git a/uui-components/src/table/DataTableRowContainer.tsx b/uui-components/src/table/DataTableRowContainer.tsx index 6f4c7debce..f0d8ed5a35 100644 --- a/uui-components/src/table/DataTableRowContainer.tsx +++ b/uui-components/src/table/DataTableRowContainer.tsx @@ -41,20 +41,43 @@ const uuiDataTableRowCssMarkers = { const CELL_BORDER_WIDTH = 1; +enum SectionType { + Fixed = 1, + Scrolling = 2, + Group = 3, + Table = 4 +} + // Scrolling/Fixed sections wrappers, as well as the whole row itself, has to have matching flex-item parameters. // This is required to have the same width, as the sum of column's width, and grow in the same proportion, as columns inside. // E.g. for 2 columns: { width: 100, grow: 0 }, { width: 200, grow: 1 } we compute { width: 300, grow: 1 } // For scrollingSection and for the whole table, we put at least grow=1 - to make the table occupy full width, even if there's no columns with grow > 0. -function getSectionStyle(columns: DataColumnProps[], minGrow = 0) { +function getSectionStyle(columns: DataColumnProps[], type: SectionType) { let grow = 0; let width = 0; columns.forEach((column) => { - const columnWidth = typeof column.width === 'number' ? (column.fix ? column.width : column.width - CELL_BORDER_WIDTH) : column.minWidth || 0; // (column.width - CELL_BORDER_WIDTH) do not forget the negative margin of the scrolling columns in the calculation of the width + let columnWidth; + if (typeof column.width === 'number') { + // As columns border's are overlap to collapse borders, effective width of each cell is less by CELL_BORDER_WIDTH + columnWidth = column.width - CELL_BORDER_WIDTH; + } else if (typeof column.minWidth === 'number') { + columnWidth = column.minWidth; + } else { + columnWidth = 0; + } + width += columnWidth; + grow += typeof column.grow === 'number' ? column.grow : 0; }); + // For fixed sections we keep 1 border width for a transparent border on the edge, so borders on scrolling section can be visible through it + if (width > 0 && type === SectionType.Fixed) { + width += CELL_BORDER_WIDTH; + } + + const minGrow = type === SectionType.Scrolling ? 1 : 0; grow = Math.max(grow, minGrow); return { @@ -83,9 +106,9 @@ export const DataTableRowContainer = React.forwardRef( const lastColumnIdx = props.columns?.indexOf(item.columns[item.columns.length - 1]) || 0; return ( -
- -
{props.renderGroupCell(item.group, index, firstColumnIdx, lastColumnIdx)}
+
+ + {props.renderGroupCell(item.group, index, firstColumnIdx, lastColumnIdx)}
{ item.columns.map((column) => { @@ -106,7 +129,7 @@ export const DataTableRowContainer = React.forwardRef( function wrapFixedSection(columns: DataColumnProps[], direction: 'left' | 'right', hasScrollingSection: boolean) { return (
[]) { return ( -
+
{renderCells(columns)}
); @@ -156,7 +182,7 @@ export const DataTableRowContainer = React.forwardRef( } // We use only total minWidth here, grow is not needed (rows are placed in block or vertical flex contexts) - const minWidth = getSectionStyle(props.columns, 1).minWidth; + const minWidth = getSectionStyle(props.columns, SectionType.Table).minWidth; const rawProps = { ...restRawProps, diff --git a/uui/components/tables/DataTableHeaderGroupCell.module.scss b/uui/components/tables/DataTableHeaderGroupCell.module.scss index e2f952a541..821d170d73 100644 --- a/uui/components/tables/DataTableHeaderGroupCell.module.scss +++ b/uui/components/tables/DataTableHeaderGroupCell.module.scss @@ -16,7 +16,7 @@ align-items: center; padding-inline-start: var(--uui-dt-header-group-cell-padding-start); padding-inline-end: var(--uui-dt-header-group-cell-padding-end); - width: 0; + align-self: stretch; background-clip: padding-box; min-height: var(--uui-dt-header-group-cell-height); diff --git a/uui/components/tables/DataTableHeaderGroupCell.tsx b/uui/components/tables/DataTableHeaderGroupCell.tsx index 4767565122..8c8078fec8 100644 --- a/uui/components/tables/DataTableHeaderGroupCell.tsx +++ b/uui/components/tables/DataTableHeaderGroupCell.tsx @@ -115,7 +115,6 @@ export class DataTableHeaderGroupCell extends const computeStyles = { '--uui-dt-header-group-cell-padding-start': `${this.getLeftPadding()}px`, '--uui-dt-header-group-cell-padding-end': `${this.getRightPadding()}px`, - width: '100%', } as React.CSSProperties; return ( From acd8edb82cc1d9750503d4a78e4ac4a1bc706bc0 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 7 Nov 2024 10:26:50 +0200 Subject: [PATCH 10/16] [TimelineScale]: fixed years animation. --- app/src/demo/tables/editableTable/TimelineHeader.tsx | 2 +- .../src/table/DataTableHeaderRow.module.scss | 2 +- uui-timeline/src/draw/scale.ts | 12 +++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/src/demo/tables/editableTable/TimelineHeader.tsx b/app/src/demo/tables/editableTable/TimelineHeader.tsx index 6bf83a4e28..b0167776bd 100644 --- a/app/src/demo/tables/editableTable/TimelineHeader.tsx +++ b/app/src/demo/tables/editableTable/TimelineHeader.tsx @@ -42,7 +42,7 @@ export function TimelineHeader({ timelineController }: TimelineHeaderProps) {
diff --git a/uui-components/src/table/DataTableHeaderRow.module.scss b/uui-components/src/table/DataTableHeaderRow.module.scss index 2dc57bc261..28564e4ad4 100644 --- a/uui-components/src/table/DataTableHeaderRow.module.scss +++ b/uui-components/src/table/DataTableHeaderRow.module.scss @@ -1,5 +1,5 @@ .root { --uui-dt-row-border-width: 1px; z-index: 5; - height: 100px; + height: 80px; } diff --git a/uui-timeline/src/draw/scale.ts b/uui-timeline/src/draw/scale.ts index e01a3c66d0..eea791e0aa 100644 --- a/uui-timeline/src/draw/scale.ts +++ b/uui-timeline/src/draw/scale.ts @@ -42,9 +42,6 @@ const defaultWidth = { todayLineHeight: 4, }; -const moveAmount = 0.7; -const topLineMoveAmount = 0.8; - const isCurrentPeriod = (leftDate: Date, rightDate: Date) => new Date() >= leftDate && new Date() <= rightDate; const getCanvasVerticalCenter = (canvasHeight: number) => canvasHeight / 2; @@ -634,8 +631,13 @@ const drawYears = ({ timelineTransform.getVisibleYears().forEach((w) => { const text = w.leftDate.getFullYear().toString().toUpperCase(); const isCurPeriod = isCurrentPeriod(w.leftDate, w.rightDate); - const textMoveAmount = isBottom ? moveAmount : topLineMoveAmount; - const line = (visibility + isBottom) * textMoveAmount; + + const bottomAnimationThreshold = 0.4; + const bottomTextMoveMount = 0.74; + const textMoveAmount = isBottom > bottomAnimationThreshold ? bottomTextMoveMount : 1; + let line = (visibility + isBottom) * textMoveAmount; + line = isBottom < bottomAnimationThreshold ? Math.min(line, 1) : line; + if (isBottom) { const y = canvasHeight; timelinePrimitives.drawHorizontalLine({ context, x1: w.left, x2: w.right + 1, y: y - 1, color: cellBorderColor, width: cellBorderWidth }); From 0de7ca8540c92522db8d4e56d9a9c1bf30c5d2f6 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Thu, 7 Nov 2024 10:55:13 +0200 Subject: [PATCH 11/16] [TimelineScale]: fixed height. --- app/src/demo/tables/editableTable/TimelineHeader.tsx | 1 - uui-components/src/table/DataTableHeaderRow.module.scss | 1 - uui-timeline/src/TimelineScale.module.scss | 1 - 3 files changed, 3 deletions(-) diff --git a/app/src/demo/tables/editableTable/TimelineHeader.tsx b/app/src/demo/tables/editableTable/TimelineHeader.tsx index b0167776bd..838c52c5b6 100644 --- a/app/src/demo/tables/editableTable/TimelineHeader.tsx +++ b/app/src/demo/tables/editableTable/TimelineHeader.tsx @@ -42,7 +42,6 @@ export function TimelineHeader({ timelineController }: TimelineHeaderProps) {
diff --git a/uui-components/src/table/DataTableHeaderRow.module.scss b/uui-components/src/table/DataTableHeaderRow.module.scss index 28564e4ad4..dee0188493 100644 --- a/uui-components/src/table/DataTableHeaderRow.module.scss +++ b/uui-components/src/table/DataTableHeaderRow.module.scss @@ -1,5 +1,4 @@ .root { --uui-dt-row-border-width: 1px; z-index: 5; - height: 80px; } diff --git a/uui-timeline/src/TimelineScale.module.scss b/uui-timeline/src/TimelineScale.module.scss index 5b91f8b4a6..c04d714ce9 100644 --- a/uui-timeline/src/TimelineScale.module.scss +++ b/uui-timeline/src/TimelineScale.module.scss @@ -5,7 +5,6 @@ canvas { .timelineHeader { position: relative; - // height: 61px; background-color: #FFF; border-top: 1px solid #EEE; // temp } From 405539695070bca0d4ab5144cec3d5367c4df46d Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Thu, 7 Nov 2024 10:57:55 +0100 Subject: [PATCH 12/16] v5.12.0-rc.1 --- app/package.json | 26 ++++++++++++------------- draft-rte/package.json | 10 +++++----- epam-assets/package.json | 2 +- epam-electric/package.json | 8 ++++---- epam-promo/package.json | 10 +++++----- extra/package.json | 8 ++++---- lerna.json | 2 +- loveship/package.json | 10 +++++----- templates/uui-cra-template/package.json | 2 +- test-utils/package.json | 4 ++-- uui-build/package.json | 2 +- uui-components/package.json | 4 ++-- uui-core/package.json | 2 +- uui-db/package.json | 4 ++-- uui-docs/package.json | 12 ++++++------ uui-e2e-tests/package.json | 2 +- uui-editor/package.json | 10 +++++----- uui-timeline/package.json | 6 +++--- uui/package.json | 8 ++++---- 19 files changed, 66 insertions(+), 66 deletions(-) diff --git a/app/package.json b/app/package.json index ec21a344fa..e6c9434b97 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "@epam/app", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM Unified UI landing", "author": "EPAM", "license": "MIT", @@ -17,19 +17,19 @@ "dependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.11", "@elastic/apm-rum": "^5.14.0", - "@epam/assets": "5.12.0-rc.0", - "@epam/draft-rte": "5.12.0-rc.0", - "@epam/electric": "5.12.0-rc.0", + "@epam/assets": "5.12.0-rc.1", + "@epam/draft-rte": "5.12.0-rc.1", + "@epam/electric": "5.12.0-rc.1", "@epam/internal": "0.0.2", - "@epam/loveship": "5.12.0-rc.0", - "@epam/promo": "5.12.0-rc.0", - "@epam/uui": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", - "@epam/uui-db": "5.12.0-rc.0", - "@epam/uui-docs": "5.12.0-rc.0", - "@epam/uui-editor": "5.12.0-rc.0", - "@epam/uui-timeline": "5.12.0-rc.0", + "@epam/loveship": "5.12.0-rc.1", + "@epam/promo": "5.12.0-rc.1", + "@epam/uui": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", + "@epam/uui-db": "5.12.0-rc.1", + "@epam/uui-docs": "5.12.0-rc.1", + "@epam/uui-editor": "5.12.0-rc.1", + "@epam/uui-timeline": "5.12.0-rc.1", "@tanstack/react-query": "^5.17.19", "@udecode/plate-common": "31.3.2", "amplitude-js": "8.9.1", diff --git a/draft-rte/package.json b/draft-rte/package.json index 7b63b41a9b..216dd3b1e7 100644 --- a/draft-rte/package.json +++ b/draft-rte/package.json @@ -1,6 +1,6 @@ { "name": "@epam/draft-rte", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "author": "EPAM", "license": "MIT", "main": "index.js", @@ -11,10 +11,10 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.12.0-rc.0", - "@epam/loveship": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/assets": "5.12.0-rc.1", + "@epam/loveship": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "@types/draft-js": "0.10.23", "classnames": "^2.2.6", "draft-convert": "^2.1.2", diff --git a/epam-assets/package.json b/epam-assets/package.json index 2c5f2fb12d..13acece9a7 100644 --- a/epam-assets/package.json +++ b/epam-assets/package.json @@ -1,6 +1,6 @@ { "name": "@epam/assets", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM Assets Library", "author": "EPAM", "license": "MIT", diff --git a/epam-electric/package.json b/epam-electric/package.json index fdc3c18ab6..2aa7dae5b3 100644 --- a/epam-electric/package.json +++ b/epam-electric/package.json @@ -1,6 +1,6 @@ { "name": "@epam/electric", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI components set branded with 'electric' style", "author": "EPAM", "license": "MIT", @@ -12,9 +12,9 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0" + "@epam/uui": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1" }, "devDependencies": { "mockdate": "^3.0.5" diff --git a/epam-promo/package.json b/epam-promo/package.json index 2a3d044524..6352137df0 100644 --- a/epam-promo/package.json +++ b/epam-promo/package.json @@ -1,6 +1,6 @@ { "name": "@epam/promo", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI4 components set", "author": "EPAM", "license": "MIT", @@ -12,10 +12,10 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.12.0-rc.0", - "@epam/uui": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/assets": "5.12.0-rc.1", + "@epam/uui": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "@types/classnames": "2.2.6", "classnames": "2.2.6" }, diff --git a/extra/package.json b/extra/package.json index 1b17826710..a9c1c691d1 100644 --- a/extra/package.json +++ b/extra/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-extra", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI components set branded with 'loveship' style", "author": "EPAM", "license": "MIT", @@ -11,9 +11,9 @@ "build": "ts-node ../uui-build/ts/scripts/buildUuiModule.ts" }, "dependencies": { - "@epam/loveship": "5.12.0-rc.0", - "@epam/promo": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/loveship": "5.12.0-rc.1", + "@epam/promo": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "immutable": "3.8.2" }, "peerDependencies": { diff --git a/lerna.json b/lerna.json index d624413ea2..931698c137 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "npmClient": "yarn", "useWorkspaces": true, "exact": true diff --git a/loveship/package.json b/loveship/package.json index aedaad1cc8..a9af28aa64 100644 --- a/loveship/package.json +++ b/loveship/package.json @@ -1,6 +1,6 @@ { "name": "@epam/loveship", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI components set branded with 'loveship' style", "author": "EPAM", "license": "MIT", @@ -12,10 +12,10 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.12.0-rc.0", - "@epam/uui": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/assets": "5.12.0-rc.1", + "@epam/uui": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "@types/classnames": "2.2.6", "classnames": "2.2.6" }, diff --git a/templates/uui-cra-template/package.json b/templates/uui-cra-template/package.json index fda8d56f5c..615183f3e7 100644 --- a/templates/uui-cra-template/package.json +++ b/templates/uui-cra-template/package.json @@ -1,6 +1,6 @@ { "name": "@epam/cra-template-uui", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "keywords": [ "UUI", "react", diff --git a/test-utils/package.json b/test-utils/package.json index 3e7f1dfbec..6b84a3e90c 100644 --- a/test-utils/package.json +++ b/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-test-utils", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "author": "EPAM", "license": "MIT", "private": false, @@ -11,7 +11,7 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-core": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.1", "@testing-library/react": "14.0.0", "@testing-library/user-event": "14.4.3", "@types/react-test-renderer": "18.0.0", diff --git a/uui-build/package.json b/uui-build/package.json index e56591d4ee..9c1a940271 100644 --- a/uui-build/package.json +++ b/uui-build/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-build", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "bin": { "epam-uui-build": "./bin/cli.js" }, diff --git a/uui-components/package.json b/uui-components/package.json index af2ee45fa0..1456f44fcd 100644 --- a/uui-components/package.json +++ b/uui-components/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-components", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI Components", "author": "EPAM", "license": "MIT", @@ -13,7 +13,7 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-core": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.1", "@popperjs/core": "2.9.0", "@types/classnames": "2.2.6", "@types/react-measure": "2.0.8", diff --git a/uui-core/package.json b/uui-core/package.json index cdb9cc06ad..963525ecb9 100644 --- a/uui-core/package.json +++ b/uui-core/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-core", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI Core", "author": "EPAM", "license": "MIT", diff --git a/uui-db/package.json b/uui-db/package.json index e343229fd3..ff81d9a2a4 100644 --- a/uui-db/package.json +++ b/uui-db/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-db", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "UUI - client-side relational state cache", "author": "EPAM", "license": "MIT", @@ -14,7 +14,7 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-core": "5.12.0-rc.0", + "@epam/uui-core": "5.12.0-rc.1", "@types/lodash.countby": "4.6.6", "@types/lodash.filter": "4.6.6", "@types/lodash.foreach": "4.5.6", diff --git a/uui-docs/package.json b/uui-docs/package.json index 52eaaa1262..6e0215ec81 100644 --- a/uui-docs/package.json +++ b/uui-docs/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-docs", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI Documentation infrastructure", "author": "EPAM", "license": "MIT", @@ -12,11 +12,11 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.12.0-rc.0", - "@epam/promo": "5.12.0-rc.0", - "@epam/uui": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/assets": "5.12.0-rc.1", + "@epam/promo": "5.12.0-rc.1", + "@epam/uui": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "@types/classnames": "2.2.6", "classnames": "^2.2.6" }, diff --git a/uui-e2e-tests/package.json b/uui-e2e-tests/package.json index d657256790..5952aa5a58 100644 --- a/uui-e2e-tests/package.json +++ b/uui-e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-e2e-tests", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "", "author": "EPAM", "license": "MIT", diff --git a/uui-editor/package.json b/uui-editor/package.json index 3af63e429d..4411f7c019 100644 --- a/uui-editor/package.json +++ b/uui-editor/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-editor", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "author": "EPAM", "license": "MIT", "main": "index.js", @@ -12,10 +12,10 @@ }, "dependencies": { "@braintree/sanitize-url": "7.0.0", - "@epam/assets": "5.12.0-rc.0", - "@epam/uui": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/assets": "5.12.0-rc.1", + "@epam/uui": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "@udecode/plate-autoformat": "31.0.0", "@udecode/plate-basic-marks": "31.0.0", "@udecode/plate-block-quote": "31.0.0", diff --git a/uui-timeline/package.json b/uui-timeline/package.json index 8ca62a63e0..ccae64ce73 100644 --- a/uui-timeline/package.json +++ b/uui-timeline/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui-timeline", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "author": "EPAM", "license": "MIT", "main": "index.js", @@ -11,8 +11,8 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "@types/lodash.sortedindex": "^4.1.9", "classnames": "^2.2.6", "lodash.sortedindex": "^4.1.0" diff --git a/uui/package.json b/uui/package.json index 4d267dfab5..01ac38a004 100644 --- a/uui/package.json +++ b/uui/package.json @@ -1,6 +1,6 @@ { "name": "@epam/uui", - "version": "5.12.0-rc.0", + "version": "5.12.0-rc.1", "description": "EPAM UUI components set", "author": "EPAM", "license": "MIT", @@ -12,9 +12,9 @@ "prepublish": "yarn build" }, "dependencies": { - "@epam/assets": "5.12.0-rc.0", - "@epam/uui-components": "5.12.0-rc.0", - "@epam/uui-core": "5.12.0-rc.0", + "@epam/assets": "5.12.0-rc.1", + "@epam/uui-components": "5.12.0-rc.1", + "@epam/uui-core": "5.12.0-rc.1", "@popperjs/core": "2.9.0", "classnames": "2.2.6", "dayjs": "1.11.12", From ad144c89882a736b2c081d9881d518ba9ddbf50b Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 25 Nov 2024 17:32:03 +0100 Subject: [PATCH 13/16] [Docs]: draft table header grouped example --- .../tables/TableGroupedHeader.example.tsx | 139 ++++++++++++++++++ app/src/docs/tables/Advanced.doc.tsx | 6 +- 2 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 app/src/docs/_examples/tables/TableGroupedHeader.example.tsx diff --git a/app/src/docs/_examples/tables/TableGroupedHeader.example.tsx b/app/src/docs/_examples/tables/TableGroupedHeader.example.tsx new file mode 100644 index 0000000000..e8a8b0fcdc --- /dev/null +++ b/app/src/docs/_examples/tables/TableGroupedHeader.example.tsx @@ -0,0 +1,139 @@ +import React, { ReactNode, useMemo, useState } from 'react'; +import { + DataSourceState, + DataColumnProps, + useUuiContext, + useLazyDataSource, + DropdownBodyProps, + DataColumnGroupProps, +} from '@epam/uui-core'; +import { Dropdown, DropdownMenuButton, DropdownMenuSplitter, DropdownMenuBody, Text, DataTable, Panel, IconButton } from '@epam/uui'; +import { City } from '@epam/uui-docs'; +import { ReactComponent as MoreIcon } from '@epam/assets/icons/common/navigation-more_vert-18.svg'; +import { ReactComponent as PencilIcon } from '@epam/assets/icons/common/content-edit-18.svg'; + +import css from './TablesExamples.module.scss'; +import { TApi } from '../../../data'; + +export default function TableGroupedHeaderExample() { + const svc = useUuiContext(); + const [tableState, setTableState] = useState({}); + + const renderMenu = (dropdownProps: DropdownBodyProps): ReactNode => ( + + + + + + + ); + + // Define columns groups array + const columnGroups: DataColumnGroupProps[] = [ + { + key: 'primary', + caption: 'Primary info', + textAlign: 'center', + }, + ]; + + // Define columns config array + const citiesColumns: DataColumnProps[] = useMemo( + () => [ + { + key: 'id', + caption: 'Id', + group: 'primary', // key group from columnGroups array + render: (city) => ( + + {city.id} + + ), + isSortable: true, + width: 120, + }, + { + key: 'name', + caption: 'Name', + group: 'primary', // key group from columnGroups array + render: (city) => ( + + {city.name} + + ), + isSortable: true, + width: 162, + grow: 1, + }, + { + key: 'countryName', + caption: 'Country', + group: 'primary', // key group from columnGroups array + render: (city) => ( + + {city.countryName} + + ), + isSortable: true, + width: 128, + isFilterActive: (filter) => filter.country && filter.country.$in && !!filter.country.$in.length, + }, + { + key: 'population', + caption: 'Population', + info: 'Number of this population in the country at the time of the last census.', + render: (city) => ( + + {city.population} + + ), + width: 136, + isSortable: true, + textAlign: 'right', + }, + { + key: 'altname', + caption: 'Alt. names', + render: (city) => {city.alternativeNames.join(', ')}, + info: 'Alternative city names', + width: 1200, + }, + { + key: 'actions', + render: () => ( + } + renderBody={ (dropdownProps) => renderMenu(dropdownProps) } + placement="bottom-end" + /> + ), + width: 54, + fix: 'right', + allowResizing: false, + }, + ], + [], + ); + + const citiesDS = useLazyDataSource({ + api: svc.api.demo.cities, + backgroundReload: true, + }, []); + + const view = citiesDS.useView(tableState, setTableState); + + return ( + + + + ); +} diff --git a/app/src/docs/tables/Advanced.doc.tsx b/app/src/docs/tables/Advanced.doc.tsx index db0844a6b8..153c7bcb8b 100644 --- a/app/src/docs/tables/Advanced.doc.tsx +++ b/app/src/docs/tables/Advanced.doc.tsx @@ -14,8 +14,6 @@ export class AdvancedTablesDoc extends BaseDocsBlock { - - @@ -23,6 +21,10 @@ export class AdvancedTablesDoc extends BaseDocsBlock { + + + + ); } From e4303cb38eb4b161fefcc2cd552a13db03bbafc6 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Tue, 26 Nov 2024 17:46:05 +0100 Subject: [PATCH 14/16] [DataTable]: add border for column groups in header --- .../tables/TableGroupedHeader.example.tsx | 183 ++++++++---------- .../examples-tables-TableGroupedHeader.json | 32 +++ .../table/DataTableRowContainer.module.scss | 2 +- .../src/table/DataTableRowContainer.tsx | 2 +- .../tables/DataTableHeaderCell.module.scss | 6 +- .../DataTableHeaderGroupCell.module.scss | 2 + .../tables/DataTableHeaderRow.module.scss | 5 + 7 files changed, 125 insertions(+), 107 deletions(-) create mode 100644 public/docs/content/examples-tables-TableGroupedHeader.json diff --git a/app/src/docs/_examples/tables/TableGroupedHeader.example.tsx b/app/src/docs/_examples/tables/TableGroupedHeader.example.tsx index e8a8b0fcdc..3466d93fc2 100644 --- a/app/src/docs/_examples/tables/TableGroupedHeader.example.tsx +++ b/app/src/docs/_examples/tables/TableGroupedHeader.example.tsx @@ -1,16 +1,7 @@ -import React, { ReactNode, useMemo, useState } from 'react'; -import { - DataSourceState, - DataColumnProps, - useUuiContext, - useLazyDataSource, - DropdownBodyProps, - DataColumnGroupProps, -} from '@epam/uui-core'; -import { Dropdown, DropdownMenuButton, DropdownMenuSplitter, DropdownMenuBody, Text, DataTable, Panel, IconButton } from '@epam/uui'; -import { City } from '@epam/uui-docs'; -import { ReactComponent as MoreIcon } from '@epam/assets/icons/common/navigation-more_vert-18.svg'; -import { ReactComponent as PencilIcon } from '@epam/assets/icons/common/content-edit-18.svg'; +import React, { useState } from 'react'; +import { DataSourceState, DataColumnProps, useUuiContext, useLazyDataSource, DataColumnGroupProps } from '@epam/uui-core'; +import { Text, DataTable, Panel, FlexRow, Badge, BadgeProps } from '@epam/uui'; +import { Person } from '@epam/uui-docs'; import css from './TablesExamples.module.scss'; import { TApi } from '../../../data'; @@ -19,104 +10,90 @@ export default function TableGroupedHeaderExample() { const svc = useUuiContext(); const [tableState, setTableState] = useState({}); - const renderMenu = (dropdownProps: DropdownBodyProps): ReactNode => ( - - - - - - - ); - // Define columns groups array const columnGroups: DataColumnGroupProps[] = [ { - key: 'primary', - caption: 'Primary info', + key: 'location', + caption: 'Location', + textAlign: 'center', + }, + { + key: 'position', + caption: 'Position', textAlign: 'center', }, ]; // Define columns config array - const citiesColumns: DataColumnProps[] = useMemo( - () => [ - { - key: 'id', - caption: 'Id', - group: 'primary', // key group from columnGroups array - render: (city) => ( - - {city.id} - - ), - isSortable: true, - width: 120, - }, - { - key: 'name', - caption: 'Name', - group: 'primary', // key group from columnGroups array - render: (city) => ( - - {city.name} - - ), - isSortable: true, - width: 162, - grow: 1, - }, - { - key: 'countryName', - caption: 'Country', - group: 'primary', // key group from columnGroups array - render: (city) => ( - - {city.countryName} - - ), - isSortable: true, - width: 128, - isFilterActive: (filter) => filter.country && filter.country.$in && !!filter.country.$in.length, - }, - { - key: 'population', - caption: 'Population', - info: 'Number of this population in the country at the time of the last census.', - render: (city) => ( - - {city.population} - - ), - width: 136, - isSortable: true, - textAlign: 'right', - }, - { - key: 'altname', - caption: 'Alt. names', - render: (city) => {city.alternativeNames.join(', ')}, - info: 'Alternative city names', - width: 1200, - }, - { - key: 'actions', - render: () => ( - } - renderBody={ (dropdownProps) => renderMenu(dropdownProps) } - placement="bottom-end" - /> - ), - width: 54, - fix: 'right', - allowResizing: false, - }, - ], - [], - ); + const personColumns: DataColumnProps[] = [ + { + key: 'name', + caption: 'Name', + render: (p) => {p.name}, + width: 130, + isSortable: true, + }, + { + key: 'profileStatus', + caption: 'Status', + render: (p) => ( + + + + ), + grow: 0, + width: 100, + minWidth: 90, + isSortable: true, + }, + { + key: 'countryName', + caption: 'Country', + group: 'location', // Specify group key + render: (p) => {p.countryName}, + grow: 0, + width: 110, + isSortable: true, + }, + { + key: 'cityName', + caption: 'City', + group: 'location', // Specify group key + render: (p) => {p.cityName}, + grow: 0, + width: 110, + isSortable: true, + }, + { + key: 'officeAddress', + caption: 'Office', + group: 'location', // Specify group key + render: (p) => {p.officeAddress}, + grow: 0, + width: 150, + isSortable: true, + }, + { + key: 'jobTitle', + caption: 'Title', + group: 'position', // Specify group key + render: (r) => {r.jobTitle}, + width: 180, + isSortable: true, + }, + { + key: 'titleLevel', + caption: 'Track & Level', + group: 'position', // Specify group key + render: (p) => {p.titleLevel}, + grow: 1, + width: 100, + isSortable: true, + }, + ]; - const citiesDS = useLazyDataSource({ - api: svc.api.demo.cities, + const citiesDS = useLazyDataSource({ + api: svc.api.demo.persons, backgroundReload: true, }, []); @@ -131,8 +108,8 @@ export default function TableGroupedHeaderExample() { getRows={ view.getVisibleRows } showColumnsConfig={ false } columnGroups={ columnGroups } + columns={ personColumns } headerTextCase="upper" - columns={ citiesColumns } /> ); diff --git a/public/docs/content/examples-tables-TableGroupedHeader.json b/public/docs/content/examples-tables-TableGroupedHeader.json new file mode 100644 index 0000000000..ed1dc5a795 --- /dev/null +++ b/public/docs/content/examples-tables-TableGroupedHeader.json @@ -0,0 +1,32 @@ +[ + { + "type": "paragraph", + "children": [ + { + "text": "To create column groups in the table header, provide the group configuration using the " + }, + { + "text": "columnGroups", + "uui-richTextEditor-code": true + }, + { + "text": " prop. For each column to be grouped, specify the " + }, + { + "text": "group", + "uui-richTextEditor-code": true + }, + { + "text": " field with the corresponding group key." + } + ] + }, + { + "type": "note-warning", + "children": [ + { + "text": "This is preview version of header groups functionality with limited support of some DataTable features, like columns reordering, resizing and columns configuration via modal." + } + ] + } +] \ No newline at end of file diff --git a/uui-components/src/table/DataTableRowContainer.module.scss b/uui-components/src/table/DataTableRowContainer.module.scss index 45ae748e9f..f9d2f4d8f4 100644 --- a/uui-components/src/table/DataTableRowContainer.module.scss +++ b/uui-components/src/table/DataTableRowContainer.module.scss @@ -81,7 +81,7 @@ flex-direction: row; } -.groupWrapper { +:global(.uui-table-column-group-wrapper) { display: flex; flex-direction: column; } \ No newline at end of file diff --git a/uui-components/src/table/DataTableRowContainer.tsx b/uui-components/src/table/DataTableRowContainer.tsx index f0d8ed5a35..f1488e002b 100644 --- a/uui-components/src/table/DataTableRowContainer.tsx +++ b/uui-components/src/table/DataTableRowContainer.tsx @@ -106,7 +106,7 @@ export const DataTableRowContainer = React.forwardRef( const lastColumnIdx = props.columns?.indexOf(item.columns[item.columns.length - 1]) || 0; return ( -
+
{props.renderGroupCell(item.group, index, firstColumnIdx, lastColumnIdx)}
diff --git a/uui/components/tables/DataTableHeaderCell.module.scss b/uui/components/tables/DataTableHeaderCell.module.scss index 272fd0098c..19643394c9 100644 --- a/uui/components/tables/DataTableHeaderCell.module.scss +++ b/uui/components/tables/DataTableHeaderCell.module.scss @@ -13,6 +13,7 @@ --uui-dt-header-cell-height: var(--uui-size); --uui-dt-header-cell-caption-column-gap: 3px; --uui-dt-header-cell-truncate-caption-line-height: 18px; + --uui-dt-header-cell-border: transparent; // color: var(--uui-text-primary); align-items: center; @@ -21,6 +22,7 @@ width: 0; background-clip: padding-box; min-height: var(--uui-dt-header-cell-height); + border-color: var(--uui-dt-header-cell-border); .caption-wrapper { column-gap: var(--uui-dt-header-cell-caption-column-gap); @@ -38,7 +40,7 @@ &:hover { background: var(--uui-dt-row-bg-hover); - box-shadow: inset 1px 0 0 var(--uui-dt-border), inset -1px 0 0 var(--uui-dt-border); + border-color: var(--uui-dt-border); } &:hover:not(:has(:global(.-clickable):hover)) { @@ -50,7 +52,7 @@ &.resizable { &:hover { - box-shadow: inset 1px 0 0 var(--uui-dt-border), inset -1px 0 0 var(--uui-dt-border); + border-color: var(--uui-dt-border); } } diff --git a/uui/components/tables/DataTableHeaderGroupCell.module.scss b/uui/components/tables/DataTableHeaderGroupCell.module.scss index 821d170d73..496a21e7ab 100644 --- a/uui/components/tables/DataTableHeaderGroupCell.module.scss +++ b/uui/components/tables/DataTableHeaderGroupCell.module.scss @@ -19,6 +19,8 @@ align-self: stretch; background-clip: padding-box; min-height: var(--uui-dt-header-group-cell-height); + border-bottom: 1px solid; + border-color: var(--uui-dt-border); .caption-wrapper { column-gap: var(--uui-dt-header-group-cell-caption-column-gap); diff --git a/uui/components/tables/DataTableHeaderRow.module.scss b/uui/components/tables/DataTableHeaderRow.module.scss index da12d29626..f1f56a0d9b 100644 --- a/uui/components/tables/DataTableHeaderRow.module.scss +++ b/uui/components/tables/DataTableHeaderRow.module.scss @@ -2,6 +2,11 @@ .root { --uui-dt-header-row-config-icon-padding: 24px; + + + :global(.uui-table-column-group-wrapper) :global(.uui-table-header-cell) { + --uui-dt-header-cell-border: var(--uui-dt-border); + } } :global(.config-icon) { From 8579a470f231bbe505f8cfca15945e8b5e083a34 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Tue, 26 Nov 2024 17:49:50 +0100 Subject: [PATCH 15/16] update changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 0b8dff7c50..6d16081d18 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ # 5.xx.xx - xx.xx.2024 **What's New** +* [DataTable]: added support of column groups in table header. Read more - https://uui.epam.com/documents?id=advancedTables&mode=doc&category=tables&theme=electric#table_with_header_groups * [ErrorPage]: Added field for additional message with support link (it works with `500, 503, default` errors), added support link for the site **What's Fixed** From 4ae61321e20eb00d3d10a5e4766e34007dfad170 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Tue, 26 Nov 2024 17:52:41 +0100 Subject: [PATCH 16/16] update changelog --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 6d16081d18..f936856ecb 100644 --- a/changelog.md +++ b/changelog.md @@ -2,7 +2,7 @@ **What's New** * [DataTable]: added support of column groups in table header. Read more - https://uui.epam.com/documents?id=advancedTables&mode=doc&category=tables&theme=electric#table_with_header_groups -* [ErrorPage]: Added field for additional message with support link (it works with `500, 503, default` errors), added support link for the site +* [ErrorPage]: added field for additional message with support link (it works with `500, 503, default` errors), added support link for the site **What's Fixed** * [PickerInput]: fixed unnecessary api calls on body open with `minCharsToSearch` prop and search in body