콘텐츠로 이동
Data Table사용 가이드

셀 표시와 이벤트

comins-table@0.2.2

0.2.2부터 렌더링의 표준 경로는 .render입니다. 기존 속성은 0.x에서 유지하며 1.0.0 제거 대상으로 안내합니다. 전환 규칙을 참고하십시오.

Cell 값은 field로 읽고, cell.format, cell.components, cell.render로 ReactNode를 렌더링할 수 있습니다. Nested path도 지원합니다.

<CominsTable
cellSelection={false}
columns={[
{ field: "name", label: "Name" },
{
field: "profile.age",
label: "Age",
cell: {
format: ({ value }) => <strong>{String(value)} years</strong>,
tooltip: ({ row, value }) => `${row.id}: ${String(value)}`,
props: {
className: ({ value }) => (Number(value) > 40 ? "cell-age-format" : "cell-role-muted"),
disabled: ({ row }) => row.data.locked === true,
},
},
},
]}
data={data}
getRowId={(row) => row.id}
onClickCell={({ column, row, value }) => console.log(row.index, column.id, value)}
onContextMenuCell={({ event, row, column }) => {
event.preventDefault();
openCellMenu(row.id, column.id);
}}
onKeyDownCell={({ event, row, column }) => console.log(event.key, row.id, column.id)}
/>

column.cell.props.disabled는 해당 cell의 click, context menu, keydown, selection, clipboard 동작을 차단합니다.

Cell range를 확장해도 해당 Row selection은 해제하지 않습니다. 선택된 Row의 Cell은 Row selection 배경을 유지하면서 range Cell에 inset outline을 추가해 두 상태를 동시에 표현합니다. Application이 지정한 custom Row 배경의 기존 우선순위도 유지합니다.

cell.render는 사용자 커스텀 컴포넌트를 직접 렌더링합니다.

{
field: "name",
label: "Name",
cell: {
render: ({ row, column, value }) => (
<MyCell row={row} column={column} value={value} />
),
},
}

cell.components는 DataTable이 제공하는 lightweight built-in 컴포넌트만 Cell 안에 렌더링합니다. components가 있으면 기본 value/format 텍스트는 표시하지 않습니다. renderer가 있으면 format과 components를 모두 대체합니다.

{
field: "enabled",
label: "Enabled",
cell: {
components: [
{
type: "checkbox",
direction: "left",
props: ({ value }) => ({ checked: Boolean(value) }),
onCheckedChange: ({ row, checked }) => {
setData((prev) =>
prev.map((item) =>
item.id === row.id ? { ...item, enabled: checked } : item
)
);
},
},
],
},
}

Cell components는 button, input, checkbox, radio, select, toggle, progress, virtual-list를 지원합니다. menu는 Header 전용이므로 Cell에서 사용할 수 없습니다. Built-in component 이벤트는 Cell/Row click, keyboard, context menu 이벤트로 전파되지 않습니다.

input은 입력 중 외부 data를 갱신하지 않고 내부 draft만 변경합니다. Enter 또는 Blur 시점에 값이 바뀐 경우 한 번만 onChange/onValueChange를 호출합니다.

virtual-list는 하나의 Cell 안에서 여러 item을 표시합니다. 기본값은 itemHeight: 28, limit: 5, 높이는 itemHeight * 5입니다. 초기 상태는 최대 5개 preview만 렌더링하고, 항목이 5개를 초과하면 ...를 표시합니다. more: true인 경우 ...가 Row 선택 전에도 동작하는 버튼으로 렌더링되며, 클릭하면 해당 Row를 단독 선택한 뒤 전체 목록을 bounded virtual scroll로 확장합니다. searchable: true인 경우 정확히 하나의 Row가 선택되었을 때만 검색 input을 표시하고 검색 결과도 virtualized range만 렌더링합니다. item 선택 상태는 Cell 내부 일시 상태로 관리됩니다. virtual scroll로 Cell이 destroy/recreate되면 item 선택 상태는 초기화될 수 있습니다.

