From 41f5669812be9326427e715f6bdad0f0b02f9889 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sun, 18 Oct 2026 02:03:05 +0700 Subject: [PATCH] =?UTF-8?q?feat(design-preview):=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D1=82=D0=B0=D1=81=D0=BA=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=20=D0=B2=20=C2=AB=D0=A1?= =?UTF-8?q?=D1=81=D1=8B=D0=BB=D0=BA=D0=B0=D1=85=20=D0=BF=D1=80=D0=B8=D0=BB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B9=C2=BB=20=D1=87=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B7=20dnd-kit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PreviewSectionGrid получил onReorder: ручка DataGridTableDndRowHandle и DataGridTableDndRows из ReUI. Порядок меняется перетаскиванием, меню строки осталось запасным путём. Co-Authored-By: Claude Sonnet 5.5 --- .../design-preview/pages/app-links-page.tsx | 18 +++++--- apps/web/src/design-preview/section-grid.tsx | 41 +++++++++++++++++-- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/apps/web/src/design-preview/pages/app-links-page.tsx b/apps/web/src/design-preview/pages/app-links-page.tsx index 38b6e1f..11c68e7 100644 --- a/apps/web/src/design-preview/pages/app-links-page.tsx +++ b/apps/web/src/design-preview/pages/app-links-page.tsx @@ -4,7 +4,6 @@ import { CloudIcon, EyeIcon, FingerprintIcon, - GripVerticalIcon, KeyRoundIcon, LayoutDashboardIcon, LayoutGridIcon, @@ -141,6 +140,15 @@ export function AppLinksPage() { [addChange], ) + /** Перетаскивание: строка встаёт на место той, на которую её бросили. */ + const dropOn = useCallback( + (activeId: string, overId: string) => { + const to = rowsRef.current.findIndex((r) => r.id === overId) + if (to >= 0) moveTo(activeId as AppId, () => to) + }, + [moveTo], + ) + const resetOrder = useCallback(() => { const before = rowsRef.current if (before.every((r, i) => r.id === INITIAL[i]?.id)) return @@ -158,10 +166,9 @@ export function AppLinksPage() { { id: 'order', title: '№', - size: 76, + size: 52, cell: (r) => ( - - + {rows.findIndex((x) => x.id === r.id) + 1} ), @@ -267,7 +274,7 @@ export function AppLinksPage() { r.id} @@ -296,6 +303,7 @@ export function AppLinksPage() { )} + onReorder={dropOn} onRowClick={setEditing} /> diff --git a/apps/web/src/design-preview/section-grid.tsx b/apps/web/src/design-preview/section-grid.tsx index 6e9bc71..18d7e24 100644 --- a/apps/web/src/design-preview/section-grid.tsx +++ b/apps/web/src/design-preview/section-grid.tsx @@ -6,6 +6,11 @@ import { DataGrid, dataGridFeatures, type DataGridFeatures } from '@/components/ import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header' import { DataGridPagination } from '@/components/reui/data-grid/data-grid-pagination' import { DataGridScrollArea } from '@/components/reui/data-grid/data-grid-scroll-area' +import { + DataGridTableDndRowHandle, + DataGridTableDndRows, +} from '@/components/reui/data-grid/data-grid-table-dnd-rows' +import type { DragEndEvent } from '@dnd-kit/core' import { DataGridTable, DataGridTableRowSelect, @@ -40,6 +45,7 @@ export type GridColumn = { export type GridView = { label: string; match: (row: T) => boolean } const SELECT_COLUMN_SIZE = 44 +const DRAG_COLUMN_SIZE = 44 /** * Секция-таблица макета: Frame + Filters-подобная панель + DataGrid на DataGridScrollArea. @@ -59,6 +65,7 @@ export function PreviewSectionGrid({ selectable = false, bulkActions, toolbar, + onReorder, pageSize = 8, emptyMessage = 'Нет записей по текущим фильтрам.', className, @@ -75,6 +82,8 @@ export function PreviewSectionGrid({ selectable?: boolean bulkActions?: (selectedIds: string[], clear: () => void) => ReactNode toolbar?: ReactNode + /** Включает перетаскивание строк (dnd-kit). Передаёт id строки и id строки, на место которой её бросили. */ + onReorder?: (activeId: string, overId: string) => void pageSize?: number emptyMessage?: string className?: string @@ -113,6 +122,16 @@ export function PreviewSectionGrid({ const defs = useMemo[]>(() => { const list: ColumnDef[] = [] + if (onReorder) { + list.push({ + id: 'drag', + header: () => Порядок, + cell: () => , + enableSorting: false, + enableResizing: false, + size: DRAG_COLUMN_SIZE, + }) + } if (selectable) { list.push({ id: 'select', @@ -140,7 +159,7 @@ export function PreviewSectionGrid({ }) } return list - }, [columns, selectable]) + }, [columns, selectable, onReorder]) const table = useTable({ features: dataGridFeatures, @@ -154,7 +173,17 @@ export function PreviewSectionGrid({ onPaginationChange: setPagination, }) - const minWidth = columns.reduce((sum, c) => sum + c.size, selectable ? SELECT_COLUMN_SIZE : 0) + const dataIds = table.getRowModel().rows.map((r) => r.id) + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event + if (!onReorder || !active || !over || active.id === over.id) return + onReorder(String(active.id), String(over.id)) + } + + const minWidth = columns.reduce( + (sum, c) => sum + c.size, + (selectable ? SELECT_COLUMN_SIZE : 0) + (onReorder ? DRAG_COLUMN_SIZE : 0), + ) const selectedIds = table.getSelectedRowModel().rows.map((r) => r.id) const paged = data.length > pageSize @@ -165,7 +194,7 @@ export function PreviewSectionGrid({ recordCount={data.length} onRowClick={onRowClick} emptyMessage={emptyMessage} - tableLayout={{ headerSticky: false, dense: true, width: 'auto' }} + tableLayout={{ headerSticky: false, dense: true, width: 'auto', rowsDraggable: Boolean(onReorder) }} > @@ -226,7 +255,11 @@ export function PreviewSectionGrid({ ) : null}
- + {onReorder ? ( + + ) : ( + + )}