-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Objective
Currently, Table does not have the ability to emulate the behavior of ordinary links when clicking on a row - namely, the ability to open a new tab without focusing on it. Modern browsers do not allow you to process the click event via onRowClick or onRowMouseDown using JS and do the necessary action, and the Table component does not provide other convenient options to achieve this. Despite this, going through the list of entities and opening several tabs at once to look at them later in turn is a fairly common scenario.
Solution Proposal
Add a util function or HOC, which will allow you to "wrap" an entire row into the desired link, while allowing you to interact with interactive elements in cells.
Proposed implementation
LinkTableUtils.tsx
import {Link, TableColumnConfig, TableProps} from '@gravity-ui/uikit';
import {cn} from 'src/helpers';
import _get from 'lodash/get';
import _has from 'lodash/has';
import cx from 'classnames';
import {ReactNode} from 'react';
import './LinkTableUtils.scss';
const b = cn('link-table-utils');
export type TableColumnConfigWithRowLink<T> = Omit<TableColumnConfig<T>, 'meta'> & {
meta: Omit<NonNullable<TableColumnConfig<T>['meta']>, 'isInteractive'> & {
isInteractive: boolean;
};
};
export const defaultLinkRowClassName = b('row');
export const interactiveElementClassName = b('interactive-element');
export const getDefaultLinkRowDescriptor = () => ({classNames: [defaultLinkRowClassName]});
export const prepareGetRowDescriptor = <T,>(
originalGetRowDescriptor: NonNullable<TableProps<T>['getRowDescriptor']>,
) => {
const newGetRowDescriptor: TableProps<T>['getRowDescriptor'] = (...args) => {
const descriptor = originalGetRowDescriptor(...args);
return {
...descriptor,
classNames: [cx(descriptor?.classNames, defaultLinkRowClassName)],
};
};
return newGetRowDescriptor;
};
export const prepareLinkColumns = <T,>(
columns: TableColumnConfigWithRowLink<T>[],
getLinkProps: (entity: T, index: number) => {href?: string; target?: string},
): TableColumnConfig<T>[] => {
const preparedColumns: TableColumnConfig<T>[] = [];
columns.forEach((column) => {
const meta = column.meta;
if (meta.isInteractive) {
const newClassName = cx(column.className, b('interactive-cell'));
preparedColumns.push({
...column,
className: newClassName,
});
} else {
preparedColumns.push(column);
}
});
preparedColumns.push({
id: '_row-link-internal-column',
name: '',
className: b('link-internal-column'),
template: (entity, index) => {
const linkProps = getLinkProps(entity, index);
if (linkProps.href) {
return (
<Link
className={b('main-link-cell')}
href={linkProps.href}
target="_blank"
aria-label={linkProps.href}
></Link>
);
}
return null;
},
});
return preparedColumns;
};LinkTableUtils.scss
.link-table-utils {
$block: &;
&__row {
// new context, transform instead of position relative because of safari
transform: translateZ(0);
&:hover {
background-color: var(--g-color-base-simple-hover-solid);
}
}
&__main-link-cell {
vertical-align: top;
&::before {
position: absolute;
inset: 0;
content: '';
}
}
&__interactive-element {
z-index: 1;
position: relative;
}
&__interactive-cell {
>* {
@extend #{$block}__interactive-element;
}
}
&__link-internal-column {
overflow: hidden;
width: 0 !important;
max-width: 0 !important;
padding: 0 !important;
border-width: 0 !important;
font-size: 0 !important;
}
}
Basic usage
// Add to TableColumnConfig
meta: { isInteractive: false, },
// Change <Table> props
columns={prepareLinkColumns(tableColumns, getLinkProps)}
getRowDescriptor={getDefaultLinkRowDescriptor}Definition of done
Utilities or HOC are added to gravity uikit.
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Type
Projects
Status
Postponed