Skip to content

feat: migrate Header tool to the Editor.js v3 SDK#130

Open
Reversean wants to merge 8 commits into
v3from
feat/sdk-v3-migration
Open

feat: migrate Header tool to the Editor.js v3 SDK#130
Reversean wants to merge 8 commits into
v3from
feat/sdk-v3-migration

Conversation

@Reversean

@Reversean Reversean commented Jul 7, 2026

Copy link
Copy Markdown

Summary

  • Replace the legacy attachInput-based Tool API with the data-first model used by @editorjs/model/@editorjs/sdk: text and level are registered as model-backed keys, and the DOM is rendered lazily in response to adapter events instead of being built eagerly in render().
  • Add a toolbox with H1–H3 entries, conversionConfig, and canBeSplit.
  • Add unit test coverage.
  • Update README for the current API and document the workspace-only constraint below.

Supersedes #128 — that branch (heading-v3) predates the data-first refactor in document-model and calls adapter.attachInput, which no longer exists in the current SDK.

This package depends on @editorjs/model/@editorjs/sdk/@editorjs/dom-adapters via workspace:^ and is intended to be used as a git submodule inside document-model's packages/tools/header — it isn't buildable or testable standalone outside that workspace.

Note: this workspace:^ setup is a stand-in until document-model actually publishes usable (non-placeholder) versions of model/sdk/dom-adapters to npm — right now those packages are stuck at 0.0.0 and every publish run silently no-ops (Registry already knows about version 0.0.0; skipping), so real versions aren't available to depend on yet. Once that's fixed upstream, this package can move to plain semver ranges and become independently buildable/publishable again.

khaydarov and others added 3 commits April 14, 2026 20:26
Replace the legacy attachInput-based Tool API with the data-first
model used by @editorjs/model and @editorjs/sdk: register text and
level as model-backed keys and render the DOM lazily in response to
adapter events, instead of building elements eagerly in render().

Add a toolbox with H1-H3 entries, conversionConfig, and canBeSplit,
and cover the tool with unit tests.
@Reversean Reversean mentioned this pull request Jul 7, 2026
Replace the v2-era installation/config/output docs (default export,
shortcut config, plain-string text, unused levels option) with the
current named export and TextNodeSerialized-based text field.

Add a TODO note explaining this package only builds inside the
document-model workspace as a git submodule, and can't be installed
or published standalone yet.
Comment thread src/index.ts Outdated
this.#adapter.setInput('text', undefined);
this.#headingEl?.remove();
this.#headingEl = undefined;
} else if (event instanceof ValueNodeChangedEvent) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not switch/case?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with switch / case

Comment thread src/index.ts
Comment on lines +58 to +62
public static type = ToolType.Block as const;

public static name = 'header';

public static readonly options = {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please ,add jsdocs to all properties and methods because our tools will be used as an example for other developers

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment thread src/index.ts Outdated
Comment on lines +64 to +66
{ title: 'Heading 1',
icon: IconH1,
data: { level: 1 as HeadingLevel } },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bad indentation

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment thread package.json Outdated
"@editorjs/editorjs": "^2.29.1"
"@codexteam/icons": "^0.3.3",
"@editorjs/dom-adapters": "workspace:^",
"@editorjs/editorjs": "^2.30.8",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it is used only for types, it should be in dev deps

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to dev-deps dom-adapters, model, editor.js

Comment thread README.md Outdated
| Field | Type | Description |
| ------------ | -------- | ----------------------- |
| placeholder | `string` | header's placeholder string |
| defaultLevel | `number` | default heading level (1–6), used when no level is set on the block |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why "levels" configuration was dropped?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially dropped the levels because it was non-functional (even in #128).

Fully implementing levels isn't possible right now — there's an active discussion on the architecture of mechanisms like this (Block Tunes): editor-js/document-model#157 (review)

- Use switch (true) / instanceof for adapter event handling in
  #onUpdate, matching the pattern used in the base BlockToolAdapter
  that dispatches these events.
- Add JSDoc to all public and private class members.
- Reformat the toolbox array for consistent indentation.
- Move @editorjs/editorjs, @editorjs/model, and @editorjs/dom-adapters
  to devDependencies — they're only used for types, never at runtime.
Restore the levels field in the config table with an honest status:
it's declared in the type but the static per-level toolbox can't
read per-registration config, so it has no effect today. Filtering
which levels are offered belongs to a future block-settings UI
(Block Tunes) that will have access to config at selection time.
Revert to heading-v3's original README content and apply only the
three changes actually forced by this PR's code:
- named export (Header is a named, not default, export)
- text field is TextNodeSerialized, not a plain string
- workspace:^-only / submodule TODO note (package.json now needs
  model/sdk/dom-adapters, unlike heading-v3's plain editorjs dep)

Everything else (registration syntax, Shortcut, Tool's settings,
levels) was already stale or non-functional in heading-v3, predates
this PR, and is left untouched rather than "fixed" here.
- defaultLevel: cover both "missing" and "invalid" fallback cases,
  not just "missing"
- #normalizeLevel's @param: describe the parameter's contract
  (unvalidated candidate value) instead of enumerating call sites
- Use {@link render} / {@link HeaderConfig.defaultLevel} instead of
  plain-text method/field references, matching existing convention
  in dom-adapters/core/sdk
- Fix formatting drift introduced by an editor auto-format pass
  (double quotes, trailing commas) back to project style
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants