From 17fd02901fbe1f972d6cc69afa392a2ede5736f6 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Fri, 1 Nov 2024 15:52:20 +0200 Subject: [PATCH 01/54] [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/54] [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/54] [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/54] [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/54] [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/54] [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/54] 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/54] [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/54] 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/54] [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/54] [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/54] 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 94230d928b1c1f43eb2c0949c8ce6116b8000fe0 Mon Sep 17 00:00:00 2001 From: Siarhei_Dzeraviannik Date: Sat, 16 Nov 2024 17:50:28 +0300 Subject: [PATCH 13/54] [Alert]: Added support for size theming --- changelog.md | 5 + epam-assets/theme/variables/6px_grid.scss | 11 ++ uui/components/overlays/Alert.module.scss | 132 +++++++++++++--------- uui/components/overlays/Alert.tsx | 33 +++--- uui/settings.ts | 7 ++ uui/settings.types.ts | 6 + 6 files changed, 123 insertions(+), 71 deletions(-) diff --git a/changelog.md b/changelog.md index d5a11b9028..c489411ef6 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,10 @@ # 5.*.* - **.**.2024 +**What's New** +* [Alert]: Added support for size theming + +# 5.*.* - **.**.2024 + **What's New** * [FlexRow][Breaking Change]: Only for `@epam/loveship` package. Now spacing default value works based on `columnGap` props. It shouldn't affect general cases, but previous spacing implementation require additional hack when it was needed to add negative margin value for container to remove corner paddings in multiline case. Now this hack should be removed, since `columnGap` implementation doesn't produce such bug for multiline. * [useTableState][Breaking Change]: columns prop is removed, since it's not needed now. Just remove it from `useTableState` provided props. diff --git a/epam-assets/theme/variables/6px_grid.scss b/epam-assets/theme/variables/6px_grid.scss index 68d983a429..ba6a694d0a 100644 --- a/epam-assets/theme/variables/6px_grid.scss +++ b/epam-assets/theme/variables/6px_grid.scss @@ -313,4 +313,15 @@ --uui-vertical-padding: 3px; } } + + .uui-alert { + &.uui-size-36 { + --uui-alert-indicator-border-width: 3px; + --uui-alert-gap-h: 12px; + --uui-alert-gap-v: 3px; + --uui-alert-padding-h: 9px; + --uui-alert-padding-v: 3px; + --uui-alert-caption-gap-h: 9px; + } + } } diff --git a/uui/components/overlays/Alert.module.scss b/uui/components/overlays/Alert.module.scss index 04312e5fbf..bcd07d710b 100644 --- a/uui/components/overlays/Alert.module.scss +++ b/uui/components/overlays/Alert.module.scss @@ -5,79 +5,99 @@ --uui-alert-bg: var(--uui-color-10); --uui-alert-border: var(--uui-color-50); --uui-alert-icon: var(--uui-color-50); - --uui-alert-border-radius: var(--uui-border-radius); - // - background-color: var(--uui-alert-bg); - border-left: 6px solid var(--uui-alert-border); - :global(.uui-text) { - color: var(--uui-alert-text); - } + //--uui-alert-font: var(--uui-font); + //--uui-alert-font-weight: var(--uui-font-weight, 400); - .icon-wrapper { - :global(.uui-icon) { - fill: var(--uui-alert-icon); - } - } -} + --uui-alert-min-height: var(--uui-size); + --uui-alert-min-width: 170px; // TODO: need clarify + --uui-alert-border-radius: var(--uui-border-radius); + --uui-alert-border-width: 0px; + --uui-alert-indicator-border-width: 6px; + --uui-alert-gap-h: 12px; + --uui-alert-gap-v: 0px; + --uui-alert-padding-h: 18px; + --uui-alert-padding-v: 9px; + --uui-alert-caption-gap-h: 12px; + --uui-alert-icon-size: var(--uui-icon-size); + //--uui-alert-line-height: var(--uui-line-height); + //--uui-alert-font-size: var(--uui-font-size); -.alert-wrapper { + // box-sizing: border-box; display: flex; align-items: center; overflow: hidden; - min-width: 170px; border-radius: var(--uui-alert-border-radius); -} + background-color: var(--uui-alert-bg); + border-width: var(--uui-alert-border-width); + border-inline-start: var(--uui-alert-indicator-border-width) solid var(--uui-alert-border); + padding-inline-start: calc(var(--uui-alert-padding-h) - var(--uui-alert-indicator-border-width)); + padding-inline-end: var(--uui-alert-padding-h); + padding-top: var(--uui-alert-padding-v); + padding-bottom: var(--uui-alert-padding-v); + min-height: var(--uui-alert-min-height); + min-width: var(--uui-alert-min-width); -.size-48 { - padding: 9px 18px 9px 12px; - min-height: 48px; + .main-path { + width: 100%; + display: flex; + column-gap: var(--uui-alert-gap-h); + } - @include scalable-icon-size(48); -} + .content-wrapper { + display: flex; + column-gap: var(--uui-alert-caption-gap-h); + width: 100%; + } -.size-36 { - padding: 3px 9px; - min-height: 36px; - border-left-width: 3px; + .content { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + column-gap: var(--uui-alert-gap-h); + row-gap: var(--uui-alert-gap-v); + width: 100%; + //font-family: var(--uui-alert-font); + //font-weight: var(--uui-alert-font-weight); + //line-height: var(--uui-alert-line-height); + //font-size: var(--uui-alert-font-size); + } - @include scalable-icon-size(36); -} + .action-wrapper { + display: flex; + align-items: center; + column-gap: var(--uui-alert-gap-h); + } -.icon-wrapper { - height: 100%; - margin-inline-end: 12px; -} + :global(.uui-text) { + color: var(--uui-alert-text); + } -.action-wrapper { - display: flex; - align-items: center; -} + svg { + height: var(--uui-alert-icon-size); + width: inherit; + } -.action-icon { - min-height: 30px; -} + .icon-wrapper { + height: 100%; -.action-link:not(:last-child) { - margin-inline-end: 12px; -} + :global(.uui-icon) { + fill: var(--uui-alert-icon); + } + } -.close-icon { - margin-inline-start: 17px; - min-height: 30px; - min-width: fit-content; - align-self: flex-start; -} + .icon { + min-height: calc(var(--uui-alert-min-height) - (2 * var(--uui-alert-padding-v)) - (2 * var(--uui-alert-border-width))); + } -.main-path { - width: 100%; - display: flex; + .close-icon { + min-height: calc(var(--uui-alert-min-height) - (2 * var(--uui-alert-padding-v)) - (2 * var(--uui-alert-border-width))); + min-width: fit-content; + align-self: flex-start; + } } -.content { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - width: 100%; -} + + diff --git a/uui/components/overlays/Alert.tsx b/uui/components/overlays/Alert.tsx index 58e0c3dce9..11fe0e09b8 100644 --- a/uui/components/overlays/Alert.tsx +++ b/uui/components/overlays/Alert.tsx @@ -2,12 +2,14 @@ import * as React from 'react'; import cx from 'classnames'; import { IHasChildren, IHasCX, Icon, IHasRawProps } from '@epam/uui-core'; import { IconContainer } from '@epam/uui-components'; -import { IconButton, LinkButton } from '../buttons'; +import { IconButton, LinkButton, LinkButtonProps } from '../buttons'; import { ReactComponent as SuccessIcon } from '@epam/assets/icons/notification-check-fill.svg'; import { ReactComponent as WarningIcon } from '@epam/assets/icons/notification-warning-fill.svg'; import { ReactComponent as ErrorIcon } from '@epam/assets/icons/notification-error-fill.svg'; import { ReactComponent as HintIcon } from '@epam/assets/icons/notification-info-fill.svg'; import { ReactComponent as CrossIcon } from '@epam/assets/icons/navigation-close-outline.svg'; +import { settings } from '../../settings'; + import css from './Alert.module.scss'; interface AlertNotificationAction { @@ -51,29 +53,30 @@ export const Alert = React.forwardRef((props, ref) = cx( 'uui-alert', css.root, - css.alertWrapper, props.color && `uui-color-${props.color}`, props.cx, - (props.size === '36' ? css.size36 : css.size48), + `uui-size-${props.size || settings.sizes.defaults.alert}`, ) } { ...props.rawProps } >
- {props.icon && ( -
- -
- )} -
- {props.children} - {props.actions && ( -
- {props.actions.map((action) => ( - - ))} +
+ {props.icon && ( +
+
)} +
+ {props.children} + {props.actions && ( +
+ {props.actions.map((action) => ( + + ))} +
+ )} +
{props.onClose && }
diff --git a/uui/settings.ts b/uui/settings.ts index c54a314bf3..49522d3566 100644 --- a/uui/settings.ts +++ b/uui/settings.ts @@ -3,6 +3,7 @@ import type { Settings } from './settings.types'; export const settings: Settings = { sizes: { defaults: { + alert: '48', badge: '36', button: '36', checkbox: '18', @@ -23,6 +24,12 @@ export const settings: Settings = { paginator: '30', rating: '18', }, + alert: { + action: { + 36: '24', + 48: '30', + }, + }, tag: { countIndicator: { 18: '12', diff --git a/uui/settings.types.ts b/uui/settings.types.ts index 431213abec..469b262327 100644 --- a/uui/settings.types.ts +++ b/uui/settings.types.ts @@ -1,4 +1,5 @@ interface DefaultSizes { + alert: string; badge: string; button: string; checkbox: string; @@ -35,6 +36,10 @@ interface UppercaseTextSize { uppercase: string; } +interface AlertSizes { + action: Sizes; +} + interface TagSizes { countIndicator: Sizes; } @@ -235,6 +240,7 @@ interface ModalSizes { interface SizesSettings { defaults: DefaultSizes; + alert: AlertSizes; tag: TagSizes; pickerInput: PickerInputSizes; rowAddons: RowAddonsSizes; From fbf6342c54b61da54413490572f975ab5c336e29 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 18 Nov 2024 13:36:58 +0100 Subject: [PATCH 14/54] [Demo]: fixed project table demo "Add task" action --- app/src/demo/tables/editableTable/ProjectTableDemo.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/demo/tables/editableTable/ProjectTableDemo.tsx b/app/src/demo/tables/editableTable/ProjectTableDemo.tsx index 0b035c6153..15cddc4187 100644 --- a/app/src/demo/tables/editableTable/ProjectTableDemo.tsx +++ b/app/src/demo/tables/editableTable/ProjectTableDemo.tsx @@ -135,7 +135,7 @@ export function ProjectTableDemo() { }, []); const insertTask = useCallback((position: DropPosition, relativeTask: Task | null = null, existingTask: Task | null = null) => { - const taskToInsert: Task = existingTask ? { ...existingTask, type: 'task' } : { id: lastId--, name: '', type: 'task' }; + const taskToInsert: Task = existingTask ? { ...existingTask, type: 'task' } : { id: lastId--, name: '', type: 'task', parentId: null }; const task: Task = setTaskInsertPosition(taskToInsert, relativeTask, position, treeRef.current); setValue((currentValue) => { @@ -153,9 +153,11 @@ export function ProjectTableDemo() { } } - let currentItems = currentValue.items - .set(task.id, task) - .set(parentTask.id, parentTask); + let currentItems = currentValue.items.set(task.id, task); + + if (parentTask) { + currentValue.items.set(parentTask.id, parentTask); + } if (prevParentTask !== null && prevParentTask !== NOT_FOUND_RECORD) { currentItems = currentItems.set(prevParentTask.id, prevParentTask); From 71e225c9b908f8d5910c6f30523a2113a43fd65d Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Wed, 20 Nov 2024 13:16:35 +0100 Subject: [PATCH 15/54] Update AdaptivePanel doc --- .../docs/content/examples-adaptivePanel-Basic.json | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/public/docs/content/examples-adaptivePanel-Basic.json b/public/docs/content/examples-adaptivePanel-Basic.json index 2e9017bcd3..399403e3e0 100644 --- a/public/docs/content/examples-adaptivePanel-Basic.json +++ b/public/docs/content/examples-adaptivePanel-Basic.json @@ -60,17 +60,24 @@ }, { "data": {}, - "type": "paragraph", + "type": "note-error", "children": [ { - "text": "Additionally, the AdaptivePanel has an " + "text": "Note: If you need to add margins between items, use the " }, { "text": "itemsGap", "uui-richTextEditor-code": true }, { - "text": " property used to define the spacing between the items within it." + "text": " prop on the " + }, + { + "text": "AdaptivePanel", + "uui-richTextEditor-code": true + }, + { + "text": " instead of applying CSS margins to each item. This is because margin values cannot be accounted when calculating the item's width and must be explicitly added." } ] } From e0aa9596ebec75b8d0a77bf8c76885c1c4bc65d7 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Wed, 20 Nov 2024 15:05:12 +0100 Subject: [PATCH 16/54] [PickerInput]: fixed unnecessary api calls on body open with `minCharsToSearch` prop and search in body. --- changelog.md | 7 ++++ .../src/pickers/hooks/usePickerInput.ts | 4 ++- .../pickers/__tests__/PickerInput.test.tsx | 35 +++++++++++++------ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index a06210b3ea..d21a8f5fbb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,10 @@ +# 5.xx.xx - xx.xx.2024 + +**What's New** + +**What's Fixed** +* [PickerInput]: fixed unnecessary api calls on body open with `minCharsToSearch` prop and search in body. + # 5.11.0 - 15.11.2024 **What's New** diff --git a/uui-components/src/pickers/hooks/usePickerInput.ts b/uui-components/src/pickers/hooks/usePickerInput.ts index 876aa537ad..bc4a59c039 100644 --- a/uui-components/src/pickers/hooks/usePickerInput.ts +++ b/uui-components/src/pickers/hooks/usePickerInput.ts @@ -52,7 +52,9 @@ export function usePickerInput(props: UsePickerInputProps (props.shouldShowBody ?? defaultShouldShowBody)(); - const showSelectedOnly = !shouldShowBody() || pickerInputState.showSelected; + const shouldLoadList = () => isSearchLongEnough() && shouldShowBody(); + + const showSelectedOnly = !shouldLoadList() || pickerInputState.showSelected; const picker = usePicker>({ ...props, showSelectedOnly }, pickerInputState); const { diff --git a/uui/components/pickers/__tests__/PickerInput.test.tsx b/uui/components/pickers/__tests__/PickerInput.test.tsx index 1bdf1ff2f1..39bd35a4ad 100644 --- a/uui/components/pickers/__tests__/PickerInput.test.tsx +++ b/uui/components/pickers/__tests__/PickerInput.test.tsx @@ -1,5 +1,5 @@ import React, { ReactNode } from 'react'; -import { ArrayDataSource, CascadeSelection } from '@epam/uui-core'; +import { ArrayDataSource, CascadeSelection, LazyDataSource } from '@epam/uui-core'; import { renderSnapshotWithContextAsync, setupComponentForTest, screen, within, fireEvent, waitFor, userEvent, PickerInputTestObject, act, delayAct, @@ -1411,25 +1411,20 @@ describe('PickerInput', () => { console.error = prevConsoleError; }); - it('should render message in body for not enough chars in search while using minCharsToSearch', async () => { - const mockEmptyDS = new ArrayDataSource({ - items: [], + it('should not load items while search less than minCharsToSearch', async () => { + const apiMock = jest.fn().mockResolvedValue([]); + + const mockEmptyDS = new LazyDataSource({ + api: apiMock, getId: ({ id }) => id, }); - const customText = 'Custom Text or Component'; - const { dom } = await setupPickerInputForTest({ value: undefined, selectionMode: 'multi', minCharsToSearch: 3, searchPosition: 'body', dataSource: mockEmptyDS, - renderNotFound: () => ( - - {customText} - - ), getSearchFields: (item) => [item!.level], }); @@ -1443,6 +1438,24 @@ describe('PickerInput', () => { const notFound = within(await screen.findByRole('dialog')); expect(notFound.getByText('Type search to load items')).toBeInTheDocument(); }); + + expect(apiMock).toBeCalledTimes(0); + + const bodyInput = within(dialog).getByPlaceholderText('Search'); + + jest.useFakeTimers(); + fireEvent.change(bodyInput, { target: { value: '1234' } }); + act(() => { + jest.runAllTimers(); + }); + jest.useRealTimers(); + + await waitFor(async () => { + const notFound = within(await screen.findByRole('dialog')); + expect(notFound.getByText('No records found')).toBeInTheDocument(); + }); + + expect(apiMock).toBeCalledTimes(1); }); it('should render custom renderEmpty', async () => { From 14ab0d19066317bdf450a091a0aba18919804863 Mon Sep 17 00:00:00 2001 From: Aleh Makaranka <29537473+cpoftea@users.noreply.github.com> Date: Thu, 21 Nov 2024 18:50:55 +0400 Subject: [PATCH 17/54] Force rerender on image load to recalculate caption visibility --- changelog.md | 1 + uui-editor/src/plugins/imagePlugin/ImageElement.tsx | 3 +++ 2 files changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index d21a8f5fbb..3e731be9b9 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ **What's Fixed** * [PickerInput]: fixed unnecessary api calls on body open with `minCharsToSearch` prop and search in body. +* [RTE]: fixed image caption not being visible when RTE initially in readonly mode # 5.11.0 - 15.11.2024 diff --git a/uui-editor/src/plugins/imagePlugin/ImageElement.tsx b/uui-editor/src/plugins/imagePlugin/ImageElement.tsx index 1d2978b768..7bc7604dd4 100644 --- a/uui-editor/src/plugins/imagePlugin/ImageElement.tsx +++ b/uui-editor/src/plugins/imagePlugin/ImageElement.tsx @@ -15,6 +15,7 @@ import { Resizable, ResizeHandle } from '../../implementation/Resizable'; import { PlateImgAlign, TImageElement } from './types'; import { Caption, CaptionTextarea } from '@udecode/plate-caption'; import { ResizableProvider } from '@udecode/plate-resizable'; +import { useForceUpdate } from '@epam/uui-core'; interface ImageElementProps extends PlateElementProps { align?: PlateImgAlign; @@ -28,6 +29,7 @@ export const ImageElement = withHOC(ResizableProvider, ({ align, ...props }: ImageElementProps) => { + const forceUpdate = useForceUpdate(); const { children, nodeProps } = props; const focused = useFocused(); @@ -80,6 +82,7 @@ export const ImageElement = withHOC(ResizableProvider, ({ visible && css.selectedImage, // for mobile nodeProps?.className, ) } + onLoad={ () => forceUpdate() } /> {!readOnly && ( Date: Thu, 21 Nov 2024 17:32:26 +0100 Subject: [PATCH 18/54] Add readonly RTE to sandbox. Add caption image for initial content. --- .../RichTextEditorDemo.module.scss | 5 + .../RTE-readonly/RichTextEditorDemo.tsx | 101 + app/src/sandbox/SandboxPage.tsx | 4 +- uui-docs/src/demoData/slateInitialValue.ts | 1955 +++++++---------- 4 files changed, 862 insertions(+), 1203 deletions(-) create mode 100644 app/src/sandbox/RTE-readonly/RichTextEditorDemo.module.scss create mode 100644 app/src/sandbox/RTE-readonly/RichTextEditorDemo.tsx diff --git a/app/src/sandbox/RTE-readonly/RichTextEditorDemo.module.scss b/app/src/sandbox/RTE-readonly/RichTextEditorDemo.module.scss new file mode 100644 index 0000000000..49e7721e90 --- /dev/null +++ b/app/src/sandbox/RTE-readonly/RichTextEditorDemo.module.scss @@ -0,0 +1,5 @@ +.container { + width: 60vw; + max-width: 1024px; + margin: 24px auto; +} diff --git a/app/src/sandbox/RTE-readonly/RichTextEditorDemo.tsx b/app/src/sandbox/RTE-readonly/RichTextEditorDemo.tsx new file mode 100644 index 0000000000..492edbbad1 --- /dev/null +++ b/app/src/sandbox/RTE-readonly/RichTextEditorDemo.tsx @@ -0,0 +1,101 @@ +import * as React from 'react'; +import { + SlateEditor, + defaultPlugins, + imagePlugin, + videoPlugin, + attachmentPlugin, + toDoListPlugin, + baseMarksPlugin, + linkPlugin, + iframePlugin, + notePlugin, + separatorPlugin, + uploadFilePlugin, + tablePlugin, + quotePlugin, + colorPlugin, + superscriptPlugin, + headerPlugin, + listPlugin, + placeholderPlugin, + codeBlockPlugin, + EditorValue, +} from '@epam/uui-editor'; +import { svc } from '../../services'; +import { demoData } from '@epam/uui-docs'; +import css from './RichTextEditorDemo.module.scss'; +import { ErrorNotification, Text } from '@epam/uui'; +import { FileUploadResponse } from '@epam/uui-core'; + +interface SlateEditorBasicExampleState { + value: EditorValue; +} + +export class RichTextEditorDemoReadonly extends React.Component { + state: SlateEditorBasicExampleState = { + value: demoData.slateInitialValue, + }; + + onChange = (value: EditorValue) => { + this.setState({ value: value }); + }; + + uploadFile = (file: File): Promise => { + return svc.uuiApi.uploadFile('/upload/uploadFileMock', file, {}) + .catch((res) => { + svc.uuiNotifications.show((props) => + { res.error.message }).catch(() => {}); + return Promise.reject(res); + }); + }; + + plugins = [ + ...defaultPlugins, + ...baseMarksPlugin(), + headerPlugin(), + colorPlugin(), + superscriptPlugin(), + listPlugin(), + toDoListPlugin(), + quotePlugin(), + linkPlugin(), + notePlugin(), + uploadFilePlugin({ uploadFile: this.uploadFile }), + attachmentPlugin(), + imagePlugin(), + videoPlugin(), + iframePlugin(), + separatorPlugin(), + tablePlugin(), + placeholderPlugin({ + items: [ + { + name: 'Name', + field: 'name', + }, + { + name: 'Email', + field: 'email', + }, + ], + }), + codeBlockPlugin(), + ]; + + render() { + return ( +
+ +
+ ); + } +} diff --git a/app/src/sandbox/SandboxPage.tsx b/app/src/sandbox/SandboxPage.tsx index f47c296fba..06b582b922 100644 --- a/app/src/sandbox/SandboxPage.tsx +++ b/app/src/sandbox/SandboxPage.tsx @@ -23,6 +23,7 @@ import { ReactQueryLocationsTable } from './reactQueryLocationsTable'; import { ProjectTableDemo } from './editableTable'; import { RtlExample } from './rtl/Rtl-example'; import { DemoForm } from './rtl/form/DemoForm'; +import { RichTextEditorDemoReadonly } from './RTE-readonly/RichTextEditorDemo'; export function SandboxPage() { const items = useMemo( @@ -41,7 +42,8 @@ export function SandboxPage() { { id: 'SkillsBatteryPopover', name: 'Skills', component: Skills }, { id: 'TableCellsStylesSandbox', name: 'Table Cells/Rows styles', component: TableCellsStylesSandbox }, { id: 'AdaptivePanel', name: 'Adaptive panel', component: AdaptivePanelDemo }, - { id: 'RTEDemo', name: 'RTE Demo', component: RichTextEditorDemo }, + { id: 'RTEDemo', name: 'RTE Contents', component: RichTextEditorDemo }, + { id: 'RTE-readonly', name: 'RTE Readonly', component: RichTextEditorDemoReadonly }, { id: 'tokens', name: 'Tokens' }, { parentId: 'tokens', id: 'tokensPalette', name: 'Palette', component: PalettePage }, { id: 'rtl-example', name: 'Rtl-example', component: RtlExample }, diff --git a/uui-docs/src/demoData/slateInitialValue.ts b/uui-docs/src/demoData/slateInitialValue.ts index a7101d8206..c49873634d 100644 --- a/uui-docs/src/demoData/slateInitialValue.ts +++ b/uui-docs/src/demoData/slateInitialValue.ts @@ -1,1353 +1,904 @@ -export const slateInitialValue = { - object: 'value', - document: { - object: 'document', +export const slateInitialValue = [ + { + type: 'uui-richTextEditor-header-1', data: {}, - nodes: [ + children: [ { - object: 'block', - type: 'uui-richTextEditor-header-1', + text: 'Rich Text Editor', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'uui-richTextEditor-header-3', + data: {}, + children: [ + { + text: 'Introduction', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: '@epam/uui-editor package contains a full-featured Rich Text Editor, based on open-source ', + 'uui-richTextEditor-span-mark': true, + }, + { + type: 'link', + data: {}, + url: 'https://www.slatejs.org/', + children: [ + { + text: 'slate.js', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + text: " library. Slate.JS is a framework to build editors, and it's highly configurable with plugins. In UUI, we picked and tuned dozen of plugins, build several plugins ourselves, added common styles and UX on top of it. One can pick from our default set of plugins, or even introduce new, app-specific plugins, on top.", + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: 'Unlikely to most Rich-Text editors, Slate uses JSON data model instead of HTML, which allows it to embed any entities, like arbitrary React components. For example, this checkbox, is a custom react component (check ', + 'uui-richTextEditor-span-mark': true, + }, + { + type: 'link', + data: {}, + url: 'https://github.com/epam/UUI/blob/main/uui-editor/src/plugins/toDoListPlugin/ToDoItem.tsx', + children: [ + { + text: 'source here', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + text: '):', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'toDoItem', + data: { + checked: false, + }, + children: [ + { + text: ' An item', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: 'We include HTML to Slate JSON converter, which is also used to convert pasted HTML.', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'uui-richTextEditor-header-2', + data: { + checked: false, + }, + children: [ + { + text: 'Out of the box components', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'uui-richTextEditor-header-3', + data: { + checked: false, + }, + children: [ + { + text: 'Basic layout', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: 'We support inline text styles: ', + 'uui-richTextEditor-span-mark': true, + }, + { + text: 'bold', + 'uui-richTextEditor-span-mark': true, + 'uui-richTextEditor-bold': true, + }, + { + text: ', ', + 'uui-richTextEditor-span-mark': true, + }, + { + text: 'italic', + 'uui-richTextEditor-span-mark': true, + 'uui-richTextEditor-italic': true, + }, + { + text: ', ', + 'uui-richTextEditor-span-mark': true, + }, + { + text: 'underlined,', + 'uui-richTextEditor-span-mark': true, + 'uui-richTextEditor-underlined': true, + }, + { + text: ' several UUI-friendly text colors: ', + 'uui-richTextEditor-span-mark': true, + }, + { + text: 'red', + color: '#FF4E33', + 'uui-richTextEditor-span-mark': true, + }, + { + text: ', ', + 'uui-richTextEditor-span-mark': true, + }, + { + text: 'yellow', + color: '#FFA21D', + 'uui-richTextEditor-span-mark': true, + }, + { + text: ', and ', + 'uui-richTextEditor-span-mark': true, + }, + { + text: 'green.', + color: '#9BC837', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: 'Numbered lists:', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'ordered-list', + data: {}, + children: [ + { + type: 'list-item', data: {}, - nodes: [ + children: [ { - object: 'text', - text: 'Rich Text Editor', - marks: [ + type: 'list-item-child', + data: { + checked: false, + }, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, + text: "In edit mode, we detect '1.' and start list automatically", + 'uui-richTextEditor-span-mark': true, }, ], }, ], - }, { - object: 'block', - type: 'uui-richTextEditor-header-3', + }, + { + type: 'list-item', data: {}, - nodes: [ + children: [ { - object: 'text', - text: 'Introduction', - marks: [ + type: 'list-item-child', + data: { + checked: false, + }, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, + text: "You can use 'tab' / 'shift/tab' to indent the list", + 'uui-richTextEditor-span-mark': true, }, ], }, ], - }, { - object: 'block', - type: 'paragraph', + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: 'Bullet lists:', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'unordered-list', + data: {}, + children: [ + { + type: 'list-item', data: {}, - nodes: [ + children: [ { - object: 'text', - text: '@epam/uui-editor package contains a full-featured Rich Text Editor, based on open-source ', - marks: [ + type: 'list-item-child', + data: { + checked: false, + }, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, + text: "Type '- ' to start the list", + 'uui-richTextEditor-span-mark': true, }, ], - }, { - object: 'inline', - type: 'link', + }, + ], + }, + { + type: 'list-item', + data: {}, + children: [ + { + type: 'list-item-child', data: { - url: 'https://www.slatejs.org/', + checked: false, }, - nodes: [ + children: [ { - object: 'text', - text: 'slate.js', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], + text: "You can create multi-level lists with 'tab' / 'shift+tab'. Example:", + 'uui-richTextEditor-span-mark': true, }, ], - }, { - object: 'text', - text: " library. Slate.JS is a framework to build editors, and it's highly configurable with plugins. In UUI, we picked and tuned dozen of plugins, build several plugins ourselves, added common styles and UX on top of it. One can pick from our default set of plugins, or even introduce new, app-specific plugins, on top.", - marks: [ + }, + { + type: 'unordered-list', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'list-item', data: {}, + children: [ + { + type: 'list-item-child', + data: { + checked: false, + }, + children: [ + { + text: 'Level 2', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'unordered-list', + data: {}, + children: [ + { + type: 'list-item', + data: {}, + children: [ + { + type: 'list-item-child', + data: { + checked: false, + }, + children: [ + { + text: 'Level 3', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + ], + }, + ], + }, + ], }, ], }, ], - }, { - object: 'block', - type: 'paragraph', + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: "There's also support 3 levels of headers, hyperlinks, superscript, and more.", + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'uui-richTextEditor-header-3', + data: { + checked: false, + }, + children: [ + { + text: 'Embedded content', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: 'Files can be dropped directly into the editor. You can embed images (align and resizing is supported):', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'image', + data: { + size: 77236, + path: '/static/uploads/blue-orange.jpg', + fileName: 'blue-orange.jpg', + name: 'blue-orange.jpg', + type: 'image', + id: '100500', + }, + url: '/static/uploads/blue-orange.jpg', + align: 'center', + width: 800, + height: 417, + children: [ + { + text: '', + 'uui-richTextEditor-span-mark': true, + }, + ], + caption: [ + { + text: 'Image caption', + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: 'Video:', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'iframe', + data: {}, + url: 'https://www.youtube.com/embed/5qap5aO4i9A', + children: [ + { + text: '', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: { + checked: false, + }, + children: [ + { + text: 'Arbitrary attachments:', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'attachment', + data: { + path: '/static/uploads/DemoExcelAttachment.xlsx', + name: 'DemoExcelAttachment.xlsx', + size: 8669, + id: '100500', + type: 'attachment', + fileName: 'DemoExcelAttachment.xlsx', + extension: 'xlsx', + }, + url: '/static/uploads/DemoExcelAttachment.xlsx', + children: [ + { + text: '', + 'uui-richTextEditor-span-mark': true, + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: 'You can also embed any arbitrary content, like PDF files, directly into the document, inside IFrame.', + }, + ], + }, + { + type: 'uui-richTextEditor-header-3', + data: {}, + children: [ + { + text: 'Tables', + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: 'We provide a powerful tables plugin:', + }, + ], + }, + { + type: 'table', + data: {}, + colSizes: [ + 130, + 200, + 200, + 183, + 161, + ], + children: [ + { + type: 'table_row', data: {}, - nodes: [ + children: [ { - object: 'text', - text: 'Unlikely to most Rich-Text editors, Slate uses JSON data model instead of HTML, which allows it to embed any entities, like arbitrary React components. For example, this checkbox, is a custom react component (check ', - marks: [ + type: 'table_header_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'Department', + }, + ], }, ], - }, { - object: 'inline', - type: 'link', - data: { - url: 'https://github.com/epam/UUI/blob/main/uui-editor/src/plugins/toDoListPlugin/ToDoItem.tsx', - }, - nodes: [ + }, + { + type: 'table_header_cell', + data: {}, + colSpan: 2, + children: [ { - object: 'text', - text: 'source here', - marks: [ + type: 'paragraph', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, + text: 'Name & Title', }, ], }, ], - }, { - object: 'text', - text: '):', - marks: [ + }, + { + type: 'table_header_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'Tasks', + }, + ], }, ], }, ], - }, { - object: 'block', - type: 'toDoItem', - data: { - checked: false, - }, - nodes: [ + }, + { + type: 'table_row', + data: {}, + children: [ { - object: 'text', - text: ' An item', - marks: [ + type: 'table_cell', + data: {}, + rowSpan: 2, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'RnD', + }, + ], }, ], }, - ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ { - object: 'text', - text: 'We include HTML to Slate JSON converter, which is also used to convert pasted HTML.', - marks: [ + type: 'table_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'Alice Green', + }, + ], }, ], }, - ], - }, { - object: 'block', - type: 'uui-richTextEditor-header-2', - data: { - checked: false, - }, - nodes: [ { - object: 'text', - text: 'Out of the box components', - marks: [ + type: 'table_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'Design', + }, + ], }, ], }, - ], - }, { - object: 'block', - type: 'uui-richTextEditor-header-3', - data: { - checked: false, - }, - nodes: [ { - object: 'text', - text: 'Basic layout', - marks: [ + type: 'table_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'Ok', + color: '#9BC837', + 'uui-richTextEditor-span-mark': true, + 'uui-richTextEditor-bold': true, + }, + ], }, ], }, ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ + }, + { + type: 'table_row', + data: {}, + children: [ { - object: 'text', - text: 'We support inline text styles: ', - marks: [ + type: 'table_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'Bob Blue', + }, + ], }, ], - }, { - object: 'text', - text: 'bold', - marks: [ + }, + { + type: 'table_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, { - object: 'mark', - type: 'uui-richTextEditor-bold', + type: 'paragraph', data: {}, - }, - ], - }, { - object: 'text', - text: ', ', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, { - object: 'text', - text: 'italic', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, { - object: 'mark', - type: 'uui-richTextEditor-italic', - data: {}, - }, - ], - }, { - object: 'text', - text: ', ', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, { - object: 'text', - text: 'underlined,', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, { - object: 'mark', - type: 'uui-richTextEditor-underlined', - data: {}, - }, - ], - }, { - object: 'text', - text: ' several UUI-friendly text colors: ', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, { - object: 'text', - text: 'red', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: { - style: { - color: '#FF4E33', - }, - }, - }, - ], - }, { - object: 'text', - text: ', ', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, { - object: 'text', - text: 'yellow', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: { - style: { - color: '#FFA21D', - }, - }, - }, - ], - }, { - object: 'text', - text: ', and ', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, { - object: 'text', - text: 'green.', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: { - style: { - color: '#9BC837', - }, - }, + children: [ + { + text: 'Developer', + }, + ], }, ], }, - ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ { - object: 'text', - text: 'Numbered lists:', - marks: [ + type: 'table_cell', + data: {}, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-span-mark', + type: 'paragraph', data: {}, + children: [ + { + text: 'Ok', + color: '#9BC837', + 'uui-richTextEditor-span-mark': true, + 'uui-richTextEditor-bold': true, + }, + ], }, ], }, ], - }, { - object: 'block', - type: 'ordered-list', + }, + { + type: 'table_row', data: {}, - nodes: [ + children: [ { - object: 'block', - type: 'list-item', + type: 'table_cell', data: {}, - nodes: [ + rowSpan: 1, + children: [ { - object: 'block', - type: 'list-item-child', - data: { - checked: false, - }, - nodes: [ + type: 'paragraph', + data: {}, + children: [ { - object: 'text', - text: "In edit mode, we detect '1.' and start list automatically", - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], + text: 'People', }, ], }, ], - }, { - object: 'block', - type: 'list-item', + }, + { + type: 'table_cell', data: {}, - nodes: [ + rowSpan: 1, + children: [ { - object: 'block', - type: 'list-item-child', - data: { - checked: false, - }, - nodes: [ + type: 'paragraph', + data: {}, + children: [ { - object: 'text', - text: "You can use 'tab' / 'shift/tab' to indent the list", - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], + text: 'Ann Chovey', }, ], }, ], }, - ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: 'Bullet lists:', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'unordered-list', - data: {}, - nodes: [ { - object: 'block', - type: 'list-item', + type: 'table_cell', data: {}, - nodes: [ + rowSpan: 1, + children: [ { - object: 'block', - type: 'list-item-child', - data: { - checked: false, - }, - nodes: [ + type: 'paragraph', + data: {}, + children: [ { - object: 'text', - text: "Type '- ' to start the list", - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], + text: 'Primary HR', }, ], }, ], - }, { - object: 'block', - type: 'list-item', + }, + { + type: 'table_cell', data: {}, - nodes: [ + rowSpan: 1, + children: [ { - object: 'block', - type: 'list-item-child', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: "You can create multi-level lists with 'tab' / 'shift+tab'. Example:", - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'unordered-list', + type: 'paragraph', data: {}, - nodes: [ + children: [ { - object: 'block', - type: 'list-item', - data: {}, - nodes: [ - { - object: 'block', - type: 'list-item-child', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: 'Level 2', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'unordered-list', - data: {}, - nodes: [ - { - object: 'block', - type: 'list-item', - data: {}, - nodes: [ - { - object: 'block', - type: 'list-item-child', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: 'Level 3', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], + text: 'In progress', + color: '#8A7CBB', + 'uui-richTextEditor-span-mark': true, + 'uui-richTextEditor-bold': true, }, ], }, ], }, ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: "There's also support 3 levels of headers, hyperlinks, superscript, and more.", - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'uui-richTextEditor-header-3', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: 'Embedded content', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: 'Files can be dropped directly into the editor. You can embed images (align and resizing is supported):', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'image', - data: { - size: 77236, - src: '/static/uploads/blue-orange.jpg', - path: '/static/uploads/blue-orange.jpg', - align: 'align-center', - fileName: 'blue-orange.jpg', - name: 'blue-orange.jpg', - type: 'image', - id: '100500', - imageSize: { - width: 800, - height: 417, - }, - }, - nodes: [ - { - object: 'text', - text: '', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: 'Video:', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'iframe', - data: { - src: 'https://www.youtube.com/embed/5qap5aO4i9A', - }, - nodes: [ - { - object: 'text', - text: '', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: { - checked: false, - }, - nodes: [ - { - object: 'text', - text: 'Arbitrary attachments:', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'attachment', - data: { - path: '/static/uploads/DemoExcelAttachment.xlsx', - name: 'DemoExcelAttachment.xlsx', - size: 8669, - id: '100500', - type: 'attachment', - src: '/static/uploads/DemoExcelAttachment.xlsx', - fileName: 'DemoExcelAttachment.xlsx', - extension: 'xlsx', - }, - nodes: [ - { - object: 'text', - text: '', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: {}, - }, - ], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'You can also embed any arbitrary content, like PDF files, directly into the document, inside IFrame.', - marks: [], - }, - ], - }, { - object: 'block', - type: 'uui-richTextEditor-header-3', - data: {}, - nodes: [ - { - object: 'text', - text: 'Tables', - marks: [], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'We provide a powerful tables plugin:', - marks: [], - }, - ], - }, { - object: 'block', - type: 'paragraph', + }, + { + type: 'table_row', data: {}, - nodes: [ + children: [ { - object: 'block', - type: 'table', - data: { - cellSizes: [ - 130, 200, 200, 183, 161, - ], - }, - nodes: [ - { - object: 'block', - type: 'table_row', - data: {}, - nodes: [ - { - object: 'block', - type: 'table_header_cell', - data: { }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Department', - marks: [], - }, - - ], - }, - ], - }, - { - object: 'block', - type: 'table_header_cell', - data: { colSpan: 2 }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Name', - marks: [], - }, - { - object: 'text', - text: ' & ', - marks: [], - }, - { - object: 'text', - text: 'Title', - marks: [], - }, - ], - }, - ], - }, - - { - object: 'block', - type: 'table_header_cell', - data: {}, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Tasks', - marks: [], - }, - ], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_row', - data: {}, - nodes: [ - { - object: 'block', - type: 'table_cell', - data: { rowSpan: 2 }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'RnD', - marks: [], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_cell', - data: {}, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Alice Green', - marks: [], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_cell', - data: {}, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Design', - marks: [], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_cell', - data: {}, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Ok', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: { - style: { - color: '#9BC837', - }, - }, - }, { - object: 'mark', - type: 'uui-richTextEditor-bold', - data: {}, - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_row', - data: {}, - nodes: [ - { - object: 'block', - type: 'table_cell', - data: {}, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Bob Blue', - marks: [], - }, - ], - }, - ], - }, { - object: 'block', - type: 'table_cell', - data: {}, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Developer', - marks: [], - }, - ], - }, - ], - }, { - object: 'block', - type: 'table_cell', - data: {}, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Ok', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: { - style: { - color: '#9BC837', - }, - }, - }, { - object: 'mark', - type: 'uui-richTextEditor-bold', - data: {}, - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_row', - data: {}, - nodes: [ - { - object: 'block', - type: 'table_cell', - data: { rowSpan: 1 }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'People', - marks: [], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_cell', - data: { rowSpan: 1 }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Ann Chovey', - marks: [], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_cell', - data: { rowSpan: 1 }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Primary HR', - marks: [], - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_cell', - data: { rowSpan: 1 }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'In progress', - marks: [ - { - object: 'mark', - type: 'uui-richTextEditor-span-mark', - data: { - style: { - color: '#8A7CBB', - }, - }, - }, { - object: 'mark', - type: 'uui-richTextEditor-bold', - data: {}, - }, - ], - }, - ], - }, - ], - }, - ], - }, + type: 'table_cell', + data: {}, + children: [ { - object: 'block', - type: 'table_row', + type: 'paragraph', data: {}, - nodes: [ + children: [ { - object: 'block', - type: 'table_cell', - data: { }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: '', - }, - ], - }, - ], - }, - { - object: 'block', - type: 'table_cell', - data: { colSpan: 3 }, - nodes: [ - { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Footer', - marks: [], - }, - ], - }, - ], + text: '', }, ], }, ], }, - ], - }, { - object: 'block', - type: 'uui-richTextEditor-header-3', - data: {}, - nodes: [ - { - object: 'text', - text: 'Placeholders:', - marks: [], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Allows to insert ', - marks: [], - }, { - object: 'inline', - type: 'placeholder', - data: { - name: 'Placeholder', - field: 'placeholder', - }, - nodes: [ - { - object: 'text', - text: '', - marks: [], - }, - ], - }, { - object: 'text', - text: " into text. Can be used for editing templates, for example for emails. Placeholders can be then replaced with real values programmatically (currently that's done by some apps in back-end code).", - marks: [], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: '', - marks: [], - }, - ], - }, { - object: 'block', - type: 'uui-richTextEditor-header-2', - data: {}, - nodes: [ - { - object: 'text', - text: 'Misc features', - marks: [], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Highlighted blocks:', - marks: [], - }, - ], - }, { - object: 'block', - type: 'note-error', - data: {}, - nodes: [ { - object: 'text', - text: 'Danger!', - marks: [ + type: 'table_cell', + data: {}, + colSpan: 3, + children: [ { - object: 'mark', - type: 'uui-richTextEditor-bold', + type: 'paragraph', data: {}, + children: [ + { + text: 'Footer', + }, + ], }, ], }, ], - }, { - object: 'block', - type: 'note-link', - data: {}, - nodes: [ - { - object: 'text', - text: 'Info', - marks: [], - }, - ], - }, { - object: 'block', - type: 'note-warning', - data: {}, - nodes: [ - { - object: 'text', - text: 'Warning', - marks: [], - }, - ], - }, { - object: 'block', - type: 'note-quote', - data: {}, - nodes: [ - { - object: 'text', - text: 'Side note', - marks: [], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ - { - object: 'text', - text: 'Splitter:', - marks: [], - }, - ], - }, { - object: 'block', - type: 'separatorBLock', - data: {}, - nodes: [ - { - object: 'text', - text: '', - marks: [], - }, - ], - }, { - object: 'block', - type: 'paragraph', - data: {}, - nodes: [ + }, + ], + }, + { + type: 'uui-richTextEditor-header-3', + data: {}, + children: [ + { + text: 'Placeholders:', + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: 'Allows to insert ', + }, + { + type: 'placeholder', + data: { + name: 'Placeholder', + field: 'placeholder', + }, + children: [ { - object: 'text', text: '', - marks: [], }, ], }, + { + text: " into text. Can be used for editing templates, for example for emails. Placeholders can be then replaced with real values programmatically (currently that's done by some apps in back-end code).", + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: '', + }, + ], + }, + { + type: 'uui-richTextEditor-header-2', + data: {}, + children: [ + { + text: 'Misc features', + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: 'Highlighted blocks:', + }, + ], + }, + { + type: 'note-error', + data: {}, + children: [ + { + text: 'Danger!', + 'uui-richTextEditor-bold': true, + }, + ], + }, + { + type: 'note-link', + data: {}, + children: [ + { + text: 'Info', + }, + ], + }, + { + type: 'note-warning', + data: {}, + children: [ + { + text: 'Warning', + }, + ], + }, + { + type: 'note-quote', + data: {}, + children: [ + { + text: 'Side note', + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: 'Splitter:', + }, + ], + }, + { + type: 'separatorBLock', + data: {}, + children: [ + { + text: '', + }, + ], + }, + { + type: 'paragraph', + data: {}, + children: [ + { + text: '', + }, ], }, -} as any; +] as any; From 7629332e862258aefb4e84cda170680136e4bbd6 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Thu, 21 Nov 2024 17:58:00 +0100 Subject: [PATCH 19/54] [DatePicker]: fixed body close in date picker input scrolled out from view --- changelog.md | 3 ++- uui-components/src/overlays/Dropdown.tsx | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index 3e731be9b9..fc6ca4bae0 100644 --- a/changelog.md +++ b/changelog.md @@ -3,8 +3,9 @@ **What's New** **What's Fixed** -* [PickerInput]: fixed unnecessary api calls on body open with `minCharsToSearch` prop and search in body. +* [PickerInput]: fixed unnecessary api calls on body open with `minCharsToSearch` prop and search in body * [RTE]: fixed image caption not being visible when RTE initially in readonly mode +* [DatePicker]: fixed body close if date picker input scrolled out from view # 5.11.0 - 15.11.2024 diff --git a/uui-components/src/overlays/Dropdown.tsx b/uui-components/src/overlays/Dropdown.tsx index 467291546c..1e62b644d9 100644 --- a/uui-components/src/overlays/Dropdown.tsx +++ b/uui-components/src/overlays/Dropdown.tsx @@ -264,7 +264,6 @@ export class Dropdown extends React.Component { if (isReferenceHidden && this.props.closeBodyOnTogglerHidden !== false && this.isOpened()) { // Yes, we know that it's hack and we can perform setState in render, but we don't have other way to do it in this case setTimeout(() => this.handleOpenedChange(false), 0); - return null; } // @ts-ignore From a42f355c9d69f999a01fb157b074c246df77fc88 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 25 Nov 2024 12:36:40 +0100 Subject: [PATCH 20/54] update bundle sizes --- uui-build/config/bundleSizeBaseLine.json | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/uui-build/config/bundleSizeBaseLine.json b/uui-build/config/bundleSizeBaseLine.json index aa68d1186e..076df6afc6 100644 --- a/uui-build/config/bundleSizeBaseLine.json +++ b/uui-build/config/bundleSizeBaseLine.json @@ -1,62 +1,62 @@ { - "version": "5.10.0", - "timestamp": "2024-10-15", + "version": "5.11.0", + "timestamp": "2024-11-22", "sizes": { "templateApp": { - "css": 300045, - "js": 478744 + "css": 303125, + "js": 482762 }, "@epam/app": { - "css": 678966, - "js": 5033790 + "css": 731357, + "js": 5035508 }, "@epam/draft-rte": { - "css": 9771, - "js": 45292 + "css": 9782, + "js": 45296 }, "@epam/electric": { "css": 2275, - "js": 2408 + "js": 2416 }, "@epam/promo": { - "css": 47627, - "js": 10896 + "css": 47140, + "js": 9424 }, "@epam/uui-extra": { "css": 0, "js": 213 }, "@epam/loveship": { - "css": 53440, - "js": 42547 + "css": 53117, + "js": 40264 }, "@epam/uui-components": { - "css": 22530, - "js": 247001 + "css": 22508, + "js": 248024 }, "@epam/uui-core": { "css": 0, - "js": 345544 + "js": 346246 }, "@epam/uui-db": { "css": 0, "js": 45769 }, "@epam/uui-docs": { - "css": 2448, - "js": 209641 + "css": 2447, + "js": 178066 }, "@epam/uui-editor": { - "css": 12733, - "js": 175284 + "css": 12746, + "js": 176104 }, "@epam/uui-timeline": { - "css": 2255, - "js": 79166 + "css": 2254, + "js": 80669 }, "@epam/uui": { - "css": 277776, - "js": 343597 + "css": 280340, + "js": 346171 } } } \ No newline at end of file From 650fa11b029aed683817f8db89b29cf63da7b2dd Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 25 Nov 2024 15:43:00 +0100 Subject: [PATCH 21/54] disable Select All for lazy tree picker example --- app/src/docs/_examples/pickerInput/LazyTreeSearch.example.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/docs/_examples/pickerInput/LazyTreeSearch.example.tsx b/app/src/docs/_examples/pickerInput/LazyTreeSearch.example.tsx index 83c23abee0..6cebce86b2 100644 --- a/app/src/docs/_examples/pickerInput/LazyTreeSearch.example.tsx +++ b/app/src/docs/_examples/pickerInput/LazyTreeSearch.example.tsx @@ -19,6 +19,7 @@ export default function LazyTreeSearch() { getId: (i) => i.id, getParentId: (i) => i.parentId, getChildCount: (l) => l.childCount, + selectAll: false, }, [], ); @@ -42,6 +43,7 @@ export default function LazyTreeSearch() { getId: (i) => i.id, getParentId: (i) => i.parentId, getChildCount: (l) => l.childCount, + selectAll: false, }, [], ); From e60225098fe60fe3a43c573a55ceb3688b3fd2ab Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 25 Nov 2024 16:34:49 +0100 Subject: [PATCH 22/54] [Docs]: set default value for multi switch example --- .../_examples/multiSwitch/Basic.example.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/app/src/docs/_examples/multiSwitch/Basic.example.tsx b/app/src/docs/_examples/multiSwitch/Basic.example.tsx index 1c6a88d40c..46e8de97db 100644 --- a/app/src/docs/_examples/multiSwitch/Basic.example.tsx +++ b/app/src/docs/_examples/multiSwitch/Basic.example.tsx @@ -11,9 +11,10 @@ import { ReactComponent as ChatIcon } from '@epam/assets/icons/communication-cha import css from './BasicExample.module.scss'; export default function BasicExample() { - const [value, onValueChange] = useState(null); - const [view, setView] = useState(null); - const [filter, setFilter] = useState(null); + const [value, onValueChange] = useState('on'); + const [userType, userTypeOnValueChange] = useState(2); + const [view, setView] = useState(1); + const [filter, setFilter] = useState(2); return ( @@ -28,8 +29,8 @@ export default function BasicExample() { items={ [ { id: 1, caption: 'Mentee' }, { id: 2, caption: 'Mentor' }, { id: 3, caption: 'Coordinator' }, ] } - value={ value } - onValueChange={ onValueChange } + value={ userType } + onValueChange={ userTypeOnValueChange } /> With Grey border Disabled Icon only From 9f5114ef35f8c086f45b3cf97520ed930d34ae01 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 25 Nov 2024 16:53:46 +0100 Subject: [PATCH 23/54] [Docs]: set default value for multi switch example --- app/src/docs/_examples/multiSwitch/Basic.example.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/docs/_examples/multiSwitch/Basic.example.tsx b/app/src/docs/_examples/multiSwitch/Basic.example.tsx index 46e8de97db..22d22d9318 100644 --- a/app/src/docs/_examples/multiSwitch/Basic.example.tsx +++ b/app/src/docs/_examples/multiSwitch/Basic.example.tsx @@ -12,7 +12,7 @@ import css from './BasicExample.module.scss'; export default function BasicExample() { const [value, onValueChange] = useState('on'); - const [userType, userTypeOnValueChange] = useState(2); + const [userType, userTypeOnValueChange] = useState(); const [view, setView] = useState(1); const [filter, setFilter] = useState(2); From c8448dc7354c431671b0efec9ab924af984ab362 Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 25 Nov 2024 17:15:48 +0100 Subject: [PATCH 24/54] [Demo]: remove columns config configuration from projects demo --- app/src/demo/tables/editableTable/TimelineMode.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/demo/tables/editableTable/TimelineMode.tsx b/app/src/demo/tables/editableTable/TimelineMode.tsx index 4f5dd455b3..f81c4979f9 100644 --- a/app/src/demo/tables/editableTable/TimelineMode.tsx +++ b/app/src/demo/tables/editableTable/TimelineMode.tsx @@ -31,7 +31,6 @@ export function TimelineMode({ value={ tableState } onValueChange={ setTableState } dataTableFocusManager={ dataTableFocusManager } - showColumnsConfig allowColumnsResizing allowColumnsReordering headerSize="60" From ad144c89882a736b2c081d9881d518ba9ddbf50b Mon Sep 17 00:00:00 2001 From: AlekseyManetov Date: Mon, 25 Nov 2024 17:32:03 +0100 Subject: [PATCH 25/54] [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 96342246355ab81be57eeb96f60baee3e1ab024a Mon Sep 17 00:00:00 2001 From: Siarhei_Dzeraviannik Date: Tue, 26 Nov 2024 14:01:52 +0300 Subject: [PATCH 26/54] [ErrorPage]: Added field for additional message with support link (it works with `500, 503, default` errors), added support link for site --- app/src/index.tsx | 9 +++++++ changelog.md | 1 + uui-core/src/services/ErrorContext.ts | 2 ++ uui/components/errors/ErrorPage.module.scss | 27 +++++++++++++++------ uui/components/errors/ErrorPage.tsx | 1 + uui/components/errors/config.ts | 3 +++ uui/i18n.ts | 2 ++ 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/app/src/index.tsx b/app/src/index.tsx index 9cc3feb878..a35e00e7ce 100644 --- a/app/src/index.tsx +++ b/app/src/index.tsx @@ -4,6 +4,7 @@ import { RouterProvider } from 'react-router'; import { createBrowserRouter } from 'react-router-dom'; import { init as initApm } from '@elastic/apm-rum'; import { Router6AdaptedRouter, useUuiServices, UuiContext, IProcessRequest, GAListener } from '@epam/uui-core'; +import { i18n } from '@epam/uui'; import { AmplitudeListener } from './analyticsEvents'; import { svc } from './services'; import App from './App'; @@ -19,6 +20,14 @@ import '@epam/assets/theme/theme_eduverse_light.scss'; import '@epam/assets/theme/theme_eduverse_dark.scss'; import './index.module.scss'; +i18n.errorHandler.supportLink = ( + <> + You can track the service availability at + {' '} + status.epam.com + +); + const router6 = createBrowserRouter([ { path: '*', element: }, ]); diff --git a/changelog.md b/changelog.md index fc6ca4bae0..0b8dff7c50 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ # 5.xx.xx - xx.xx.2024 **What's New** +* [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 diff --git a/uui-core/src/services/ErrorContext.ts b/uui-core/src/services/ErrorContext.ts index 9a6b708a5f..c2310797d7 100644 --- a/uui-core/src/services/ErrorContext.ts +++ b/uui-core/src/services/ErrorContext.ts @@ -43,6 +43,8 @@ export interface ErrorPageInfo { imageUrl?: string; /** Url of error image to display on error page in case of mobile layout (app width < 720px) */ mobileImageUrl?: string; + /** Additional message with link to the support portal */ + supportLink?: React.ReactNode; } export class UuiError extends Error { diff --git a/uui/components/errors/ErrorPage.module.scss b/uui/components/errors/ErrorPage.module.scss index fdc912f386..8f4ac89cd5 100644 --- a/uui/components/errors/ErrorPage.module.scss +++ b/uui/components/errors/ErrorPage.module.scss @@ -39,6 +39,22 @@ font-size: 16px; color: var(--uui-text-primary); max-width: 700px; + margin-top: 8px; +} + +:global(.uui-error-support-link) { + font-family: var(--uui-font); + font-weight: 400; + text-align: center; + line-height: 24px; + font-size: 16px; + color: var(--uui-text-primary); + max-width: 700px; + margin-top: 18px; + + a { + text-decoration: none; + } } @media screen and (max-width: 720px) { @@ -48,7 +64,6 @@ } :global(.uui-error-title) { - font-family: var(--uui-font); font-weight: 400; font-size: 24px; line-height: 30px; @@ -57,12 +72,10 @@ } :global(.uui-error-subtitle) { - font-family: var(--uui-font); - font-weight: 400; - text-align: center; - line-height: 24px; - font-size: 16px; - color: var(--uui-text-primary); + max-width: 460px; + } + + :global(.uui-error-support-link) { max-width: 460px; } } diff --git a/uui/components/errors/ErrorPage.tsx b/uui/components/errors/ErrorPage.tsx index 77817b6d7c..11ac2a9592 100644 --- a/uui/components/errors/ErrorPage.tsx +++ b/uui/components/errors/ErrorPage.tsx @@ -13,6 +13,7 @@ export const ErrorPage: React.FC = (props) => { ERROR OCCURRED!
{props.title}
{props.subtitle}
+
{props?.supportLink}
); diff --git a/uui/components/errors/config.ts b/uui/components/errors/config.ts index a42cab87ad..79fca53cd1 100644 --- a/uui/components/errors/config.ts +++ b/uui/components/errors/config.ts @@ -26,17 +26,20 @@ export const getErrorPageConfig = () => ({ mobileImageUrl: 'https://static.cdn.epam.com/uploads/690afa39a93c88c4dd13758fe1d869d5/EPM-UUI/error-pages-illustrations/L_Error_500_Monochrome.svg', title: i18n.errorHandler.errorPageConfig.serverError.title, subtitle: i18n.errorHandler.errorPageConfig.serverError.subtitle, + supportLink: i18n.errorHandler.supportLink, }, serviceUnavailable: { imageUrl: 'https://static.cdn.epam.com/uploads/690afa39a93c88c4dd13758fe1d869d5/EPM-UUI/error-pages-illustrations/L_Error_503_Monochrome.svg', mobileImageUrl: 'https://static.cdn.epam.com/uploads/690afa39a93c88c4dd13758fe1d869d5/EPM-UUI/error-pages-illustrations/L_Error_503_Monochrome.svg', title: i18n.errorHandler.errorPageConfig.serviceUnavailable.title, subtitle: i18n.errorHandler.errorPageConfig.serviceUnavailable.subtitle, + supportLink: i18n.errorHandler.supportLink, }, default: { imageUrl: 'https://static.cdn.epam.com/uploads/690afa39a93c88c4dd13758fe1d869d5/EPM-UUI/error-pages-illustrations/L_Empty_Monochrome.svg', mobileImageUrl: 'https://static.cdn.epam.com/uploads/690afa39a93c88c4dd13758fe1d869d5/EPM-UUI/error-pages-illustrations/L_Empty_Monochrome.svg', title: i18n.errorHandler.errorPageConfig.default.title, subtitle: i18n.errorHandler.errorPageConfig.default.subtitle, + supportLink: i18n.errorHandler.supportLink, }, }); diff --git a/uui/i18n.ts b/uui/i18n.ts index 41aa077381..9930d7d835 100644 --- a/uui/i18n.ts +++ b/uui/i18n.ts @@ -1,3 +1,4 @@ +import { ReactNode } from 'react'; import { i18n as uuiI18n } from '@epam/uui-core'; const TREE_SHAKEABLE_INIT = () => ({ @@ -153,6 +154,7 @@ const TREE_SHAKEABLE_INIT = () => ({ subtitle: 'We are trying to recover. Please wait.', }, }, + supportLink: undefined as ReactNode, }, }); From 4f1e9ee07c0288963e044c1521cf1abf0113e9d2 Mon Sep 17 00:00:00 2001 From: Siarhei_Dzeraviannik Date: Tue, 26 Nov 2024 17:22:00 +0300 Subject: [PATCH 27/54] [Alert]: updated example, updated stylelint config --- app/src/docs/_examples/alert/Sizes.example.tsx | 1 + uui-build/linting/stylelintrc.base.js | 6 ++++++ uui/components/overlays/Alert.module.scss | 11 +---------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/docs/_examples/alert/Sizes.example.tsx b/app/src/docs/_examples/alert/Sizes.example.tsx index 1752b2a689..1df0b99520 100644 --- a/app/src/docs/_examples/alert/Sizes.example.tsx +++ b/app/src/docs/_examples/alert/Sizes.example.tsx @@ -15,6 +15,7 @@ export default function BasicAlertExample() { {' '} alert('close action') } actions={ [{ name: 'ACTION 1', action: () => null }, { name: 'ACTION 2', action: () => null }] } > diff --git a/uui-build/linting/stylelintrc.base.js b/uui-build/linting/stylelintrc.base.js index 76a4f75c8b..d866d8a536 100644 --- a/uui-build/linting/stylelintrc.base.js +++ b/uui-build/linting/stylelintrc.base.js @@ -73,6 +73,12 @@ const SCSS_COMMON_RULES = { 'scss/selector-no-redundant-nesting-selector': null, 'scss/dollar-variable-pattern': null, 'scss/no-global-function-names': null, + 'length-zero-no-unit': [ + true, { + ignore: ['custom-properties'], + ignoreFunctions: ['var', '/^--/'], + }, + ], }; module.exports = { diff --git a/uui/components/overlays/Alert.module.scss b/uui/components/overlays/Alert.module.scss index bcd07d710b..7afef19994 100644 --- a/uui/components/overlays/Alert.module.scss +++ b/uui/components/overlays/Alert.module.scss @@ -6,11 +6,8 @@ --uui-alert-border: var(--uui-color-50); --uui-alert-icon: var(--uui-color-50); - //--uui-alert-font: var(--uui-font); - //--uui-alert-font-weight: var(--uui-font-weight, 400); - --uui-alert-min-height: var(--uui-size); - --uui-alert-min-width: 170px; // TODO: need clarify + --uui-alert-min-width: 170px; --uui-alert-border-radius: var(--uui-border-radius); --uui-alert-border-width: 0px; --uui-alert-indicator-border-width: 6px; @@ -20,8 +17,6 @@ --uui-alert-padding-v: 9px; --uui-alert-caption-gap-h: 12px; --uui-alert-icon-size: var(--uui-icon-size); - //--uui-alert-line-height: var(--uui-line-height); - //--uui-alert-font-size: var(--uui-font-size); // box-sizing: border-box; @@ -59,10 +54,6 @@ column-gap: var(--uui-alert-gap-h); row-gap: var(--uui-alert-gap-v); width: 100%; - //font-family: var(--uui-alert-font); - //font-weight: var(--uui-alert-font-weight); - //line-height: var(--uui-alert-line-height); - //font-size: var(--uui-alert-font-size); } .action-wrapper { From c7bdb63b00b3ed1c0f380d075e029626f6156c0a Mon Sep 17 00:00:00 2001 From: Siarhei_Dzeraviannik Date: Tue, 26 Nov 2024 17:29:49 +0300 Subject: [PATCH 28/54] changelog updated --- changelog.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index 1626bd66e2..17bb054de9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ # 5.xx.xx - xx.xx.2024 **What's New** +* [Alert]: Added support for size theming * [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** @@ -10,11 +11,6 @@ # 5.11.0 - 15.11.2024 -**What's New** -* [Alert]: Added support for size theming - -# 5.*.* - **.**.2024 - **What's New** * [FlexRow][Breaking Change]: Only for `@epam/loveship` package. Now spacing default value works based on `columnGap` props. It shouldn't affect general cases, but previous spacing implementation require additional hack when it was needed to add negative margin value for container to remove corner paddings in multiline case. Now this hack should be removed, since `columnGap` implementation doesn't produce such bug for multiline. * [useTableState][Breaking Change]: columns prop is removed, since it's not needed now. Just remove it from `useTableState` provided props. From 8551bf7dd3e6457ff104557a03b8909ffecaa178 Mon Sep 17 00:00:00 2001 From: Siarhei_Dzeraviannik Date: Tue, 26 Nov 2024 17:47:13 +0300 Subject: [PATCH 29/54] snapshots updated --- .../__snapshots__/Alert.test.tsx.snap | 154 ++++++++++-------- 1 file changed, 89 insertions(+), 65 deletions(-) diff --git a/uui/components/overlays/__tests__/__snapshots__/Alert.test.tsx.snap b/uui/components/overlays/__tests__/__snapshots__/Alert.test.tsx.snap index 12ebc121ab..2d99899cba 100644 --- a/uui/components/overlays/__tests__/__snapshots__/Alert.test.tsx.snap +++ b/uui/components/overlays/__tests__/__snapshots__/Alert.test.tsx.snap @@ -2,42 +2,46 @@ exports[`Alert should render with maximum props 1`] = `
- +
+ +
-
-
- +
+ ACTION 1 +
+ +