npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@llui/lexical

v0.5.1

Published

Low-level binding between Lexical and the LLui signal runtime — mount Lexical via foreign(), plugin contract, and the DecoratorNode ↔ LLui sub-view bridge

Downloads

650

Readme

@llui/lexical

Low-level binding between Lexical and the LLui signal runtime.

pnpm add @llui/lexical lexical

What it provides

  • lexicalForeign — a foreign() seam that mounts a Lexical editor inside an LLui view while keeping the editor's imperative lifecycle isolated from the runtime's reconciler.
  • Plugin contract — a small interface for registering Lexical plugins (history, rich-text, selection, …) against the mounted editor.
  • DecoratorNode ↔ LLui bridge — render an LLui sub-view inside a Lexical DecoratorNode, so decorator content participates in the same TEA update cycle as the surrounding app.
  • The commit hub — one shared registerUpdateListener and one editor-state read per commit, serving every plugin that only needs to know where the selection is.

The commit hub

A plugin that reacts to the caret subscribes with ctx.onCommit(facts => …) instead of registering its own update listener. One listener, one editorState.read(), one caret measurement and one shared ancestor walk serve every subscriber — six overlay plugins in @llui/markdown-editor cost what one used to.

The callback runs inside the shared read, so bare $ helpers are free and writes are forbidden; ctx.emit from there is buffered and delivered once the read has closed, which is what keeps read-then-dispatch out of the plugin contract. ctx.withFacts(fn) derives the same facts on demand, for the scroll/resize path where geometry moved but the document did not. facts.selectionOnly marks a commit that dirtied no node — an element-anchored overlay can skip its getBoundingClientRect outright.

A commit is batched: every subscriber refreshes first, then every buffered emission drains in subscription order. Do not write a plugin that depends on a sibling's message having been reduced by the time yours runs.

lexicalForeign builds the hub and hands it to each plugin as the PluginContext. Breaking: PluginContext therefore now carries onCommit and withFacts as well as emit — code that hand-rolled a { emit } context (tests, custom hosts) should call createCommitHub(editor, emit) instead.

What selectionOnly costs

Skipping the measurement on a caret-only commit is a real behavioural trade, not a free win. An element-anchored overlay now re-measures on a dirtying commit or on the host's scroll/resize listener, and on nothing else. A layout shift that is neither — a sibling element growing, a webfont swapping in, an image above the editor finishing its load — leaves such an overlay at a stale position until the next dirtying commit, where previously any caret move happened to correct it. That accidental correction is what the gate removes. A host that needs more should drive ctx.withFacts from whatever observes its own layout (e.g. a ResizeObserver).

Writing a value into the document

lexicalForeign is the sole authority on echo for the controlled value, in both directions, and it answers one question in each: inbound, would applying this value change the live document?; outbound, does the document now serialize to something the host doesn't have? So onChange does not fire for a commit that leaves the serialized document unchanged, and a host push that describes the document already on screen is not written (the caret survives).

Push through the ForeignController handed to onReady(editor, controller)controller.applyValue(value) returns whether the document was written. Writing through the raw editor instead bypasses the authority, and the host owns the resulting echo loop.

serialize and deserialize are called inside a read/update context that the seam opens, so they may use bare $ helpers.

This is the plumbing layer. For a batteries-included editor see @llui/markdown-editor; for collaborative editing see @llui/lexical-collab.

Peer dependencies

@llui/dom, lexical, and the @lexical/{history,rich-text,selection,utils} packages (all ^0.46) are peers — install the ones your integration uses.