HƯỚNG DẪN LẬP TRÌNH / BẢN PHÁT TRIỂN

Từ dữ liệu đến bảng tương tác.

Core quản lý trạng thái. Renderer quản lý tương tác. Ứng dụng quản lý lưu trữ.

1. Build từ mã nguồn

Packages chưa phát hành lên npm. Dùng Node.js 22 trở lên và bản checkout của repository.

git clone https://github.com/haodn-dev/acheron-grid.git
cd acheron-grid
npm ci
npm run build
npm run playground

Với ứng dụng riêng, cài các package đã build qua đường dẫn local bằng package manager.

npm install /path/to/acheron-grid/packages/core /path/to/acheron-grid/packages/canvas
Core TypeScript độc lập giao diện quản lý trạng thái và lệnh. Canvas vẽ ô và xử lý tương tác. React, Vue hoặc TypeScript thuần kết nối bảng với ứng dụng của bạn.

2. Mount bảng

Container phải có chiều rộng và chiều cao lớn hơn 0. Dùng row ID ổn định và column key rõ ràng.

import { LocalDataSource } from '@acheron-grid/core';
import { createGrid } from '@acheron-grid/canvas';

const source = new LocalDataSource([
  { id: 1, title: 'Hello grid' }
], row => row.id);
const grid = createGrid({
  container: document.querySelector('#grid'),
  columns: [{ key: 'title', title: 'Title', editable: true }],
  dataSource: source
});
// On unmount:
grid.destroy();

3. Cấu hình tương tác

Định nghĩa parser từng cột để kiểm tra đầu vào. Tách quyền sửa, chọn, clipboard và định dạng. Cell renderer nhận giá trị và metadata định dạng; option renderer nhận column key.

  • Chỉnh sửa: Enter hoặc F2 mở editor văn bản/lựa chọn; Enter bật/tắt ô checkbox.
  • Định dạng: Ctrl/Cmd+B và I định dạng các ô đã chọn; khi đang sửa rich text, chúng định dạng phần văn bản được chọn.
  • Liên kết: hover hoặc chọn ô để xem nút mở từng liên kết an toàn.
  • Cấu trúc: chọn nguyên hàng/cột để đổi thứ tự, chèn hoặc xóa qua các thao tác có sẵn.
  • Rich text: HTML được chuyển thành text runs an toàn; Markdown dùng parser adapter tùy chọn.

Xem tài liệu package Canvas để biết đầy đủ options. Nhánh mặc định của repository có thể khác bản local này.

Editor và kiểm tra dữ liệu

Dùng parser từng cột để kiểm tra văn bản trước khi lưu hoặc dán. Ném lỗi rõ nghĩa để giữ bản nháp cho người dùng sửa. API updates nhận giá trị đã kiểm tra, không chạy column parser.

columnEditors: {
  priority: { type: 'select', values: ['High', 'Medium', 'Low'] },
  tags: { type: 'multiselect', values: ['Idea', 'Design', 'Content'] },
  approved: { type: 'checkbox' }
},
choiceEditor: { placeholder: 'Find an option…', maxHeight: 220 },
multilineEditor: true,
wrapText: true,
editorOptions: { pinned: true, showLabel: 'scroll', guardNavigation: true }

Đặt các options này cùng columns và data source khi tạo grid. Multiselect lưu chuỗi phân cách dấu phẩy; nhãn không được có dấu phẩy. Up/Down di chuyển, Space chọn/bỏ, Enter/Apply lưu, Escape/Cancel hủy. Renderer của option và cell nên dùng cùng bảng màu.

Thử editor & kiểm tra dữ liệu ↗

Menu chuột phải có tìm kiếm

Bấm phải ô, index hàng, header hoặc Shift+F10. Gõ khi menu mở để lọc thao tác; dùng mũi tên và Enter để chọn, Escape để đóng. Thao tác phụ thuộc selection, quyền và cấu hình: clipboard, chọn hàng/cột, định dạng, khóa, cố định, resize, insert/delete/move, merge và group. Menu header có sort/filter; thao tác bị tắt giải thích giới hạn.

Thử menu có tìm kiếm ↗ · Thử sort và filter ↗

Selection và clipboard

Click và Shift-click chọn hình chữ nhật. Ctrl/Cmd-click thêm vùng. Index và grouped header chọn cả phạm vi. Shift+Space chọn hàng, Ctrl/Cmd+Space chọn cột. Shift+F10 mở menu lọc khi gõ.

grid.selectRow(0);
const tsv = grid.copySelection();
grid.paste(tsv);

