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 playgroundVớ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/canvas2. 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.
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.
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.
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: trueGiữ 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.
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.
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.
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.
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.
- Core: data sources, commands, quyền, events và history
- Canvas: rendering, custom editor, theme, trợ năng và tương tác
- React và Vue: lifecycle, props runtime và refs có kiểu
- Hướng dẫn thao tác dạng Markdown
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.