Skip to content

/wp on an empty line should create a block work-package link, not an inline one#142

Open
ihordubas99 wants to merge 2 commits into
devfrom
feature/75310-slash-on-empty-line-paste-block-wp
Open

/wp on an empty line should create a block work-package link, not an inline one#142
ihordubas99 wants to merge 2 commits into
devfrom
feature/75310-slash-on-empty-line-paste-block-wp

Conversation

@ihordubas99
Copy link
Copy Markdown
Collaborator

@ihordubas99 ihordubas99 commented May 26, 2026

Ticket

https://community.openproject.org/projects/communicator-stream/work_packages/75310

What are you trying to accomplish?

When a user triggers the slash menu on an empty line and selects "Link existing work package", the work package should be inserted as a full-width block card rather than an inline chip. On a non-empty line the existing inline chip behaviour is preserved.

What approach did you choose and why?

At slash menu selection time we check whether the current block's content is empty. If it is, we insert an openProjectWorkPackageBlock in place of the empty paragraph and register its ID in a module-level pendingBlockRegistry - a local in-memory Set, never synced to the document. The block component reads this registry to decide whether to render the search dropdown, which means only the user who triggered the insertion sees it; collaborators sharing the same document never get a search UI they did not ask for. This mirrors the existing pattern used by inline chips (registerInlineWpCallbacks). On cancel the block is removed entirely; on confirm the registry entry is cleared and the block receives its wpid. The mousedown outside-click handler in BlockWorkPackage was also updated to use e.composedPath() instead of contains(e.target) so the popover close logic works correctly inside a Shadow DOM.

As a side effect, the previous implementation accessed TipTap's private _tiptapEditor instance to subscribe to selectionUpdate events in order to track whether the block was "active". That coupling is now removed - the search dropdown visibility is driven entirely by the registry, with no dependency on editor internals.

Merge checklist

  • Added/updated tests
  • Added/updated documentation in Lookbook (patterns, previews, etc)
  • Tested major browsers (Chrome, Firefox, Edge, ...)

Copy link
Copy Markdown

Copilot AI left a comment

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 adjusts the editor’s slash-menu “Link existing work package” insertion behavior so that selecting it on an empty line inserts a full-width block work-package card, while keeping the existing inline-chip behavior when triggered on a non-empty line. It introduces a local-only pending-block registry to control which client sees the search UI, and removes the previous coupling to TipTap private internals.

Changes:

  • Route slash-menu selection to either block-card insertion (empty line) or inline-chip insertion (non-empty line).
  • Add a module-level pendingBlockRegistry used by the block component to decide whether to show the search dropdown.
  • Update the block card’s outside-click handling to use MouseEvent.composedPath() for Shadow DOM compatibility, and add browser tests covering block-vs-inline routing.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
test/lib/components/integration/editor.slashMenu.browser.test.tsx Adds integration tests asserting block insertion on empty line and inline insertion on non-empty line.
lib/components/SlashMenu.tsx Adds empty-block detection and routes insertion to either block-card or inline-chip flow; registers pending block IDs.
lib/components/BlockWorkPackage/pendingBlockRegistry.ts Introduces a local in-memory registry for pending block IDs (not synced to document).
lib/components/BlockWorkPackage/BlockWorkPackage.tsx Drives search dropdown visibility via the pending registry, removes TipTap private selection tracking, and improves outside-click detection via composedPath().

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

Comment on lines +129 to 135
const isPending = pendingBlockRegistry.has(block.id);

return (
<Block
tabIndex={disableFocus ? -1 : 0}
style={disableFocus ? { pointerEvents: "none" } : undefined}
>
<Block $pending={isPending}>
<div contentEditable={false} style={{ userSelect: "none" }}>
{!block.props.wpid && !block.props.initialized && isActive && (
{isPending && (
<SearchContainer>
@ihordubas99 ihordubas99 force-pushed the feature/75310-slash-on-empty-line-paste-block-wp branch from acc27f1 to 89434c4 Compare May 26, 2026 14:53
@ihordubas99
Copy link
Copy Markdown
Collaborator Author

Now if you put a space " " before the slash, it will link the inline chip. Not sure what's the best way to do it, leave it like that, or link the block anyway in this case? What do you think @judithroth?

@ihordubas99 ihordubas99 marked this pull request as ready for review May 26, 2026 15:21
@ihordubas99 ihordubas99 requested a review from judithroth May 26, 2026 15:21
@judithroth
Copy link
Copy Markdown
Contributor

Now if you put a space " " before the slash, it will link the inline chip. Not sure what's the best way to do it, leave it like that, or link the block anyway in this case? What do you think @judithroth?

@ihordubas99 good question. I think I'd leave it like it is. The question is where would we draw the line, what about 2 spaces? 4 or 6? Or should we remove them?

However, let's wait with merging this until we finished all the Bugs for 17.5. Since this changes the setup of op-blocknote-extensions in OpenProject again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants