跳到正文
cccskills
免费在 GitHub 公开

handsontable-dev

Work on Handsontable core bugs, features, and TypeScript types using its architecture and implementation conventions. The skill directs tasks to specialist guides and outlines registration, compatibility, documentation, and testing checks for changes.

中文简介正在准备中。当前显示英语简介。

原文查看原文说明

Use for ANY work touching the `handsontable/` core package: fixing bugs, adding features, modifying TypeScript types, removing as-casts, writing or debugging plugins, editors, renderers, validators, cell types, hooks, shortcuts, selection, helpers, index translations, or i18n. Also use for how-to questions about core internals (plugin lifecycle, coordinate systems, hook registration, TypeScript conventions). Triggers on file paths under `handsontable/src/` (excluding `3rdparty/walkontable/` which has its own skill), or when the user describes a symptom in the core grid without naming a file. This is the primary entry point for all core Handsontable development, when in doubt, load it.

集成工具Playwright
查看安装方法

适用场景

  • Investigate bugs in the core grid
  • Add plugins, editors, or renderers
  • Fix TypeScript types and remove unnecessary casts
  • Check feature registration and required validation

包含的文件(1)

  • SKILL.md12.7 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Handsontable Core Development

Dispatch table

Load handsontable-code-review (architecture dimension) first for every change, then the task-specific specialist. It is the design lens (SOLID, Law of Demeter, plugin decoupling, breaking changes); the task skill is the implementation guide.

TaskSkill
Create / modify a pluginhandsontable-plugin-dev
Create / modify an editorhandsontable-editor-dev
Create / modify a rendererhandsontable-renderer-dev
Create / modify a validatorhandsontable-validator-dev
Create / modify a cell typehandsontable-celltype-dev
Write a new E2E testhandsontable-playwright-e2e (Playwright, tests/e2e/)
Maintain a legacy E2E test (*.spec.js, frozen)handsontable-e2e-testing
Write / modify unit tests (*.unit.js or *.unit.ts)handsontable-unit-testing
Make a test actually prove behaviortest-writing-discipline
Build a demo / test pagehandsontable-demo-page
Work on CSS / themeshandsontable-css-dev
Walkontable rendering enginewalkontable-dev / walkontable-testing
A rendering-engine geometry change needs a spec (viewport, overlays, sizing, scroll sync)engine tier: edit an existing walkontable Jasmine spec, or add new coverage in tests/e2e/walkontable/*.spec.ts (walkontable-dev, Testing)
Lint violationshandsontable/AGENTS.md (Lint) + handsontable/.ai/CONVENTIONS.md
Coordinate translation (physical/visual/renderable)coordinate-systems
i18n / translationsi18n-translations
Visual regression testsvisual-testing
Docs pageswriting-docs-pages

Design rules from handsontable-code-review

Full checklist: its references/architecture.md.

  • Plugin decoupling. Talk via hooks; reach another plugin only through hot.getPlugin('Name'). No circular plugin dependencies.
  • Conflict ownership. The plugin that introduces an incompatibility owns the blocking logic. For hard conflicts, call registerConflict() from src/plugins/base/conflictRegistry.ts at module load time.
  • Law of Demeter. Go through TableView or Core for Walkontable data, not this.hot.view.wt.wtTable chains.
  • Liskov. Honor the full BasePlugin contract (lifecycle methods + static properties).
  • Cascading config. New options fit cell → column → global where applicable; document table-level-only options (like data) in JSDoc.
  • Breaking changes. Keep the legacy CSS class in the DOM when renaming. Keep old API names working (no warning for legacy, one-time warning for deprecated). Keep every default setting value. Put removed hooks/options on the removed list so misuse throws.
  • Convention over configuration. Red flags: new options with the same value at every call site (make it the default), new directories outside the existing taxonomy, explicit wiring where auto-discovery works.
  • Gold standard: src/plugins/pagination/pagination.ts (plugin structure, settings validation, conflict registration, focus management).

File layout

src/plugins/{pluginName}/        index.ts, {pluginName}.ts, types.ts?, __tests__/,
                                 AGENTS.md + CLAUDE.md->AGENTS.md (required)
src/editors/{editorName}/        index.ts, {editorName}.ts
src/renderers/{rendererName}/    index.ts, {rendererName}.ts
src/validators/{validatorName}/  index.ts, {validatorName}.ts
src/cellTypes/{typeName}/        index.ts, {typeName}.ts

Unit tests are *.unit.js or *.unit.ts. New E2E is Playwright (tests/e2e/*.spec.ts); the Jasmine *.spec.js suite is frozen (edit existing specs, migrate broken ones to Playwright). .d.ts files are generated by npm run build:types into handsontable/tmp/.


TypeScript gotchas

1. Generalize the signature, add zero as casts

New code adds no as casts (as SomeType, <SomeType>value). Treat the urge to write one as a wrong type upstream. Exhaust these in order: (1) make the function/method signature generic; (2) make the shared entity generic; (3) narrow with a type guard; (4) use unknown only at a true I/O boundary. A cast is acceptable only when none apply (external/normalization boundary, known TS generic-inference gap) and carries a comment saying why. as unknown as T (double cast) is banned. Use unknown instead of any at boundaries, then narrow. After removing casts, rerun npm run test:types; some are load-bearing.

// ✗ function getFirst(items: unknown[]): SomeRow { return items[0] as SomeRow; }
// ✓ function getFirst<T>(items: T[]): T { return items[0]; }

Fix the type at its source. When the same cast repeats across consumers, make the shared structure generic with a permissive default so existing callers compile unchanged:

class TreeNode<T extends object = Record<string, unknown>> {
  data: T;
  walkDown(cb: (node: TreeNode<T>) => unknown) { /* ... */ }
}

