Core copy, paste & fill
0.2.0: Types and helpers on this page use the React-state contract from the root
comins-tableentry. Neutral/corehas a separate type contract. See the migration guide for imports and cell policies.
These functions operate on data and copied objects without accessing the OS clipboard. Cell operations honor disabled/copyable/pasteable rules and available row/column bounds.
copyCominsRow
Section titled “copyCominsRow”export declare function copyCominsRow<TData>(state: CominsTableState<TData>, rowId: CominsRowId): CominsCopiedRow<TData>;Returns the business row reference and JSON.stringify(row). A missing row throws Error; non-serializable values may also throw. Row copying does not apply per-cell copy guards.
pasteCominsRow
Section titled “pasteCominsRow”export declare function pasteCominsRow<TData>(state: CominsTableState<TData>, copied: CominsCopiedRow<TData>, options: CominsPasteRowOptions<TData>): CominsTableState<TData>;append adds at the end with optional new-ID generation. insert-after inserts after the target and generates an ID. In 0.2.0, overwrite and replace both shallow-merge while retaining the target ID; target-only properties are not removed. Generated IDs are assigned to the id property and must agree with your getRowId.
copyCominsCell
Section titled “copyCominsCell”export declare function copyCominsCell<TData>(state: CominsTableState<TData>, { columnId, rowId }: CominsCellAddress): CominsCopiedCell | null;Returns raw value and string text without using a formatter. Missing, disabled or non-copyable cells return null.
pasteCominsCell
Section titled “pasteCominsCell”export declare function pasteCominsCell<TData>(state: CominsTableState<TData>, { columnId, rowId }: CominsCellAddress, copied: CominsCopiedCell | null): CominsTableState<TData>;Writes copied.value immutably through the dotted field path. A null copy, missing cell or non-pasteable cell returns the original state. No automatic string type conversion is performed.
copyCominsCellRange
Section titled “copyCominsCellRange”export declare function copyCominsCellRange<TData>(state: CominsTableState<TData>, range?: CominsCellRange | null, rowIds?: readonly CominsRowId[]): CominsCopiedCellRange | null;Copies a rectangle in visible-column/rowIds order. Non-copyable cells remain null placeholders and become empty strings in text. text joins values with tabs/newlines without additional quoting.
pasteCominsCellRange
Section titled “pasteCominsCellRange”export declare function pasteCominsCellRange<TData>(state: CominsTableState<TData>, target: CominsCellAddress, copied: CominsCopiedCellRange | null, rowIds?: readonly CominsRowId[]): CominsTableState<TData>;Overwrites from the target origin in displayed order. Null source cells, out-of-bounds targets and non-pasteable cells are skipped. The 0.2.0 Core helper can apply an allowed subset; it does not reject the whole operation atomically.
fillCominsCellRange
Section titled “fillCominsCellRange”export declare function fillCominsCellRange<TData>(state: CominsTableState<TData>, { source, target }: CominsFillCellRangeOptions, rowIds?: readonly CominsRowId[]): CominsTableState<TData>;Repeats raw values from a single source cell or rectangular source pattern across the target. Pass rowIds for projected order. Protected cells are skipped; validateFill rejection or an exception cancels the entire fill. Preserves source types without calling parseClipboard. Numeric/date series are not generated.
CominsCopiedRow
Section titled “CominsCopiedRow”export type CominsCopiedRow<TData> = { kind: "row"; row: TData; text: string;};| Property | Behavior / default |
|---|---|
kind |
row discriminator. |
row |
Reference to the copied row. |
text |
JSON text of the row. |
CominsCopiedCell
Section titled “CominsCopiedCell”export type CominsCopiedCell = { kind: "cell"; text: string; value: unknown;};| Property | Behavior / default |
|---|---|
kind |
cell discriminator. |
text |
Empty for nullish values, otherwise String(value). |
value |
Raw value. |
CominsCopiedCellRangeCell
Section titled “CominsCopiedCellRangeCell”export type CominsCopiedCellRangeCell = { columnId: string; text: string; value: unknown;} | null;Copyable cells store columnId/text/value; non-copyable positions are null.
CominsCopiedCellRange
Section titled “CominsCopiedCellRange”export type CominsCopiedCellRange = { kind: "cell-range"; rows: CominsCopiedCellRangeCell[][]; text: string;};| Property | Behavior / default |
|---|---|
kind |
cell-range discriminator. |
rows |
Two-dimensional copied cells preserving their positions. |
text |
Tab-separated columns and newline-separated rows. |
CominsPasteRowOptions
Section titled “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 discriminates the union. append optionally accepts getNewRowId; insert-after requires targetRowId and optionally accepts getPastedRowId; overwrite/replace require targetRowId. Generate unique business IDs without mutating inputs.
CominsFillCellRangeOptions
Section titled “CominsFillCellRangeOptions”export type CominsFillCellRangeOptions = { source: CominsCellAddress | CominsCellRange; target: CominsCellRange;};| Property | Behavior / default |
|---|---|
source |
Single source cell address or anchor/focus rectangle. |
target |
Anchor/focus rectangle to fill. Uses state.rowIds order unless rowIds is supplied. |
Related documentation
Section titled “Related documentation”parseCominsClipboardText
Section titled “parseCominsClipboardText”export declare function parseCominsClipboardText(text: string): string[][];Parses text without accessing the OS clipboard. Supports TSV tabs, CRLF/newlines, quoted delimiters and doubled quotes, returning a string matrix. A trailing row delimiter does not add another row. HTML and formulas are never executed. Malformed quoting or limits above 1,000,000 UTF-16 code units or 100,000 cells throw an error.
pasteCominsText
Section titled “pasteCominsText”export declare function pasteCominsText<TData>(state: CominsTableState<TData>, target: CominsCellAddress, text: string, rowIds?: readonly CominsRowId[]): CominsTableState<TData>;Immutably applies text starting at the target cell in visible column order. Without rowIds, uses data order; pass projected IDs for sorted/filtered views. Clips out-of-bounds data and skips protected cells without shifting positions. Uses parseClipboard for conversion. Parser/guard errors reject the entire operation and preserve the input state. Returns the original state when nothing changes.
Paste and fill example
Section titled “Paste and fill example”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.
Select a cell to begin.
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>;}