팔레트와 그리드 전송
comins-grid-layout@0.3.0
전송은 request/commit 구조입니다. DOM drop이 typed request를 만들면 패키지는 임시 engine 이동을 rollback하고, 소비자가 React 상태를 갱신하여 승인 여부를 결정합니다.
import { DashboardGrid, insertDashboardWidgetAtLayout, serializeDashboardState, useDashboardDragIn, useDashboardGrid,} from "comins-grid-layout";
let sequence = 0;
export function TransferTarget() { const target = useDashboardGrid({ initialColumns: 12 }); const paletteRef = useDashboardDragIn({ sourceId: "metric-palette", previewLayout: { w: 2, h: 2 }, createWidget: () => { const id = `metric-${++sequence}`; return { id, title: "지표", layout: { id, x: 0, y: 0, w: 2, h: 2 } }; }, });
return ( <> <button ref={paletteRef} type="button">지표 드래그</button> <DashboardGrid gridId="target-grid" acceptExternalWidgets widgets={target.widgets} onLayoutCommit={target.commands.applyLayoutSnapshot} onWidgetDropRequest={(request) => { const result = insertDashboardWidgetAtLayout( target.state, request.widget, request.targetLayout, request.targetSnapshot, ); if (result.accepted) target.commands.restoreLayout(serializeDashboardState(result.state)); }} renderWidget={(widget) => widget.title} /> </> );}useDashboardDragIn의 sourceId는 팔레트 출처, previewLayout은 drag geometry입니다. createWidget은 drag마다 새로운 안정 ID를 반환해야 합니다. dragOptions로 source 조작을 설정하고 disabled로 연결을 해제합니다.
Grid 간 전송에서는 source/target마다 고유 gridId를 지정합니다. source의 gridTransferMode는 move 또는 copy, target의 acceptExternalWidgets는 boolean 또는 predicate입니다. target은 onWidgetDropRequest를 처리합니다.
복사 모드에서는 원래 자리에 원본 모양을 남기고 + 윤곽선만 포인터를 따라갑니다. 이 정적 미리보기는 드래그 시작 시점의 표시용 복제이며 별도 React 위젯이나 엔진 노드가 아닙니다. 드롭·취소 시 제거됩니다. 같은 Grid 안에 놓으면 기존처럼 위치만 변경하며, 복사는 다른 Grid로 전송할 때 적용됩니다.
source와 target Grid의 컬럼 너비가 달라도 adapter는 포인터로 잡은 지점의 비율을 보존해 target 셀 좌표로 환산합니다. 최종 배치는 대상의 컬럼 경계와 기존 위젯 충돌에 따라 보정될 수 있습니다.
Grid source request는 transferDashboardWidget에 source/target 상태와 request 좌표, snapshot, widget ID, mode를 전달합니다. 승인 결과의 양쪽 상태를 serializeDashboardState 후 각 hook에 restoreLayout합니다. move는 source에서 위젯을 제거하고, copy는 source에 남깁니다. 두 모드 모두 ID를 유지하므로 target에 같은 ID가 있으면 거부됩니다. copy가 새 ID를 자동 생성하지는 않습니다.
거부 사유는 missing-widget, duplicate-id, not-transferable, invalid-layout입니다. 동일 상태 전송, locked/이동 불가/최소화/최대화 위젯, 잘못된 mode는 거부되며 양쪽 상태는 변경되지 않아야 합니다.
Playground: /examples/advanced/multi-grid/horizontal. 페이지의 배치 방향 컨트롤로 전송 계약은 유지한 채 가로/세로 Grid 배치를 비교합니다. 키보드용 전송 버튼도 같은 helper를 사용하지만 대상 Grid의 하단에 배치합니다. 드래그는 놓은 위치를 사용합니다.
React/Vue 예제의 A → B 전송 허용/차단 토글은 같은 위젯으로 허용 조건을 비교합니다. 차단 시 A → B 이동·복사는 드래그와 버튼 모두 적용되지 않으며 양쪽 목록을 유지합니다. B → A와 팔레트 추가는 계속 허용합니다. 드래그에는 acceptExternalWidgets를 사용하고 버튼도 같은 조건을 검사한 뒤 helper를 호출합니다. 신규 팔레트 위젯은 6×2로 추가되어 6컬럼 Grid A에서는 전체 너비, 12컬럼 Grid B에서는 절반 너비를 차지합니다.
외부 DOM 드롭 대상에서 consumer 제어 상태로 삭제하는 예제는 /examples/advanced/external-drop-trash에서 별도로 확인합니다.