Core 복사·붙여넣기·채우기
0.2.0: 이 페이지의 타입과 helper는 루트
comins-table의 React 상태 계약입니다. 중립/core는 별도 타입 계약을 사용합니다. 마이그레이션 가이드에서 import 경로와 셀 정책 차이를 확인합니다.
이 함수들은 데이터와 복사 객체를 처리하며 OS clipboard에 접근하지 않습니다. 각 셀의 disabled/copyable/pasteable 규칙과 사용 가능한 행·컬럼 범위에 따라 동작합니다.
copyCominsRow
섹션 제목: “copyCominsRow”export declare function copyCominsRow<TData>(state: CominsTableState<TData>, rowId: CominsRowId): CominsCopiedRow<TData>;업무 행 참조와 JSON.stringify(row) 문자열을 반환합니다. 없는 행이면 Error를 던지며 JSON 직렬화가 불가능한 값도 예외가 날 수 있습니다. 행 복사는 셀별 복사 guard를 적용하지 않습니다.
pasteCominsRow
섹션 제목: “pasteCominsRow”export declare function pasteCominsRow<TData>(state: CominsTableState<TData>, copied: CominsCopiedRow<TData>, options: CominsPasteRowOptions<TData>): CominsTableState<TData>;append는 끝에 추가하며 새 ID 생성은 선택 사항입니다. insert-after는 대상 다음에 삽입하고 ID를 생성합니다. 0.2.0의 overwrite와 replace는 모두 대상 ID를 유지하는 얕은 병합 경로이므로 원본에 없는 대상 속성을 삭제하지 않습니다. ID 생성은 id 속성에 기록하므로 사용자 getRowId와 맞춰야 합니다.
copyCominsCell
섹션 제목: “copyCominsCell”export declare function copyCominsCell<TData>(state: CominsTableState<TData>, { columnId, rowId }: CominsCellAddress): CominsCopiedCell | null;원시 value와 문자열 text를 반환합니다. formatter를 사용하지 않으며 없는/비활성/복사 불가 셀은 null입니다.
pasteCominsCell
섹션 제목: “pasteCominsCell”export declare function pasteCominsCell<TData>(state: CominsTableState<TData>, { columnId, rowId }: CominsCellAddress, copied: CominsCopiedCell | null): CominsTableState<TData>;copied.value를 field 점 경로에 새 객체로 반영합니다. null 복사 객체·없는 셀·붙여넣기 불가 셀이면 원래 상태입니다. 문자열 타입 변환을 자동 수행하지 않습니다.
copyCominsCellRange
섹션 제목: “copyCominsCellRange”export declare function copyCominsCellRange<TData>(state: CominsTableState<TData>, range?: CominsCellRange | null, rowIds?: readonly CominsRowId[]): CominsCopiedCellRange | null;표시 컬럼과 rowIds 순서의 직사각형을 복사합니다. 복사 불가 셀은 null 자리로 남겨 위치를 보존하고 text에서는 빈 문자열로 표현합니다. text는 탭/개행을 연결한 값이며 별도 quoting을 하지 않습니다.
pasteCominsCellRange
섹션 제목: “pasteCominsCellRange”export declare function pasteCominsCellRange<TData>(state: CominsTableState<TData>, target: CominsCellAddress, copied: CominsCopiedCellRange | null, rowIds?: readonly CominsRowId[]): CominsTableState<TData>;대상 시작 셀부터 표시 순서로 덮어씁니다. null 원본 셀·범위 밖 대상·붙여넣기 불가 셀은 건너뜁니다. 0.2.0 Core에서는 허용된 부분만 반영하므로 전체 원자적 거절 API가 아닙니다.
fillCominsCellRange
섹션 제목: “fillCominsCellRange”export declare function fillCominsCellRange<TData>(state: CominsTableState<TData>, { source, target }: CominsFillCellRangeOptions, rowIds?: readonly CominsRowId[]): CominsTableState<TData>;단일 셀 또는 사각형 source의 원시 값 패턴을 target에 반복합니다. rowIds로 투영 순서를 지정할 수 있습니다. 보호된 셀은 건너뛰며 validateFill 거절 또는 예외가 발생하면 전체 Fill을 취소합니다. 원본 타입을 유지하고 parseClipboard를 거치지 않습니다. 숫자·날짜 연속값 생성은 지원하지 않습니다.
CominsCopiedRow
섹션 제목: “CominsCopiedRow”export type CominsCopiedRow<TData> = { kind: "row"; row: TData; text: string;};| 속성 | 동작·기본값 |
|---|---|
kind |
row 판별자. |
row |
복사한 행 참조. |
text |
행의 JSON 문자열. |
CominsCopiedCell
섹션 제목: “CominsCopiedCell”export type CominsCopiedCell = { kind: "cell"; text: string; value: unknown;};| 속성 | 동작·기본값 |
|---|---|
kind |
cell 판별자. |
text |
nullish는 빈 문자열, 그 외 String(value). |
value |
원시 값. |
CominsCopiedCellRangeCell
섹션 제목: “CominsCopiedCellRangeCell”export type CominsCopiedCellRangeCell = { columnId: string; text: string; value: unknown;} | null;복사 가능한 셀은 columnId/text/value를 보관하며, 복사 불가 위치는 null입니다.
CominsCopiedCellRange
섹션 제목: “CominsCopiedCellRange”export type CominsCopiedCellRange = { kind: "cell-range"; rows: CominsCopiedCellRangeCell[][]; text: string;};| 속성 | 동작·기본값 |
|---|---|
kind |
cell-range 판별자. |
rows |
위치를 유지하는 2차원 복사 셀 배열. |
text |
탭으로 열, 개행으로 행을 구분한 문자열. |
CominsPasteRowOptions
섹션 제목: “CominsPasteRowOptions”export type CominsPasteRowOptions<TData> = { getNewRowId?: (row: TData) => CominsRowId; mode: "append";} | { getPastedRowId?: (row: TData) => CominsRowId; mode: "insert-after"; targetRowId: CominsRowId;} | { mode: "overwrite" | "replace"; targetRowId: CominsRowId;};mode가 union을 판별합니다. append는 getNewRowId가 선택이고, insert-after는 targetRowId 필수/getPastedRowId 선택입니다. overwrite/replace는 targetRowId가 필수입니다. 중복되지 않는 업무 ID를 생성하고 입력 객체를 변경하지 마십시오.
CominsFillCellRangeOptions
섹션 제목: “CominsFillCellRangeOptions”export type CominsFillCellRangeOptions = { source: CominsCellAddress | CominsCellRange; target: CominsCellRange;};| 속성 | 동작·기본값 |
|---|---|
source |
복사할 단일 셀 주소 또는 anchor/focus 사각 범위. |
target |
채울 anchor/focus 사각 범위. rowIds 인수를 생략하면 state.rowIds 순서를 사용합니다. |
관련 문서
섹션 제목: “관련 문서”parseCominsClipboardText
섹션 제목: “parseCominsClipboardText”export declare function parseCominsClipboardText(text: string): string[][];파싱만 수행하며 OS 클립보드에 접근하지 않습니다. TSV의 탭, CRLF/개행, 인용된 구분자와 이중 따옴표를 처리하여 문자열 행렬을 반환합니다. 마지막 줄 구분자는 추가 행으로 만들지 않습니다. HTML·수식은 실행하지 않습니다. UTF-16 1,000,000자 또는 100,000셀 제한 초과 및 잘못된 인용 형식은 오류를 던집니다.
pasteCominsText
섹션 제목: “pasteCominsText”export declare function pasteCominsText<TData>(state: CominsTableState<TData>, target: CominsCellAddress, text: string, rowIds?: readonly CominsRowId[]): CominsTableState<TData>;대상 셀부터 표시 컬럼 순서로 문자열을 불변 반영합니다. rowIds를 생략하면 데이터 순서이며 정렬·필터 뷰에서는 투영된 ID 순서를 전달하십시오. 범위 밖은 잘라내고 보호된 셀은 위치를 유지한 채 건너뜁니다. parseClipboard로 값을 변환하며 parser·guard 실패 시 전체 작업이 오류로 종료되어 입력 상태는 유지됩니다. 실제 변경이 없으면 원래 상태를 반환합니다.
붙여넣기·채우기 예제
섹션 제목: “붙여넣기·채우기 예제”제품·수량 셀을 선택하고 TSV를 붙여넣으십시오. 범위를 드래그해 선택한 뒤 아래로 채우기를 실행하거나 모서리 핸들을 드래그할 수 있습니다. ID는 보호됩니다.
셀을 선택해 시작하십시오.
import { useRef, useState } from 'react';import { CominsTable, type CominsTableColumn, type CominsTableRef } from 'comins-table';import 'comins-table/styles.css';
type Row = { id: string; product: string; quantity: number };const initialRows: Row[] = [ { id: 'a', product: 'Notebook', quantity: 3 }, { id: 'b', product: 'Pencil', quantity: 1 }, { id: 'c', product: 'Folder', quantity: 2 }, { id: 'd', product: 'Eraser', quantity: 4 },];export default function TableClipboardDemo({ lang = 'ko' }: { lang?: string }) { const ko = lang === 'ko'; const table = useRef<CominsTableRef<Row>>(null); const [rows, setRows] = useState(initialRows); const [message, setMessage] = useState(''); const columns: CominsTableColumn<Row>[] = [ { id: 'id', field: 'id', label: 'ID', width: 80, cell: { props: { pasteable: false } } }, { id: 'product', field: 'product', label: ko ? '제품' : 'Product', width: 210 }, { id: 'quantity', field: 'quantity', label: ko ? '수량' : 'Quantity', width: 160, cell: { parseClipboard: ({ text }) => { const value = Number(text); if (!text.trim() || !Number.isFinite(value) || value < 0) throw new Error(ko ? '수량은 0 이상의 숫자여야 합니다.' : 'Quantity must be a non-negative number.'); return value; }, validateFill: ({ value }) => typeof value === 'number' && Number.isFinite(value) && value >= 0, } }, ]; const fill = (direction: 'down' | 'right') => { const changed = table.current?.fillSelection(direction); if (changed) setMessage(ko ? '선택 범위를 채웠습니다.' : 'Filled the selected range.'); }; return <div className="demo" data-demo="table-clipboard"> <p>{ko ? '제품·수량 셀을 선택하고 TSV를 붙여넣으십시오. 범위를 드래그해 선택한 뒤 아래로 채우기를 실행하거나 모서리 핸들을 드래그할 수 있습니다. ID는 보호됩니다.' : 'Select a product or quantity cell and paste TSV. Drag to select a range, then fill down or drag its corner handle. IDs are protected.'}</p> <div className="demo-toolbar"> <button onClick={() => fill('down')}>{ko ? '아래로 채우기' : 'Fill down'}</button> <button onClick={() => fill('right')}>{ko ? '오른쪽으로 채우기' : 'Fill right'}</button> <button onClick={() => { setRows(initialRows); setMessage(''); }}>{ko ? '초기화' : 'Reset'}</button> </div> <div className="table-viewport"><CominsTable ref={table} columns={columns} data={rows} getRowId={row => row.id} cellSelection rowSelectionOnClick={false} clipboard clipboardPaste fillHandle onChangeData={next => { setRows(next); setMessage(ko ? '변경을 반영했습니다.' : 'Changes applied.'); }} onClipboardError={error => setMessage(error.message)} /></div> <p role="status" className="demo-status">{message || (ko ? '셀을 선택해 시작하십시오.' : 'Select a cell to begin.')}</p> <output aria-label={ko ? '현재 수량' : 'Current quantities'}>{rows.map(row => row.quantity).join(', ')}</output> </div>;}