좌우 컬럼 고정과 배치 복원
Name을 왼쪽, Status를 오른쪽에 고정하고 가로 스크롤·폭 축소·배치 복원을 확인합니다.
조작 순서
섹션 제목: “조작 순서”- 가로 스크롤바를 오른쪽으로 움직입니다. Name과 Status는 해당 가장자리에 남고 가운데 Team·Email·Region은 스크롤됩니다.
- 배치 저장 → 고정 해제를 누릅니다. 모든 컬럼이 가운데 영역으로 바뀝니다. 저장 배치 복원으로 고정 설정을 되돌립니다.
- 260px 폭을 누릅니다. 고정 폭이 가용 공간을 초과하면 일부 고정 열이 임시로 스크롤 영역에 들어갑니다.
- 설정 조회로
pinned값이 남아 있음을 확인하고 원래 폭으로 돌아옵니다. 공간이 확보되면 고정 표시가 복원됩니다.
설정과 저장 계약
섹션 제목: “설정과 저장 계약”| 값/API | 역할 |
|---|---|
columns[].pinned |
"left" 또는 "right"로 초기 고정 위치를 지정합니다. |
getColumnLayout() |
현재 order, width, visibility, pinned 설정을 조회합니다. |
setColumnLayout(layout) |
조회한 구조를 다시 적용합니다. 원본 행 데이터의 저장·복원은 아닙니다. |
onChangeColumnLayout |
예제의 배치 JSON 표시를 갱신합니다. |
저장 버튼은 메모리에 snapshot을 보관합니다. 페이지를 새로고침하면 저장값이 사라집니다. ID가 같은 컬럼 정의와 호환되는 배치를 사용하십시오. 조회와 변경은 별도 이벤트에서 수행합니다.
좁은 화면의 표시
섹션 제목: “좁은 화면의 표시”패키지는 가운데 스크롤 영역에 최소 48px를 확보합니다. 고정 너비가 이를 침범하면 더 넓은 쪽의 안쪽 고정 블록부터 임시 해제하며, 같은 너비이면 오른쪽이 우선입니다. 이 예제는 left 140px, right 130px입니다. 260px에서는 Name의 effective pin이 해제될 수 있지만 저장된 pinned: "left" 설정은 유지됩니다.
이 표시 조정은 구성 값을 바꾸거나 onChangeColumnLayout을 발생시키는 작업이 아닙니다. 고정된 컬럼의 직접 resize 제한과 컨테이너 resize에 따른 임시 해제는 다른 동작입니다.
범위와 관련 문서
섹션 제목: “범위와 관련 문서”이 예제는 flat data의 Header/Body와 개별 열을 다룹니다. Header Group, Summary 경계, resize gesture, Tree 조합을 모두 검증하는 예제가 아닙니다. Tree에는 Column Pinning을 적용하지 않습니다.
컬럼 고정 가이드 · getColumnLayout · setColumnLayout
직접 실행
섹션 제목: “직접 실행”import { useRef, useState } from 'react';import { CominsTable, type CominsTableColumn, type CominsTableRef, type CominsColumnLayout } from 'comins-table';import 'comins-table/styles.css';type Row = { id: string; name: string; team: string; email: string; region: string; status: string };const rows: Row[] = [ { id: 'alpha', name: 'Alpha', team: 'Design', email: 'alpha@example.test', region: 'Seoul', status: 'Active' }, { id: 'beta', name: 'Beta', team: 'Engineering', email: 'beta@example.test', region: 'Busan', status: 'Pending' },];const columns: CominsTableColumn<Row>[] = [ { id: 'name', field: 'name', label: 'Name', width: 140, pinned: 'left' }, { id: 'team', field: 'team', label: 'Team', width: 200 }, { id: 'email', field: 'email', label: 'Email', width: 260 }, { id: 'region', field: 'region', label: 'Region', width: 200 }, { id: 'status', field: 'status', label: 'Status', width: 130, pinned: 'right' },];export default function TablePinningDemo({ lang = 'ko' }: { lang?: string }) { const ko = lang === 'ko'; const table = useRef<CominsTableRef<Row>>(null); const [saved, setSaved] = useState<CominsColumnLayout | null>(null); const [layout, setLayout] = useState<CominsColumnLayout | null>(null); const [narrow, setNarrow] = useState(false); return <div className="demo" data-demo="table-pinning"> <div className="demo-toolbar"> <button onClick={() => { const next = table.current?.getColumnLayout(); if (next) { setSaved(next); setLayout(next); } }}>{ko ? '배치 저장' : 'Save layout'}</button> <button onClick={() => { const next = table.current?.getColumnLayout(); if (next) table.current?.setColumnLayout({ ...next, columns: Object.fromEntries(Object.entries(next.columns).map(([id, column]) => [id, { ...column, pinned: undefined }])) }); }}>{ko ? '고정 해제' : 'Unpin columns'}</button> <button disabled={!saved} onClick={() => { if (saved) table.current?.setColumnLayout(saved); }}>{ko ? '저장 배치 복원' : 'Restore layout'}</button> <button onClick={() => setNarrow(value => !value)}>{narrow ? (ko ? '원래 폭' : 'Full width') : (ko ? '260px 폭' : '260px width')}</button> <button onClick={() => setLayout(table.current?.getColumnLayout() ?? null)}>{ko ? '설정 조회' : 'Inspect configuration'}</button> </div> <div className="table-viewport" style={{ width: narrow ? 260 : '100%', maxWidth: '100%' }}> <CominsTable ref={table} columns={columns} data={rows} getRowId={row => row.id} onChangeColumnLayout={setLayout} /> </div> <p>{ko ? '아래 가로 스크롤바를 움직여 Name과 Status 위치를 비교하십시오.' : 'Use the horizontal scrollbar below the table to compare Name and Status positions.'}</p> <details><summary>{ko ? '설정된 컬럼 배치' : 'Configured column layout'}</summary><pre data-pinning-layout>{JSON.stringify(layout, null, 2)}</pre></details> </div>;}