Example: src/utils/dataStructures/tree.ts TreeNode<T>, consumed by nestedHeaders as TreeNode<HeaderNodeData>.

1a. DOM narrowing

Use isHTMLElement from src/helpers/dom/element.ts (for a Node | Element | null value) instead of x as HTMLElement, x instanceof HTMLElement, or a nodeType === Node.ELEMENT_NODE guard.

2. .d.ts files

Declarations are generated from source into handsontable/tmp/ only: hand-write no .d.ts anywhere (there is no separate types/ mirror) and edit nothing under tmp/. If a type is missing from the public API, fix the JSDoc/export in the .ts source and rerun npm run build:types.

3. import type for types

import type { HotInstance } from '../../core/types';

4. Import shared types from core/

TypeLocation
GridSettings, Events, HookKeysrc/core/settings.ts
HotInstancesrc/core/types.ts
Plugin-local typesthe plugin's own types.ts

Import these types; never paste a partial copy of GridSettings/HotInstance into the file you are editing (a local copy drifts from the real signature). When the existing type is too wide, narrow it with a generic parameter or type guard at the boundary. Consumers import the same types from the package (import type { GridSettings } from 'handsontable'); see docs/content/guides/tools-and-building/typescript-types/typescript-types.md.

Adding a new hook:

  1. Add the callback signature to GridSettings in src/core/settings.ts.
  2. Register the hook name in src/core/hooks/constants.ts / src/core/hooks/index.ts.
  3. Call Hooks.getSingleton().register('myHook') at module level in the plugin file.

5. Private fields use #, callbacks are arrow-function class fields

class MyPlugin extends BasePlugin {
  #map: HidingMap | null = null;
  #onAfterRender = (): void => { /* `this` is bound */ };
}

@private JSDoc tags and .bind(this) are forbidden.

6. Cognitive complexity ≤ 15 per function

Extract a helper to fix a violation.


Cross-cutting rules (enforced by ESLint)

RuleWhat to do
No throw new Error()throwWithCause('...', cause) from src/helpers/errors.ts
No window / document / console globalsthis.hot.rootWindow, this.hot.rootDocument, helpers from src/helpers/console.ts
No raw setTimeout / setIntervalthis.hot._registerTimeout(fn, delay) (auto-clears on hot.destroy())
No barrel importsImport from the specific submodule path (plugins/index, editors/index, renderers/index, validators/index, cellTypes/index, i18n/index are off limits). Only src/registry.ts may use barrels.
No direct cross-plugin importsHooks or this.hot.getPlugin('Name')
it() in *.spec.js must be asyncasync with await when calling HOT rendering APIs
No native toLocaleLowerCase(locale)localeLowerCase(value, locale) from helpers/string (enforced by no-restricted-syntax)

JSDoc

