Skip to content

InlineToolbar implementation#153

Open
gohabereg wants to merge 4 commits into
mainfrom
feature/inline-toolbar
Open

InlineToolbar implementation#153
gohabereg wants to merge 4 commits into
mainfrom
feature/inline-toolbar

Conversation

@gohabereg

Copy link
Copy Markdown
Member

Still lots to do — left several @todo across the code.
Need to update the test cases for changed functions

  1. InlineToolbar now renders InlinePopover
  2. Inline Tools return popover items via getToolbarConfig method

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

Unit Tests

Package Coverage Delta
@editorjs/collaboration-manager 85.81% 0% ⚪️
@editorjs/model 98.43% 0% ⚪️
@editorjs/ot-server 20% 0% ⚪️
@editorjs/dom-adapters 86.95% 0% ⚪️
@editorjs/core 91.33% +0.03% 🟢

Mutation Tests

Package Mutation score Dashboard URL
@editorjs/model No mutants found.
@editorjs/dom-adapters 0.00% 🔴 Dashboard
@editorjs/core 11.34% 🔴 Dashboard

Copilot AI left a comment

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.

Pull request overview

This PR refactors the inline formatting UX to be popover-driven: the InlineToolbar UI now renders an @editorjs/ui-kit PopoverInline, and inline tools provide toolbar/menu items via a new getToolbarConfig() API. It also expands selection/formatting APIs to support explicit caret indices, user attribution, and keeping/restoring selection.

Changes:

  • Replaced InlineToolbar’s button list/actions rendering with a PopoverInline built from each inline tool’s getToolbarConfig() output.
  • Updated SDK/core selection APIs to accept optional caretIndex, userId, action, and keepSelection, and added SelectionAPI.caretIndex.
  • Introduced shared MenuConfig types (SDK) and updated internal inline tools (bold/italic/link) to provide toolbar config items.

Reviewed changes

Copilot reviewed 26 out of 26 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/ui/src/InlineToolbar/InlineToolbar.ts Builds and positions a PopoverInline from available inline tools’ toolbar configs.
packages/ui/src/InlineToolbar/InlineToolbar.module.pcss Updates inline toolbar positioning styles and adds input styling for inline-tool UI.
packages/sdk/src/entities/InlineTool.ts Replaces renderActions with required getToolbarConfig() and updates constructor typing.
packages/sdk/src/entities/MenuConfig.ts Adds menu config typings (wrapping ui-kit popover item types) and exports them from SDK entities.
packages/core/src/components/SelectionManager.ts Expands inline tool application API (caret index/user/action/keepSelection) and selection exposure.
packages/core/src/tools/internal/inline-tools/link/index.ts Migrates Link tool to popover-based config (icon + HTML child input) and updated data format.
packages/core/src/tools/ToolsManager.ts / ToolsFactory.ts / packages/core/src/index.ts Introduces an EditorAPI factory to avoid circular deps when constructing tools and plugins.
packages/sdk/src/api/SelectionAPI.ts + packages/core/src/api/SelectionAPI.ts Aligns Selection API surface with new apply options and exposes caret index.
packages/dom-adapters/src/utils/useSelectionChange.ts Avoids processing selectionchange events coming from native input elements.
packages/model/src/.../FormattingAction.ts Adds None action and fixes enum formatting.
packages/core/src/components/SelectionManager.spec.ts + packages/core/src/api/SelectionAPI.spec.ts Updates tests to match renamed/changed selection APIs (coverage still incomplete for new options).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +207 to +214
} else {
caret?.update(
new IndexBuilder()
.from(caretIndex)
.addTextRange([caretIndex.textRange![1], caretIndex.textRange![1]])
.build()
);
}
Comment on lines +259 to +263
const rect = range.getBoundingClientRect();
const holderRect = this.#config.holder.getBoundingClientRect();

this.#nodes.holder.style.top = `${rect.top}px`;
this.#nodes.holder.style.left = `${rect.left}px`;
this.#nodes.holder.style.zIndex = '1000';
}

/**
* Renders the list of available inline tools in the Inline Toolbar
* @param tools - Inline Tools available for the current selection
* @param textRange - current selection text range
* @param fragments - inline fragments for the current selection
*/
#updateToolsList(tools: Map<InlineToolName, InlineTool>, textRange: TextRange, fragments: InlineFragment[]): void {
this.#nodes.buttons.innerHTML = '';

Array.from(tools.entries()).forEach(([name, tool]) => {
const button = make('button');

button.textContent = name;

const isActive = tool.isActive(textRange, fragments.filter((fragment: InlineFragment) => fragment.tool === name));

if (isActive) {
button.style.fontWeight = 'bold';
}
const newPosition = {
/**
Comment on lines +116 to +135
onOpen: (close: (parent?: boolean) => void): void => {
const caretIndex = this.#api.selection.caretIndex;

linkInput.addEventListener('keydown', (event: KeyboardEvent) => {
if (event.key === 'Enter') {
event.preventDefault();
event.stopImmediatePropagation();

close(true);

this.#api.selection.applyInlineTool({
tool: LinkInlineTool.name,
data: { href: linkInput.value },
caretIndex: caretIndex!,
/** @todo Replace link instead of applying the formatting again. Needs to be implemented in the model */
action: isActive ? FormattingAction.None : FormattingAction.Format,
keepSelection: false,
});
}
});

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Input is destroyed every time popover is closed

Comment on lines 215 to +238
@@ -234,7 +235,7 @@ describe('SelectionManager', () => {
jest.spyOn(model, 'getCaret').mockReturnValue({ index: indexMock } as unknown as ReturnType<typeof model.getCaret>);

expect(() => {
selectionManager.applyInlineToolForCurrentSelection('bold' as InlineToolName);
selectionManager.applyInlineTool({ toolName: 'bold' as InlineToolName });
Comment thread packages/ui/src/InlineToolbar/InlineToolbar.module.pcss
Comment on lines +141 to +142
/** If true, Manager will restore the selection after applying the tool. True by defulat */
keepSelection?: boolean;
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.

2 participants