Paste kiểm tra mọi đích, quyền và parser trước một command nguyên tử; không tự tạo hàng thiếu. TSV chỉ trao đổi giá trị; clipboard nội bộ và API có cấu trúc có thể giữ rich style và offset vùng. Không mặc định ứng dụng khác giữ cùng định dạng. Giới hạn 100.000 ô và 10 triệu đơn vị UTF-16.

Thử selection & bàn phím ↗

Giá trị, events và history

grid.updateCells([
  { rowIndex: 0, columnKey: 'title', value: 'Lorem ipsum' }
]);
grid.undo();
grid.redo();

Dùng row ID và column key ổn định. LocalDataSource hỗ trợ batch đồng bộ nguyên tử; source tùy chỉnh cần setValues nguyên tử khi ghi nhiều ô. Sửa giá trị, định dạng, resize/freeze và cấu trúc dùng cùng history có giới hạn. Locks ngoài history; đo hàng tự động không phải command người dùng. Replay kiểm tra lại quyền và có thể từ chối thay đổi bên ngoài xung đột.

Dùng onEvent để theo dõi domain events đã commit như cell:change và structure:change. Notifications không rollback thay đổi đã commit. Ghi thẳng vào source bỏ qua history; ứng dụng quản lý lưu trữ.

Tìm kiếm, sort và filter

grid.openSearch();
grid.setView({
  sort: { columnKey: 'title', direction: 'asc' },
  filters: [{ columnKey: 'title', operator: 'contains', query: 'Lorem' }]
});
grid.setView({});

Search tô sáng text đang hiển thị. Local view sort một cột, kết hợp filters bằng AND; có contains, equals, not-empty, empty. Khi dùng onViewChange, thêm viewMode: 'core' để giữ state. Tọa độ hàng public theo thứ tự hiển thị; permission resolver và domain event không phải selection dùng tọa độ source và ID ổn định.

Xóa view trước thao tác cấu trúc; bỏ merge/group trước sort/filter. Chi phí filter/sort in-memory vẫn theo kích thước source.

Thử tìm kiếm, sort & filter ↗

Header nhiều cấp, freeze và resize

headerGroups: [{ title: 'Availability', children: [
  { title: 'Channels', children: ['online', 'onsite'] },
  { title: 'Delivery', children: ['shipping'] }
] }],
headerHeight: 28,
autoRowHeight: true,
wrapText: true

Giữ columns phẳng; grouped leaves phải duy nhất, liền nhau, đúng thứ tự cột. Header height là chiều cao mỗi hàng header. Header cha được tô màu khi chọn cột con.

grid.setFrozen(1, 1);
grid.setColumnWidth(1, 240);
grid.setRowHeight(0, 64);

Số freeze không tính header/index. Resize xem đường hướng dẫn rồi áp dụng khi thả. Auto-fit theo nội dung đang nhìn thấy; auto row height đo mọi cột của hàng visible. Kích thước đặt thủ công ưu tiên. Vùng freeze quá lớn có thể chiếm hết viewport.

Thử header, freeze & resize ↗

Cấu trúc, merge và nhóm hàng

Bật kéo bằng onReorder và áp dụng move qua API public. beforeIndex là ranh giới chèn trước khi bỏ vị trí cũ. Host tạo row ID/giá trị mặc định qua onRowChange. allowColumnChanges bật menu tạo/xóa cột.

onReorder: request => {
  if (request.axis === 'row') grid.moveRows(request.indices, request.beforeIndex);
  else grid.moveColumns(request.indices, request.beforeIndex);
}

Callback chạy sau mount, khi grid đã có. Dùng canChangeStructure kiểm tra quyền áp dụng cả command và replay. Các cột cùng nhóm phải liền nhau.

grid.mergeCells({ startRow: 2, endRow: 3, startColumn: 1, endColumn: 2 });
const groupId = grid.groupRows(3, 6);
grid.setGroupCollapsed(groupId, true);
grid.setGroupCollapsed(groupId, false);
grid.ungroupRows(groupId);

Range bao gồm cả điểm cuối. Merge giữ giá trị bên dưới để unmerge; row group là nhóm thủ công, không tổng hợp. Mở group và unmerge ô liên quan trước thay đổi cấu trúc không tương thích.

Thử thao tác hàng/cột ↗ · Thử merge & group ↗

Rich text, ảnh và liên kết an toàn

import { markdownToHtml } from '@acheron-grid/markdown';

// createGrid options:
richTextColumns: { notes: 'markdown', description: 'html' },
markdownToHtml,
imageColumns: ['avatar']

