"use client"; import React, { useMemo } from "react"; import { GripVertical } from "lucide-react"; import { Input } from "@/components/ui/input"; import { Checkbox } from "@/components/ui/checkbox"; import { cn } from "@/lib/utils"; import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, type DragEndEvent, } from "@dnd-kit/core"; import { SortableContext, verticalListSortingStrategy, useSortable, arrayMove, } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { FormatSegment } from "./types"; import { SEGMENT_TYPE_LABELS, buildFormattedString, SAMPLE_VALUES } from "./config"; // 개별 세그먼트 행 interface SortableSegmentRowProps { segment: FormatSegment; index: number; onChange: (index: number, updates: Partial) => void; } function SortableSegmentRow({ segment, index, onChange }: SortableSegmentRowProps) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: `${segment.type}-${index}` }); const style = { transform: CSS.Transform.toString(transform), transition, }; return (
{SEGMENT_TYPE_LABELS[segment.type]} onChange(index, { showLabel: checked === true }) } className="h-3.5 w-3.5" /> onChange(index, { label: e.target.value })} placeholder="" className={cn( "h-6 px-1 text-xs", !segment.showLabel && "text-gray-400 line-through", )} /> onChange(index, { separatorAfter: e.target.value })} placeholder="" className="h-6 px-1 text-center text-xs" /> onChange(index, { pad: parseInt(e.target.value) || 0 }) } disabled={segment.type !== "row" && segment.type !== "level"} className={cn( "h-6 px-1 text-center text-xs", segment.type !== "row" && segment.type !== "level" && "bg-gray-100 opacity-50", )} />
); } // FormatSegmentEditor 메인 컴포넌트 interface FormatSegmentEditorProps { label: string; segments: FormatSegment[]; onChange: (segments: FormatSegment[]) => void; sampleValues?: Record; } export function FormatSegmentEditor({ label, segments, onChange, sampleValues = SAMPLE_VALUES, }: FormatSegmentEditorProps) { const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 5 }, }), useSensor(KeyboardSensor), ); const preview = useMemo( () => buildFormattedString(segments, sampleValues), [segments, sampleValues], ); const sortableIds = useMemo( () => segments.map((seg, i) => `${seg.type}-${i}`), [segments], ); const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event; if (!over || active.id === over.id) return; const oldIndex = sortableIds.indexOf(active.id as string); const newIndex = sortableIds.indexOf(over.id as string); if (oldIndex === -1 || newIndex === -1) return; onChange(arrayMove([...segments], oldIndex, newIndex)); }; const handleSegmentChange = (index: number, updates: Partial) => { const updated = segments.map((seg, i) => i === index ? { ...seg, ...updates } : seg, ); onChange(updated); }; return (
{label}
라벨 구분 자릿수
{segments.map((segment, index) => ( ))}
미리보기: {preview || "(빈 값)"}
); }