mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
add drag/drop to column reordering
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
gap: var(--theme-spacing-md);
|
gap: var(--theme-spacing-md);
|
||||||
@@ -24,3 +25,29 @@
|
|||||||
outline: 2px solid var(--theme-colors-primary);
|
outline: 2px solid var(--theme-colors-primary);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item.dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.dragged-over-top::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
height: 2px;
|
||||||
|
content: '';
|
||||||
|
background-color: var(--theme-colors-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.dragged-over-bottom::before {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
height: 2px;
|
||||||
|
content: '';
|
||||||
|
background-color: var(--theme-colors-primary);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
|
import {
|
||||||
|
attachClosestEdge,
|
||||||
|
type Edge,
|
||||||
|
extractClosestEdge,
|
||||||
|
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
||||||
|
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
||||||
|
import {
|
||||||
|
draggable,
|
||||||
|
dropTargetForElements,
|
||||||
|
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
||||||
|
import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview';
|
||||||
import { useDebouncedState } from '@mantine/hooks';
|
import { useDebouncedState } from '@mantine/hooks';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
import { motion } from 'motion/react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import styles from './table-config.module.css';
|
import styles from './table-config.module.css';
|
||||||
@@ -25,6 +35,7 @@ import { Stack } from '/@/shared/components/stack/stack';
|
|||||||
import { TextInput } from '/@/shared/components/text-input/text-input';
|
import { TextInput } from '/@/shared/components/text-input/text-input';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { Tooltip } from '/@/shared/components/tooltip/tooltip';
|
import { Tooltip } from '/@/shared/components/tooltip/tooltip';
|
||||||
|
import { dndUtils, DragData, DragOperation, DragTarget } from '/@/shared/types/drag-and-drop';
|
||||||
import { ItemListKey, ListPaginationType } from '/@/shared/types/types';
|
import { ItemListKey, ListPaginationType } from '/@/shared/types/types';
|
||||||
|
|
||||||
interface TableConfigProps {
|
interface TableConfigProps {
|
||||||
@@ -432,6 +443,23 @@ const TableColumnConfig = ({
|
|||||||
}));
|
}));
|
||||||
}, [value, searchColumns, fuse]);
|
}, [value, searchColumns, fuse]);
|
||||||
|
|
||||||
|
const handleReorder = useCallback(
|
||||||
|
(idFrom: string, idTo: string, edge: Edge | null) => {
|
||||||
|
const idList = value.map((item) => item.id);
|
||||||
|
const newIdOrder = dndUtils.reorderById({
|
||||||
|
edge,
|
||||||
|
idFrom,
|
||||||
|
idTo,
|
||||||
|
list: idList,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Map the new ID order back to full items
|
||||||
|
const newOrder = newIdOrder.map((id) => value.find((item) => item.id === id)!);
|
||||||
|
onChange(newOrder);
|
||||||
|
},
|
||||||
|
[onChange, value],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="xs">
|
<Stack gap="xs">
|
||||||
<Group justify="space-between" mb="md">
|
<Group justify="space-between" mb="md">
|
||||||
@@ -444,149 +472,300 @@ const TableColumnConfig = ({
|
|||||||
size="xs"
|
size="xs"
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
{filteredColumns.map(({ item, matches }) => (
|
<div style={{ userSelect: 'none' }}>
|
||||||
<motion.div
|
{filteredColumns.map(({ item, matches }) => (
|
||||||
className={clsx(styles.item, {
|
<TableColumnItem
|
||||||
[styles.matched]: matches && matches.length > 0,
|
handleAlignCenter={handleAlignCenter}
|
||||||
})}
|
handleAlignLeft={handleAlignLeft}
|
||||||
key={item.id}
|
handleAlignRight={handleAlignRight}
|
||||||
layout
|
handleAutoSize={handleAutoSize}
|
||||||
>
|
handleChangeEnabled={handleChangeEnabled}
|
||||||
<Group wrap="nowrap">
|
handleMoveDown={handleMoveDown}
|
||||||
<Checkbox
|
handleMoveUp={handleMoveUp}
|
||||||
checked={item.isEnabled}
|
handlePinToLeft={handlePinToLeft}
|
||||||
id={item.id}
|
handlePinToRight={handlePinToRight}
|
||||||
label={labelMap[item.id]}
|
handleReorder={handleReorder}
|
||||||
onChange={(e) => handleChangeEnabled(item, e.currentTarget.checked)}
|
handleRowWidth={handleRowWidth}
|
||||||
size="sm"
|
item={item}
|
||||||
/>
|
key={item.id}
|
||||||
</Group>
|
label={labelMap[item.id]}
|
||||||
<Group wrap="nowrap">
|
matches={matches}
|
||||||
<ActionIconGroup className={styles.group}>
|
/>
|
||||||
<ActionIcon
|
))}
|
||||||
icon="arrowUp"
|
</div>
|
||||||
iconProps={{ size: 'md' }}
|
|
||||||
onClick={() => handleMoveUp(item)}
|
|
||||||
size="xs"
|
|
||||||
tooltip={{
|
|
||||||
label: t('table.config.general.moveUp', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
variant="subtle"
|
|
||||||
/>
|
|
||||||
<ActionIcon
|
|
||||||
icon="arrowDown"
|
|
||||||
iconProps={{ size: 'md' }}
|
|
||||||
onClick={() => handleMoveDown(item)}
|
|
||||||
size="xs"
|
|
||||||
tooltip={{
|
|
||||||
label: t('table.config.general.moveDown', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
variant="subtle"
|
|
||||||
/>
|
|
||||||
</ActionIconGroup>
|
|
||||||
<ActionIconGroup className={styles.group}>
|
|
||||||
<ActionIcon
|
|
||||||
icon="arrowLeftToLine"
|
|
||||||
iconProps={{ size: 'md' }}
|
|
||||||
onClick={() => handlePinToLeft(item)}
|
|
||||||
size="xs"
|
|
||||||
tooltip={{
|
|
||||||
label: t('table.config.general.pinToLeft', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
variant={item.pinned === 'left' ? 'filled' : 'subtle'}
|
|
||||||
/>
|
|
||||||
<ActionIcon
|
|
||||||
icon="arrowRightToLine"
|
|
||||||
iconProps={{ size: 'md' }}
|
|
||||||
onClick={() => handlePinToRight(item)}
|
|
||||||
size="xs"
|
|
||||||
tooltip={{
|
|
||||||
label: t('table.config.general.pinToRight', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
variant={item.pinned === 'right' ? 'filled' : 'subtle'}
|
|
||||||
/>
|
|
||||||
</ActionIconGroup>
|
|
||||||
<ActionIconGroup className={styles.group}>
|
|
||||||
<ActionIcon
|
|
||||||
icon="alignLeft"
|
|
||||||
iconProps={{ size: 'md' }}
|
|
||||||
onClick={() => handleAlignLeft(item)}
|
|
||||||
size="xs"
|
|
||||||
tooltip={{
|
|
||||||
label: t('table.config.general.alignLeft', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
variant={item.align === 'start' ? 'filled' : 'subtle'}
|
|
||||||
/>
|
|
||||||
<ActionIcon
|
|
||||||
icon="alignCenter"
|
|
||||||
iconProps={{ size: 'md' }}
|
|
||||||
onClick={() => handleAlignCenter(item)}
|
|
||||||
size="xs"
|
|
||||||
tooltip={{
|
|
||||||
label: t('table.config.general.alignCenter', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
variant={item.align === 'center' ? 'filled' : 'subtle'}
|
|
||||||
/>
|
|
||||||
<ActionIcon
|
|
||||||
icon="alignRight"
|
|
||||||
iconProps={{ size: 'md' }}
|
|
||||||
onClick={() => handleAlignRight(item)}
|
|
||||||
size="xs"
|
|
||||||
tooltip={{
|
|
||||||
label: t('table.config.general.alignRight', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
}),
|
|
||||||
}}
|
|
||||||
variant={item.align === 'end' ? 'filled' : 'subtle'}
|
|
||||||
/>
|
|
||||||
</ActionIconGroup>
|
|
||||||
<NumberInput
|
|
||||||
className={clsx(styles.group, styles.numberInput)}
|
|
||||||
hideControls={false}
|
|
||||||
leftSection={
|
|
||||||
<>
|
|
||||||
{item.pinned === null && (
|
|
||||||
<Tooltip
|
|
||||||
label={t('table.config.general.autosize', {
|
|
||||||
postProcess: 'sentenceCase',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Checkbox
|
|
||||||
checked={item.autoSize}
|
|
||||||
disabled={item.pinned !== null}
|
|
||||||
id={item.id}
|
|
||||||
onChange={(e) =>
|
|
||||||
handleAutoSize(item, e.currentTarget.checked)
|
|
||||||
}
|
|
||||||
size="xs"
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
max={2000}
|
|
||||||
min={0}
|
|
||||||
onChange={(value) => handleRowWidth(item, value)}
|
|
||||||
size="xs"
|
|
||||||
step={10}
|
|
||||||
value={item.width}
|
|
||||||
variant="subtle"
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
</motion.div>
|
|
||||||
))}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DragHandle = ({ dragHandleRef }: { dragHandleRef: React.RefObject<HTMLButtonElement> }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActionIcon
|
||||||
|
icon="dragVertical"
|
||||||
|
iconProps={{
|
||||||
|
size: 'md',
|
||||||
|
}}
|
||||||
|
ref={dragHandleRef}
|
||||||
|
size="xs"
|
||||||
|
style={{ cursor: 'grab' }}
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.dragToReorder', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant="transparent"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TableColumnItem = ({
|
||||||
|
handleAlignCenter,
|
||||||
|
handleAlignLeft,
|
||||||
|
handleAlignRight,
|
||||||
|
handleAutoSize,
|
||||||
|
handleChangeEnabled,
|
||||||
|
handleMoveDown,
|
||||||
|
handleMoveUp,
|
||||||
|
handlePinToLeft,
|
||||||
|
handlePinToRight,
|
||||||
|
handleReorder,
|
||||||
|
handleRowWidth,
|
||||||
|
item,
|
||||||
|
label,
|
||||||
|
matches,
|
||||||
|
}: {
|
||||||
|
handleAlignCenter: (item: ItemTableListColumnConfig) => void;
|
||||||
|
handleAlignLeft: (item: ItemTableListColumnConfig) => void;
|
||||||
|
handleAlignRight: (item: ItemTableListColumnConfig) => void;
|
||||||
|
handleAutoSize: (item: ItemTableListColumnConfig, checked: boolean) => void;
|
||||||
|
handleChangeEnabled: (item: ItemTableListColumnConfig, checked: boolean) => void;
|
||||||
|
handleMoveDown: (item: ItemTableListColumnConfig) => void;
|
||||||
|
handleMoveUp: (item: ItemTableListColumnConfig) => void;
|
||||||
|
handlePinToLeft: (item: ItemTableListColumnConfig) => void;
|
||||||
|
handlePinToRight: (item: ItemTableListColumnConfig) => void;
|
||||||
|
handleReorder: (idFrom: string, idTo: string, edge: Edge | null) => void;
|
||||||
|
handleRowWidth: (item: ItemTableListColumnConfig, number: number | string) => void;
|
||||||
|
item: ItemTableListColumnConfig;
|
||||||
|
label: string;
|
||||||
|
matches: null | readonly Fuse.FuseResultMatch[];
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
const dragHandleRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
const [isDraggedOver, setIsDraggedOver] = useState<Edge | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ref.current || !dragHandleRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return combine(
|
||||||
|
draggable({
|
||||||
|
element: dragHandleRef.current,
|
||||||
|
getInitialData: () => {
|
||||||
|
const data = dndUtils.generateDragData({
|
||||||
|
id: [item.id],
|
||||||
|
operation: [DragOperation.REORDER],
|
||||||
|
type: DragTarget.TABLE_COLUMN,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
onDragStart: () => {
|
||||||
|
setIsDragging(true);
|
||||||
|
},
|
||||||
|
onDrop: () => {
|
||||||
|
setIsDragging(false);
|
||||||
|
},
|
||||||
|
onGenerateDragPreview: (data) => {
|
||||||
|
disableNativeDragPreview({ nativeSetDragImage: data.nativeSetDragImage });
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
dropTargetForElements({
|
||||||
|
canDrop: (args) => {
|
||||||
|
const data = args.source.data as unknown as DragData;
|
||||||
|
const isSelf = (args.source.data.id as string[])[0] === item.id;
|
||||||
|
return dndUtils.isDropTarget(data.type, [DragTarget.TABLE_COLUMN]) && !isSelf;
|
||||||
|
},
|
||||||
|
element: ref.current,
|
||||||
|
getData: ({ element, input }) => {
|
||||||
|
const data = dndUtils.generateDragData({
|
||||||
|
id: [item.id],
|
||||||
|
operation: [DragOperation.REORDER],
|
||||||
|
type: DragTarget.TABLE_COLUMN,
|
||||||
|
});
|
||||||
|
|
||||||
|
return attachClosestEdge(data, {
|
||||||
|
allowedEdges: ['top', 'bottom'],
|
||||||
|
element,
|
||||||
|
input,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDrag: (args) => {
|
||||||
|
const closestEdgeOfTarget: Edge | null = extractClosestEdge(args.self.data);
|
||||||
|
setIsDraggedOver(closestEdgeOfTarget);
|
||||||
|
},
|
||||||
|
onDragLeave: () => {
|
||||||
|
setIsDraggedOver(null);
|
||||||
|
},
|
||||||
|
onDrop: (args) => {
|
||||||
|
const closestEdgeOfTarget: Edge | null = extractClosestEdge(args.self.data);
|
||||||
|
|
||||||
|
const from = args.source.data.id as string[];
|
||||||
|
const to = args.self.data.id as string[];
|
||||||
|
|
||||||
|
handleReorder(from[0], to[0], closestEdgeOfTarget);
|
||||||
|
setIsDraggedOver(null);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [item.id, handleReorder]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(styles.item, {
|
||||||
|
[styles.draggedOverBottom]: isDraggedOver === 'bottom',
|
||||||
|
[styles.draggedOverTop]: isDraggedOver === 'top',
|
||||||
|
[styles.dragging]: isDragging,
|
||||||
|
[styles.matched]: matches && matches.length > 0,
|
||||||
|
})}
|
||||||
|
ref={ref}
|
||||||
|
>
|
||||||
|
<Group wrap="nowrap">
|
||||||
|
<DragHandle dragHandleRef={dragHandleRef} />
|
||||||
|
<Checkbox
|
||||||
|
checked={item.isEnabled}
|
||||||
|
id={item.id}
|
||||||
|
label={label}
|
||||||
|
onChange={(e) => handleChangeEnabled(item, e.currentTarget.checked)}
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
<Group wrap="nowrap">
|
||||||
|
<ActionIconGroup className={styles.group}>
|
||||||
|
<ActionIcon
|
||||||
|
icon="arrowUp"
|
||||||
|
iconProps={{ size: 'md' }}
|
||||||
|
onClick={() => handleMoveUp(item)}
|
||||||
|
size="xs"
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.moveUp', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant="subtle"
|
||||||
|
/>
|
||||||
|
<ActionIcon
|
||||||
|
icon="arrowDown"
|
||||||
|
iconProps={{ size: 'md' }}
|
||||||
|
onClick={() => handleMoveDown(item)}
|
||||||
|
size="xs"
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.moveDown', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant="subtle"
|
||||||
|
/>
|
||||||
|
</ActionIconGroup>
|
||||||
|
<ActionIconGroup className={styles.group}>
|
||||||
|
<ActionIcon
|
||||||
|
icon="arrowLeftToLine"
|
||||||
|
iconProps={{ size: 'md' }}
|
||||||
|
onClick={() => handlePinToLeft(item)}
|
||||||
|
size="xs"
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.pinToLeft', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant={item.pinned === 'left' ? 'filled' : 'subtle'}
|
||||||
|
/>
|
||||||
|
<ActionIcon
|
||||||
|
icon="arrowRightToLine"
|
||||||
|
iconProps={{ size: 'md' }}
|
||||||
|
onClick={() => handlePinToRight(item)}
|
||||||
|
size="xs"
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.pinToRight', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant={item.pinned === 'right' ? 'filled' : 'subtle'}
|
||||||
|
/>
|
||||||
|
</ActionIconGroup>
|
||||||
|
<ActionIconGroup className={styles.group}>
|
||||||
|
<ActionIcon
|
||||||
|
icon="alignLeft"
|
||||||
|
iconProps={{ size: 'md' }}
|
||||||
|
onClick={() => handleAlignLeft(item)}
|
||||||
|
size="xs"
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.alignLeft', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant={item.align === 'start' ? 'filled' : 'subtle'}
|
||||||
|
/>
|
||||||
|
<ActionIcon
|
||||||
|
icon="alignCenter"
|
||||||
|
iconProps={{ size: 'md' }}
|
||||||
|
onClick={() => handleAlignCenter(item)}
|
||||||
|
size="xs"
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.alignCenter', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant={item.align === 'center' ? 'filled' : 'subtle'}
|
||||||
|
/>
|
||||||
|
<ActionIcon
|
||||||
|
icon="alignRight"
|
||||||
|
iconProps={{ size: 'md' }}
|
||||||
|
onClick={() => handleAlignRight(item)}
|
||||||
|
size="xs"
|
||||||
|
tooltip={{
|
||||||
|
label: t('table.config.general.alignRight', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
variant={item.align === 'end' ? 'filled' : 'subtle'}
|
||||||
|
/>
|
||||||
|
</ActionIconGroup>
|
||||||
|
<NumberInput
|
||||||
|
className={clsx(styles.group, styles.numberInput)}
|
||||||
|
hideControls={false}
|
||||||
|
leftSection={
|
||||||
|
<>
|
||||||
|
{item.pinned === null && (
|
||||||
|
<Tooltip
|
||||||
|
label={t('table.config.general.autosize', {
|
||||||
|
postProcess: 'sentenceCase',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={item.autoSize}
|
||||||
|
disabled={item.pinned !== null}
|
||||||
|
id={item.id}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleAutoSize(item, e.currentTarget.checked)
|
||||||
|
}
|
||||||
|
size="xs"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
max={2000}
|
||||||
|
min={0}
|
||||||
|
onChange={(value) => handleRowWidth(item, value)}
|
||||||
|
size="xs"
|
||||||
|
step={10}
|
||||||
|
value={item.width}
|
||||||
|
variant="subtle"
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user