jsdoc/require-jsdoc is error for src/**/*.ts and scripts/**/*.mjs: every class, method, function declaration, and class field needs a block. Test and type files (*.unit.ts, *.spec.ts, *.types.ts, *.d.ts) are exempt.

  • Multiline format (root AGENTS.md), with a blank line before /** and after */.
  • {Type} in every @param and @returns, public or private. docs:api (jsdoc-to-markdown) reads compiled handsontable/tmp/ and prints these types in the API reference. Keep them in sync with the TS signature ({number|object} for number | { from: number; to: number }). The TS [80004] warning is suppressed for .ts source.
  • The {Type} must parse as JSDoc (catharsis), not TypeScript. A tuple breaks docs:api with Invalid type expression. Write @type {Array<number> | null} and keep the tuple on the TS annotation (#pastePlan: [number, number, number, number] | null). No PR check catches this: the docs path filter in .github/workflows/checks.yml covers docs/** and handsontable/package.json, not handsontable/src/**, so the break surfaces as a failing Docs Staging Deployment on the next unrelated push touching docs/**. After a JSDoc type change, build the package and run npm --prefix docs run docs:api.
  • Private # fields: a description block, no @private.
  • Descriptions state something new (what the member does or represents, with population/invalidation rules where relevant), not a restatement of its name. American English, active voice, short sentences.

DOM and data gotchas

  • Merged cells: read meta, not DOM. Read colspan/rowspan from hot.getCellMeta(row, col), not td.colSpan / td.rowSpan. MergeCells sets cellProperties.colspan via afterGetCellMeta; the DOM attribute may be missing outside the viewport and ignores custom afterGetCellMeta overrides.
  • Coordinates. Translate physical/visual/renderable with hot.rowIndexMapper / hot.columnIndexMapper (coordinate-systems skill).
  • i18n. Add constants to src/i18n/constants.ts and translations to every file in src/i18n/languages/.

Registration wiring

ComponentWire into
Pluginsrc/plugins/index.ts
Editorsrc/editors/index.ts + src/editors/factory.ts
Renderersrc/renderers/index.ts + src/renderers/factory.ts
Validatorsrc/validators/index.ts
Cell typesrc/cellTypes/index.ts
Any new option / hooksrc/dataMap/metaManager/metaSchema.ts + src/core/settings.ts

Build: type declarations

npm run build:types        # step 1: tsc emits tmp/**/*.d.ts
npm run downlevel:types    # step 2: rewrites post-TS-5.1 lib types to TS 5.1 equivalents

npm run build runs both. Run after any change to the public type surface (new export, changed parameter type, new GridSettings option). Wrappers consume handsontable/tmp/.

The dev compiler is TS 6, which infers ArrayIterator, IteratorObject (TS 5.6+) and WeakKey (TS 5.2+), absent from TS 5.1. scripts/downlevel-dts.mjs swaps them for IterableIterator<T> / object. CI job verify-emitted-types runs tsc@5.1.6 --noEmit against tmp/ and reports the leaked identifier as TS2304: Cannot find name '...'. Fix by either annotating the source with the TS 5.1 type (: IterableIterator<T>, WeakMap<object, V>) or adding a row to REPLACEMENTS in scripts/downlevel-dts.mjs.


Mandatory checklist for every change

  • Source file is .ts
  • No as / any casts introduced
  • No .d.ts files hand-edited
  • Unit tests (*.unit.js or *.unit.ts), pure logic, no mocks
  • E2E tests: Playwright in tests/e2e/ (new); legacy *.spec.js suite is frozen
  • npm run build (or build:types + downlevel:types) run if public types changed
  • Wired into all relevant index / factory files
  • Added to metaSchema.ts if a new option was introduced
  • JSDoc on every class, method, function declaration, and class field (multiline; {Type} in every @param/@returns, in sync with the TS signature; no @private on # fields)
  • No breaking change (or it is explicitly called out)
  • Changelog entry added (bin/changelog entry)

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Develop and modify the Handsontable Angular wrapper with guidance on component lifecycle, settings updates, and NgZone, which controls change detection. It also covers standalone examples, global configuration, and the build and test workflow.

中文简介正在准备中。当前显示英语简介。

  • Fix settings updates in the Angular wrapper
  • Review change detection around grid operations
  • Update examples to standalone components
handsontable/handsontable2.2万2026年10月19日 更新

Open local or public web pages in BrowserStack Live for checks on real mobile devices or desktop browsers. The skill prepares temporary access to a local server, launches the requested session, and shares its dashboard link.

中文简介正在准备中。当前显示英语简介。

  • Check a local page on an Android device
  • Open a page in Safari on an iPhone or iPad
  • Inspect behavior in a specific desktop browser
handsontable/handsontable2.2万2026年10月19日 更新

Prepare user-facing changelog entries for source code changes. The skill determines whether an entry is needed, classifies the change, writes a clear title, and uses the project CLI to create a JSON file tied to the pull request.

中文简介正在准备中。当前显示英语简介。

  • Add a changelog entry for a bug fix
  • Classify a new feature or behavior change
  • Explain a breaking change and its replacement
handsontable/handsontable2.2万2026年10月19日 更新

Explore relationships between functions and files using a prebuilt code graph, a map of code dependencies. Trace bugs, inspect callers and execution paths, and assess the impact of refactoring or proposed changes.

中文简介正在准备中。当前显示英语简介。

  • Explore callers and dependencies in unfamiliar code
  • Trace a bug across multiple files
  • Assess the impact of renaming or removing code
handsontable/handsontable2.2万2026年10月19日 更新

Work with Handsontable row and column positions by distinguishing source data, displayed order, and rendered cells. It guides index conversion and helps investigate misplaced data when sorting, filtering, hiding, or moving rows and columns.

中文简介正在准备中。当前显示英语简介。

  • Investigating misplaced rows or columns
  • Converting between source and displayed indexes
  • Combining filters with manual column movement
handsontable/handsontable2.2万2026年10月19日 更新

Create Handsontable documentation examples for JavaScript, TypeScript, React, Angular, and Vue. The skill explains source files, generated JavaScript, required imports and license settings, embedding examples in guides, and checking that each framework version displays correctly.

中文简介正在准备中。当前显示英语简介。

  • Adding a code example to a feature guide
  • Preparing examples for multiple frameworks
  • Generating JavaScript examples from TypeScript
handsontable/handsontable2.2万2026年10月19日 更新

查看 handsontable 的全部技能

报告此技能的问题