편집
셀을 바로 수정합니다. 텍스트·숫자·날짜·선택 편집기, 유효성 검사, 실행 취소, 변경 내역까지 지원합니다.
이 데모의 코드
import { createGrid, type ColumnDef, type Row } from '@freegridjs/core';
import { makeRows } from '../data';
import { button, separator, text, tr, type DemoContext } from '../ui';
const CITIES: Record<string, string[]> = {
'South Korea': ['Seoul', 'Busan', 'Incheon'],
Japan: ['Tokyo', 'Osaka', 'Kyoto'],
Germany: ['Berlin', 'Munich', 'Hamburg'],
France: ['Paris', 'Lyon', 'Marseille'],
Spain: ['Madrid', 'Barcelona', 'Valencia'],
China: ['Beijing', 'Shanghai', 'Shenzhen'],
'United States': ['New York', 'Seattle', 'Austin'],
'United Kingdom': ['London', 'Manchester', 'Leeds'],
};
export default function mount(ctx: DemoContext) {
const { lang } = ctx;
const h = (en: string, ko: string) => tr(lang, { en, ko });
const data = makeRows(300).map(r => ({ ...r, city: CITIES[r.country][r.id % 3] }));
const columns: ColumnDef[] = [
{ field: 'id', header: 'ID', type: 'number', format: '0', width: 70, pinned: 'left' },
// text editor + required
{ field: 'name', header: h('Name', '이름'), width: 170, editable: true, required: true },
// select editor
{ field: 'country', header: h('Country', '국가'), width: 150, editable: true,
editor: { type: 'select', options: Object.keys(CITIES) } },
// dependent select: options come from the row's country
{ field: 'city', header: h('City', '도시'), width: 130, editable: true,
editor: { type: 'select', options: (row: Row) => CITIES[row.country] ?? [] } },
// number editor + validation
{ field: 'q1', header: h('Q1 revenue', '1분기 매출'), type: 'number', format: '#,##0', width: 130, editable: true,
validate: v => (v == null || (typeof v === 'number' && v >= 0) ? true : h('Must be 0 or more', '0 이상이어야 합니다')) },
{ field: 'joined', header: h('Joined', '가입일'), type: 'date', width: 130, editable: true },
{ field: 'active', header: h('Active', '활성'), type: 'boolean', width: 90, editable: true }, // Space or double-click toggles
{ field: 'email', header: h('Email (read-only)', '이메일 (읽기 전용)'), width: 260 },
];
const grid = createGrid(ctx.host, {
columns, data, rowSelection: 'multiple', locale: lang,
summary: { rows: [{ label: h('Total', '합계'), columns: { q1: 'sum', id: 'count' } }] },
});
grid.on('cellValueChanged', e => ctx.log(`cellValueChanged → ${e.colId}: ${String(e.oldValue)} → ${String(e.newValue)}`));
grid.on('validationFailed', e => ctx.log(`validationFailed → ${e.colId}: ${e.message}`));
grid.on('rowsAdded', e => ctx.log(`rowsAdded → ${e.rows.length}`));
grid.on('rowsRemoved', e => ctx.log(`rowsRemoved → ${e.rows.length}`));
text(ctx, h('Double-click, press Enter or just type. Enter saves, Esc cancels, Tab moves on.',
'더블클릭하거나 Enter를 누르거나 바로 입력하세요. Enter로 저장, Esc로 취소, Tab으로 다음 칸.'));
separator(ctx);
button(ctx, h('Add row', '행 추가'), () => {
const [row] = grid.addRows([{ id: 1000 + grid.getData().length, name: '', country: 'South Korea', city: 'Seoul', q1: 0, active: true }], 0);
grid.scrollToRow(0);
grid.startEdit(0, 'name');
return row;
});
button(ctx, h('Delete selected', '선택 행 삭제'), () => grid.removeSelectedRows());
button(ctx, h('Undo', '실행 취소'), () => grid.undo());
button(ctx, h('Redo', '다시 실행'), () => grid.redo());
separator(ctx);
button(ctx, h('Show changes', '변경 내역 보기'), () => {
const m = grid.getModifiedRows();
ctx.log(h(`created ${m.created.length}, updated ${m.updated.length}, deleted ${m.deleted.length}`,
`추가 ${m.created.length}, 수정 ${m.updated.length}, 삭제 ${m.deleted.length}`));
for (const c of grid.getChanges().slice(0, 10)) ctx.log(` #${c.row.id} ${c.colId}: ${String(c.oldValue)} → ${String(c.newValue)}`);
});
button(ctx, h('Save (commit)', '저장 (commit)'), () => {
grid.commitChanges();
ctx.log(h('changes committed — this is where you would send them to your server', '변경 확정 — 실제로는 여기서 서버로 보냅니다'));
});
button(ctx, h('Revert all', '모두 되돌리기'), () => grid.revertChanges());
return grid;
}