Virtual List Row 선택 기준:

  • 일반 Item 클릭은 해당 Item이 속한 Row만 선택합니다.
  • Ctrl/Cmd 클릭은 해당 Row의 선택을 toggle하고, Shift 클릭은 직전 anchor부터 현재 Item이 속한 Row까지 화면에 보이는 Row 범위를 선택합니다.
  • Item의 Enter와 Space 활성화도 클릭과 동일한 Row 선택 규칙을 적용합니다.
  • More는 Row 선택 전에도 동작하며, 먼저 해당 Row를 단독 선택한 다음 전체 목록을 확장합니다.
  • Search는 하나의 Row만 선택된 상태에서만 사용할 수 있습니다.
  • Item과 More 이벤트는 컴포넌트 내부에서 처리되며 onClickCell 또는 onClickRow를 호출하지 않습니다.
{
field: "items",
label: "Items",
cell: {
components: [
{
type: "virtual-list",
items: ({ row }) => row.data.items,
props: {
limit: 5,
itemHeight: 28,
more: true,
searchable: true,
},
searchFilter: ({ item, itemIndex, value }) =>
itemIndex === 0 || String(item.label).includes(value),
onClickItem: ({ item, itemIndex, value }) => {
console.log(itemIndex, item.value, value);
},
onContextMenuItem: ({ event, item }) => {
event.preventDefault();
console.log(item.value);
},
},
],
},
}

searchFilter payload는 item, itemIndex, value만 받습니다. 여기서 value는 검색 input 값입니다. 검색 input은 searchable: true이고 정확히 하나의 Row가 선택된 virtual-list Cell에만 표시됩니다.

Cell 내부 입력 컴포넌트는 immutable update로 외부 data 또는 store를 갱신해야 합니다.

Cell click은 cell selection과 함께 해당 row도 선택합니다. Ctrl/Cmd/Shift modifier가 있는 cell click도 row selection 규칙을 따릅니다.

cellSelection={false}는 cell/range selection state, data-selected, range style을 비활성화합니다. 일반 onClickCell, onDoubleClickCell, onContextMenuCell, onKeyDownCell callback과 row selection은 유지합니다. Playground의 Td Cell 예제는 cellSelection 토글 대신 포맷, 스타일, renderer, 복사/붙여넣기 차단 guard, cell event callback 중심으로 구성합니다. Cell styling 예제는 기본 COMINS mint 톤과 구분되도록 어두운 배경, 노란색 텍스트, serif/monospace font, 두꺼운 left border, uppercase 스타일을 사용합니다.

같은 column 안에서 cell을 세로로 drag하면 row reorder가 아니라 cell range selection으로 처리합니다. Row reorder는 Row drag handle에서만 수행합니다.

기본 playground 스타일은 table border를 겹치지 않게 분리하고, TH/TD의 right/bottom grid line을 1px solid로 적용합니다. Cell selection은 mint inset outline으로 표시하고, range selection은 더 연한 mint 배경색으로 표시합니다. Context menu 데이터 확인은 standalone Context Menu 예제에서 제공합니다.

Playground 검증 기준:

  • 셀 예제는 format, column props style/className/disabled, renderer, cell click, double click, context menu, keyboard event를 각각 inline Alert로 보여줍니다.
  • Cell selection 검증은 data-selected, data-range-selected, computed CSS, row selection 동시 적용 여부를 기준으로 합니다.
  • cellSelection={false} 검증은 dedicated regression test에서 cell selection style이 사라지더라도 cell callback과 row selection이 유지되는지 확인합니다.
  • 같은 column cell drag 검증은 range selection이 유지되고 row order가 변경되지 않는지 확인합니다.
  • Context menu 검증은 메뉴 클릭 후 selection 유지와 선택 메뉴 Alert 표시를 함께 확인합니다.

실행 가능한 대표 예제 · 배포 기준 원본 가이드