Skip to content

Commit

Permalink
fix(withTableSettings): isSelected -> selected, isRequired -> required (
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanVor authored Apr 9, 2024
1 parent d826ca7 commit cf1dfb0
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ describe('withTableSettings', () => {

await userEvent.click(screen.getByRole('button', {name: 'Table settings'}));
await userEvent.click(await screen.findByRole('button', {name: 'description'}));
await userEvent.click(screen.getByRole('button', {name: 'Apply'}));
await userEvent.click(screen.getByRole('button', {name: 'button_apply'}));

expect(updateSettings).toHaveBeenCalledWith([
{
Expand Down
2 changes: 0 additions & 2 deletions src/components/Table/hoc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,4 @@ export {withTableSettings} from './withTableSettings/withTableSettings';
export type {
WithTableSettingsProps,
TableSettingsData,
TableColumnSetupItem,
} from './withTableSettings/withTableSettings';
export * from './withTableSettings/TableColumnSetup/TableColumnSetup';
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@use '../../../../variables';

$block: '.#{variables.$ns}table-column-setup';
$block: '.#{variables.$ns}inner-table-column-setup';

#{$block} {
&__controls {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import {Gear, Grip, Lock} from '@gravity-ui/icons';
import {DragDropContext, Draggable, Droppable} from 'react-beautiful-dnd';
import type {
DraggableChildrenFn,
DraggableProvided,
DraggableStateSnapshot,
OnDragEndResponder,
Expand All @@ -19,21 +20,17 @@ import type {
TreeSelectRenderContainer,
TreeSelectRenderItem,
} from '../../../../TreeSelect/types';
import type {ListItemViewProps} from '../../../../useList';
import type {ListItemCommonProps, ListItemViewProps} from '../../../../useList';
import {ListContainerView, ListItemView} from '../../../../useList';
import {block} from '../../../../utils/cn';
import type {TableColumnSetupItem, TableSetting} from '../withTableSettings';
import type {TableColumnConfig} from '../../../Table';
import type {TableSetting} from '../withTableSettings';

import i18n from './i18n';

import './TableColumnSetup.scss';

function identity<T>(value: T): T {
return value;
}

const b = block('table-column-setup');
const tableColumnSetupCn = b(null);
const b = block('inner-table-column-setup');
const controlsCn = b('controls');

const reorderArray = <T extends unknown>(list: T[], startIndex: number, endIndex: number): T[] => {
Expand All @@ -44,17 +41,35 @@ const reorderArray = <T extends unknown>(list: T[], startIndex: number, endIndex
return result;
};

const prepareDndItems = (tableColumnItems: TableColumnSetupItem[]) => {
return tableColumnItems.map<Item>((tableColumnItem) => {
const hasSelectionIcon = tableColumnItem.isRequired === false;
const prepareStickyState = (
itemsById: Record<string, TableColumnSetupItem>,
visibleFlattenIds: string[],
) => {
let lastStickyStartIdx = 0;
for (; lastStickyStartIdx !== visibleFlattenIds.length; lastStickyStartIdx++) {
const visibleFlattenId = visibleFlattenIds[lastStickyStartIdx];
const item = itemsById[visibleFlattenId];

if (item?.sticky !== 'left' && item?.sticky !== 'start') {
break;
}
}

return {
...tableColumnItem,
startSlot: tableColumnItem.isRequired ? <Icon data={Lock} /> : undefined,
hasSelectionIcon,
selected: hasSelectionIcon ? tableColumnItem.isSelected : undefined,
};
});
let firstStickyEndIdx = visibleFlattenIds.length;
for (; firstStickyEndIdx !== 0; firstStickyEndIdx--) {
const visibleFlattenId = visibleFlattenIds[firstStickyEndIdx - 1];
const item = itemsById[visibleFlattenId];

if (item?.sticky !== 'right' && item?.sticky !== 'end') {
break;
}
}

return {
stickyStartItemIdList: visibleFlattenIds.slice(0, lastStickyStartIdx),
sortableItemIdList: visibleFlattenIds.slice(lastStickyStartIdx, firstStickyEndIdx),
stickyEndItemIdList: visibleFlattenIds.slice(firstStickyEndIdx),
};
};

const prepareValue = (tableColumnItems: TableColumnSetupItem[]) => {
Expand All @@ -70,10 +85,13 @@ const prepareValue = (tableColumnItems: TableColumnSetupItem[]) => {
};

interface RenderContainerProps {
provided: DraggableProvided;
snapshot: DraggableStateSnapshot;
isDragDisabled?: boolean;
provided?: DraggableProvided;
snapshot?: DraggableStateSnapshot;
}

const RENDER_DRAG_DISABLED_CONTAINER_PROPS: RenderContainerProps = {isDragDisabled: true};

interface SwitcherProps {
onKeyDown: React.KeyboardEventHandler<HTMLElement>;
onClick: React.MouseEventHandler<HTMLElement>;
Expand All @@ -86,50 +104,68 @@ interface UseDndRenderContainerParams {
const useDndRenderContainer = ({onDragEnd, renderControls}: UseDndRenderContainerParams) => {
const uniqId = useUniqId();

const dndRenderContainer: TreeSelectRenderContainer<Item> = ({
const dndRenderContainer: TreeSelectRenderContainer<TableColumnSetupItem> = ({
renderItem,
visibleFlattenIds,
items: _items,
itemsById,
containerRef,
id,
className,
}) => {
const visibleFlattenItemList = visibleFlattenIds.map((visibleFlattenId, idx) =>
renderItem(visibleFlattenId, idx),
const renderDndActiveItem: DraggableChildrenFn = (provided, snapshot, rubric) => {
const renderContainerProps: RenderContainerProps = {
provided,
snapshot,
};

return renderItem(
visibleFlattenIds[rubric.source.index],
rubric.source.index,
renderContainerProps,
);
};

const {stickyStartItemIdList, sortableItemIdList, stickyEndItemIdList} = prepareStickyState(
itemsById,
visibleFlattenIds,
);

const stickyStartItemList = stickyStartItemIdList.map((visibleFlattenId, idx) => {
return renderItem(visibleFlattenId, idx, RENDER_DRAG_DISABLED_CONTAINER_PROPS);
});

const sortableItemList = sortableItemIdList.map((visibleFlattenId, idx) => {
return renderItem(visibleFlattenId, idx + stickyStartItemIdList.length);
});

const stickyEndItemList = stickyEndItemIdList.map((visibleFlattenId, idx) => {
return renderItem(
visibleFlattenId,
stickyStartItemList.length + sortableItemList.length + idx,
RENDER_DRAG_DISABLED_CONTAINER_PROPS,
);
});

return (
<React.Fragment>
<ListContainerView ref={containerRef} id={id} className={className}>
{stickyStartItemList}
<DragDropContext onDragEnd={onDragEnd}>
<Droppable
droppableId={uniqId}
renderClone={(provided, snapshot, rubric) => {
const renderContainerProps: RenderContainerProps = {
provided,
snapshot,
};

return renderItem(
visibleFlattenIds[rubric.source.index],
rubric.source.index,
renderContainerProps,
);
}}
>
<Droppable droppableId={uniqId} renderClone={renderDndActiveItem}>
{(droppableProvided) => {
return (
<div
{...droppableProvided.droppableProps}
ref={droppableProvided.innerRef}
>
{visibleFlattenItemList}
{sortableItemList}
{droppableProvided.placeholder}
</div>
);
}}
</Droppable>
</DragDropContext>
{stickyEndItemList}
</ListContainerView>
<div className={controlsCn}>{renderControls()}</div>
</React.Fragment>
Expand All @@ -140,23 +176,30 @@ const useDndRenderContainer = ({onDragEnd, renderControls}: UseDndRenderContaine
};

const useDndRenderItem = (sortable: boolean | undefined) => {
const renderDndItem: TreeSelectRenderItem<Item, RenderContainerProps> = ({
data,
const renderDndItem: TreeSelectRenderItem<TableColumnSetupItem, RenderContainerProps> = ({
data: item,
props,
index,
renderContainerProps,
}) => {
const isDragDisabled = sortable === false;
const isDragDisabled = sortable === false || renderContainerProps?.isDragDisabled === true;
const endSlot = isDragDisabled ? undefined : <Icon data={Grip} size={16} />;
const hasSelectionIcon = !item.isRequired;
const startSlot = item.isRequired ? <Icon data={Lock} /> : undefined;
const selected = item.isRequired ? false : props.selected;

const endSlot =
data.endSlot ?? (isDragDisabled ? undefined : <Icon data={Grip} size={16} />);

const commonProps = {
const commonProps: ListItemViewProps = {
...props,
...data,
selected,
startSlot,
hasSelectionIcon,
endSlot,
};

if (isDragDisabled) {
return <ListItemView {...commonProps} key={commonProps.id} />;
}

const renderItem = (provided: DraggableProvided, snapshot: DraggableStateSnapshot) => (
<ListItemView
{...commonProps}
Expand All @@ -167,15 +210,15 @@ const useDndRenderItem = (sortable: boolean | undefined) => {
/>
);

if (renderContainerProps) {
if (renderContainerProps?.provided && renderContainerProps.snapshot) {
return renderItem(renderContainerProps.provided, renderContainerProps.snapshot);
}

return (
<Draggable
draggableId={data.id}
draggableId={props.id}
index={index}
key={`item-key-${data.id}`}
key={`item-key-${props.id}`}
isDragDisabled={isDragDisabled}
>
{renderItem}
Expand All @@ -186,11 +229,17 @@ const useDndRenderItem = (sortable: boolean | undefined) => {
return renderDndItem;
};

type Item = TableColumnSetupItem &
ListItemViewProps & {
id: string;
isDragDisabled?: boolean;
export type TableColumnSetupItem = TableSetting & {
title: React.ReactNode;
isRequired?: boolean;
sticky?: TableColumnConfig<unknown>['sticky'];
};

const mapItemDataToProps = (item: TableColumnSetupItem): ListItemCommonProps => {
return {
title: item.title,
};
};

export type RenderControls = (params: {
DefaultApplyButton: React.ComponentType;
Expand All @@ -214,6 +263,8 @@ export interface TableColumnSetupProps {
* @deprecated
*/
renderControls?: RenderControls;

className?: string;
}

export const TableColumnSetup = (props: TableColumnSetupProps) => {
Expand All @@ -225,6 +276,7 @@ export const TableColumnSetup = (props: TableColumnSetupProps) => {
onUpdate: propsOnUpdate,
sortable,
renderControls,
className,
} = props;

const [open, setOpen] = React.useState(false);
Expand Down Expand Up @@ -295,20 +347,17 @@ export const TableColumnSetup = (props: TableColumnSetupProps) => {
});
};

const [value, dndItems] = React.useMemo(
() => [prepareValue(items), prepareDndItems(items)] as const,
[items],
);
const value = React.useMemo(() => prepareValue(items), [items]);

return (
<TreeSelect
className={tableColumnSetupCn}
mapItemDataToProps={identity}
className={b(null, className)}
mapItemDataToProps={mapItemDataToProps}
multiple
size="l"
open={open}
value={value}
items={dndItems}
items={items}
onUpdate={onUpdate}
popupWidth={popupWidth}
onOpenChange={onOpenChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {actionsColumnId, enhanceSystemColumn} from '../withTableActions/withTabl
import {selectionColumnId} from '../withTableSelection/withTableSelection';

import {TableColumnSetup} from './TableColumnSetup/TableColumnSetup';
import type {RenderControls} from './TableColumnSetup/TableColumnSetup';
import type {RenderControls, TableColumnSetupItem} from './TableColumnSetup/TableColumnSetup';
import i18n from './i18n';

import './withTableSettings.scss';
Expand All @@ -28,11 +28,6 @@ export type TableSetting = {

export type TableSettingsData = TableSetting[];

export type TableColumnSetupItem = TableSetting & {
title: React.ReactNode;
isRequired?: boolean;
};

export function filterColumns<I>(
columns: TableColumnConfig<I>[],
settings: TableSettingsData,
Expand Down Expand Up @@ -79,6 +74,7 @@ const getTableColumnSetupItem = <I extends unknown>(
isSelected: isProtected ? true : isSelected,
isRequired: isProtected,
title: column ? getColumnStringTitle(column) : id,
sticky: column?.sticky,
};
};

Expand Down
10 changes: 10 additions & 0 deletions src/components/TableColumnSetup/TableColumnSetup.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@use '../variables';

$block: '.#{variables.$ns}table-column-setup';

#{$block} {
&__status {
margin-inline-start: 5px;
color: var(--g-color-text-secondary);
}
}
Loading

0 comments on commit cf1dfb0

Please sign in to comment.