Markdown adapter là tùy chọn; core/Canvas không phụ thuộc parser. Người dùng thấy nội dung có định dạng, host lưu source strings. HTML hỗ trợ gạch dưới; Markdown không bổ sung cú pháp gạch dưới. Ctrl/Cmd+B/I định dạng từ đang chọn khi sửa hoặc ô được chọn khi không sửa.

Canvas chỉ vẽ text runs giới hạn, không mount HTML hoặc chạy handlers. Đây không phải sanitizer tổng quát để chèn HTML lưu trữ vào DOM khác. Ảnh visible được tải với anonymous CORS; chưa có upload/crop. Hover/focus ô liên kết để thấy nút mở từng URL an toàn.

Thử rich text & liên kết ↗

Quyền, khóa và tùy chỉnh

resolveCellPermission: cell => cell.rowId === 'protected'
  ? { writable: false }
  : undefined,
permissions: { formatting: false }

Selection, copy, paste, editing, writing, formatting là các quyền độc lập. false rõ ràng vẫn có quyền phủ quyết ở scope cụ thể hơn. Hàng chỉ đọc vẫn có thể chọn/copy. Đổi policy động cần grid.render() để cập nhật controls; commit editor kiểm tra lại policy.

grid.setLocked({ scope: 'row', rowIndex: 0 }, true);
grid.format([{ scope: 'column', columnIndex: 1 }], { background: '#fff0dd' });
grid.setTheme({ selectionColor: '#d44b21', iconColor: '#334155' });

Khóa áp dụng cho ô/hàng/cột/bảng. Mở khóa ô không gỡ khóa hàng/bảng liên quan. Freeze giữ nội dung visible, không cấm sửa. Đổi theme giữ mount; renderCell/createEditor tùy chỉnh hiển thị. Renderer phải tôn trọng format fields hỗ trợ. Policy client không thay thế xác thực server.

Thử định dạng & quyền ↗

Xử lý lỗi

  • Bảng trống: kiểm tra kích thước container, số hàng source, column keys và console trình duyệt.
  • Không sửa được: kiểm tra editable, parsers, setters, quyền đã resolve và khóa.
  • Markdown bị từ chối: cung cấp callback markdownToHtml đồng bộ.
  • Không hiện ảnh: kiểm tra URL, CORS và phản hồi server.
  • Move/đổi view bị từ chối: kiểm tra draft đang mở, view, group, merge và policy của host.
  • Không có undo: ghi trực tiếp vào source và đo tự động không đi qua user history.

Luôn destroy grid khi host unmount. Xem hướng dẫn thực hành Markdown đầy đủ và contracts từng package để biết chi tiết giới hạn.

React và Vue

Các package @acheron-grid/react và @acheron-grid/vue quản lý Canvas mount/unmount, refs có kiểu và chuyển tiếp events từ core. Giữ options ổn định; cập nhật theme, view, freeze qua props runtime mà không remount.

Đọc ví dụ React và Vue dạng Markdown để xem component đầy đủ, phiên bản peer và lifecycle contracts. Cả hai adapter render container rỗng khi SSR; framework nằm ngoài core headless.

4. Đọc cùng trợ lý AI

Bắt đầu với mục lục tài liệu public, sau đó đọc Ghi chú tích hợp AI. Markdown có ví dụ cụ thể và giới hạn đã triển khai. Không công khai thông tin xác thực hoặc kế hoạch nội bộ.

MCP adapter tùy chọn đã cung cấp tài liệu và công cụ đọc/sửa do host duyệt. Xem tài liệu MCP để cấu hình stdio và xem giới hạn. Playground trên trình duyệt không tự kết nối.

Xem tài liệu năm package và ghi chú AI ↗

Tài liệu API và ví dụ chi tiết

Hướng dẫn này bao gồm quy trình phổ biến, không phải mọi option/method. Xem tài liệu package để biết contracts, mặc định, callback payloads và trường hợp đặc biệt.

Hướng dẫn này chưa có API reference tự sinh có tìm kiếm hoặc ví dụ chạy được cho mọi renderer/editor. Tài liệu repository có thể thuộc revision khác bản local.

Giới hạn hiện tại

Đây là bản phát triển thử nghiệm. Chưa có remote data source, cộng tác, công thức hay MCP browser bridge tự động. Thay đổi demo chỉ ở phiên hiện tại. Virtualization không làm filter in-memory độc lập với kích thước dữ liệu.

Giấy phép MIT, bản quyền Hao Duong. Chưa công bố hiệu năng production hoặc chứng nhận trợ năng.