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

@sigx/lynx-markdown

v0.35.0

Published

SignalX-native streaming markdown renderer and WYSIWYG editor for Lynx. Renders and edits @sigx/richtext (mdast) trees natively as <view>/<text> primitives, through @sigx/richtext-markdown, with incremental streaming for AI output.

Readme

@sigx/lynx-markdown

A SignalX-native, streaming-aware markdown renderer — and a true-WYSIWYG editor — for Lynx.

It renders and edits @sigx/richtext trees natively: the mdast-compatible incremental parser, the streaming controller and the render engine live in @sigx/richtext / @sigx/richtext-markdown (shared with the web), and this package maps the tree to native Lynx <view>/<text>/<image> primitives — so it renders identically on every platform (iOS, Android, Harmony) and is fully controllable from JS. Built for AI output: as the source string grows token-by-token, finalized blocks keep a stable identity and are never re-parsed or remounted, so completed content doesn't flicker or reflow while new tokens stream in.

📚 Documentation

Full prop reference, streaming API, theming, the WYSIWYG editor and live examples → sigx.dev/lynx/modules/markdown/overview

Install

pnpm add @sigx/lynx-markdown

(@sigx/richtext and @sigx/richtext-markdown come along as dependencies; their @sigx/reactivity / @sigx/runtime-core peers are the ones @sigx/lynx already requires.)

A taste

import { MarkdownView } from '@sigx/lynx-markdown';

export default function ArticleScreen() {
  return (
    <MarkdownView
      value={'# Hello\n\nThis is **markdown** with a [link](https://sigx.dev).'}
      onLink={(url) => openUrl(url)}
    />
  );
}

createTextStream() (re-exported from @sigx/richtext) bridges a token loop to <MarkdownView> for AI output, coalescing bursts of tokens into a bounded number of re-renders. MarkdownEditor (from @sigx/lynx-markdown/editor) adds block-tree WYSIWYG editing on the native @sigx/lynx-richtext element — see below. The supported syntax, full prop tables, streaming API, theming and editor/toolbar contracts are documented on the docs site.

Plugins and components

<MarkdownView> takes two maps that mirror @sigx/richtext's:

  • plugins — @sigx/richtext plugins (RichTextPlugin[]: node specs, plus markdown syntax and serializer rules under formats.markdown). Pass a stable array; changing its identity re-parses from scratch. mentionPlugin (the @[label](id) syntax) is re-exported here.
  • components — a partial ComponentMap<JSXElement> (alias LynxMarkdownComponents) keyed by mdast node type: root, paragraph, heading (depth), blockquote, list (ordered, start, spread), listItem (ordered, index, number, checked, spread), code (value, lang, meta, open), thematicBreak, table (align), tableRow (header, index), tableCell (header, align, index), html, text, emphasis, strong, delete, inlineCode, break, link (url, title, autolink, onLink), image (url, alt, title, plus this package's onImageTap) — and one flat slot per plugin node type (components.mention, components.emoji). Unspecified slots fall back to the neutral defaultComponents; a ready-made daisyUI mapping ships in @sigx/lynx-daisyui.
import { MarkdownView, mentionPlugin, type Mention } from '@sigx/lynx-markdown';

<MarkdownView
  value="ping @[Andy](u1)"
  plugins={[mentionPlugin]}
  components={{ mention: ({ node }: { node: Mention }) => <text class="chip">@{node.label}</text> }}
/>

Link and image URLs are sanitised by the engine before a component sees them (javascript: and friends become #).

Editor

@sigx/lynx-markdown/editor is the Lynx host of the block-tree editor core in @sigx/richtext/editor: one createEditor() per <MarkdownEditor>, the mdast Root as the document, and every root block rendered as a keyed BlockView — paragraphs and headings as native <sigx-richtext boundary-keys> fields, code blocks as a <textarea>, lists / quotes / tables as views. State, history, commands, keymap, input rules (# , - , 1. , - [ ] , > , **bold**, …), plugins and trigger sessions all live in the core and behave the same as on the web; this package only maps them onto Lynx. The entry is opt-in because it makes the optional @sigx/lynx-richtext and @sigx/lynx-keyboard peers real requirements.

import { MarkdownEditor, createSlashPlugin, type MarkdownEditorController } from '@sigx/lynx-markdown/editor';
import { createMentionPlugin } from '@sigx/lynx-markdown';

const mention = createMentionPlugin({ search: (q) => users.filter((u) => u.label.includes(q)) });
let ctrl: MarkdownEditorController | null = null;

<MarkdownEditor
  value={draft.value}
  onChange={(md) => { draft.value = md; }}
  plugins={[mention, createSlashPlugin()]}
  toolbar="bottom"
  placeholder="Write…"
  controllerRef={(c) => { ctrl = c; }}
/>
  • Document in, document out — value / onChange(markdown) for markdown, document / onDocumentChange(doc, transaction) for the tree (bind either or both; an inbound value equal to what the editor last emitted is ignored).
  • Keyboard — Enter splits, Backspace at a block's start / Delete at its end join, arrows off the first / last line move between blocks, Tab / Shift-Tab indent list items, Escape selects the block. These reach the core through the element's bindboundarykey; on a native build without it, a typed newline still splits the block but the edge deletes stay in-block.
  • Plugins — the same RichTextPlugin[] <MarkdownView> takes; a plugin's editor slice adds inline kinds, triggers, toolbar items, commands, keymap bindings and input rules. createMentionPlugin (@ with candidate search) and the core's createSlashPlugin (/ block menu) ship ready-made; a baseline mention plugin is always registered so controller.insertChip() round-trips.
  • Suggestions — the built-in popup renders inside the block the session belongs to (suggestionPopup styles it). Hosts that dock their own list pass suggestions="none" and draw from renderSuggestions(api) / onTriggerSession(session).
  • Controller — controllerRef yields the formatting shortcuts (toggleBold, setHeading, setList, insertLink, insertChip, …), getMarkdown / setMarkdown, getDocument / setDocument, undo / redo, focus and fullscreen — plus editor (the core instance) and run(command | name) for everything else.
  • Toolbar — toolbar / toolbarItems / renderToolbarItem, or place <EditorToolbar controller={ctrl}> yourself; active / enabled states come from the core's toolbarState. A daisyUI skin ships in @sigx/lynx-daisyui.
  • Composing your own layout — BlockView, InlineBlock, CodeBlock, createLynxEditorView and the surfaces (createLynxInlineSurface, createLynxCodeSurface, flatToDoc / docToFlat) are exported for hosts that need more than the component.

MarkdownEditor follows the OS text-size setting: fontSize (default 16) is the size at the default system setting, multiplied by the effective font scale — and the auto-grow window (minLines/maxLines) scales with it, live. Raw RichTextInput does not auto-scale; multiply its fontSize by useFontScale() (from @sigx/lynx) if you use it directly.

License

MIT