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

@shashimadushan/docx-editor-react-native

v0.7.4

Published

React Native (Expo + bare) wrapper for the docx-editor-toolkit editor — a touch-friendly DOCX editor rendered inside a WebView, with a typed postMessage bridge for loading/saving .docx bytes.

Readme

@shashimadushan/docx-editor-react-native

A touch-friendly DOCX editor for React Native (Expo managed + bare), built by running @shashimadushan/docx-editor-editor's mobile layout inside a react-native-webview. The whole editor UI ships as one prebuilt HTML file baked into the package — no dev server, no CDN, no asset pipeline to configure — so it works unmodified in Expo Go, EAS dev builds, and bare React Native.

Optional features (the AI agent, the Sri Lankan legal templates) are separate plugin packages: install one and its code is in your app, don't and it isn't.

Full guide: docs/REACT_NATIVE.md — every prop, the plugin model, native chrome, autosave, troubleshooting, and the 0.4 migration. This README is the overview.

Install

npx expo install @shashimadushan/docx-editor-react-native react-native-webview expo-file-system

Bare RN: npm install @shashimadushan/docx-editor-react-native react-native-webview, then pod install.

expo-file-system is an optional peer dependency but strongly recommended — it backs the autosave adapter and lets the ~1.8 MB editor HTML be cached to a local file and loaded via file:// rather than crossing the RN bridge as a prop, which on Android risks a TransactionTooLargeException. Without it the component still works, with a one-time warning.

Usage

import * as React from 'react';
import { View, Button } from 'react-native';
import { DocxEditorView, useDocxEditorHandle } from '@shashimadushan/docx-editor-react-native';

export default function App() {
  const handle = useDocxEditorHandle();
  const [isDirty, setIsDirty] = React.useState(false);

  return (
    <View style={{ flex: 1 }}>
      <Button title="Load" onPress={() => handle.current?.loadDocx(SOME_BASE64_DOCX)} />
      <Button
        title="Save"
        onPress={async () => {
          const base64 = await handle.current?.saveDocx();
          // persist `base64` (write to FileSystem, upload, share…)
        }}
      />
      <DocxEditorView
        ref={handle}
        onReady={() => console.log('editor ready')}
        onDirtyChange={setIsDirty}
        onError={(message) => console.warn('docx editor error', message)}
        style={{ flex: 1 }}
      />
    </View>
  );
}

See examples/expo-demo for a complete Expo app — document picker, save to file, draft restore on launch, both plugins, both native sheets.

What you get

  • The mobile editor — tabbed toolbar (Home / Insert / contextual Table / Image), folded header with mode switcher, status bar with word count and zoom, selection format bar, bottom sheets for File/View.
  • .docx load and save, base64 in and out.
  • Autosave drafts to on-device storage, with a pluggable adapter.
  • Host-provided templates, extra toolbar buttons, comment persistence, theme tokens, and raw CSS overrides — all live-patchable from props without reloading the WebView.
  • mode prop — lock Editing/Suggesting/Viewing to a host-controlled value (e.g. 'viewing' for a document opened from a view-only share), live-patchable like the rest. See Read-only / locked mode.
  • fileName prop — set the mobile header's title (e.g. from your own document record), live-patchable like the rest. A brand-new document also no longer shows a literal "Untitled" heading baked into the page — that was a bug (fixed in 0.7.3), not a feature.
  • onFileNameChange prop — fires on every keystroke when the user renames the document in the mobile header, so you can persist it (draft metadata, a server PATCH). Without a handler, an in-header rename is purely cosmetic and disappears on reload — that gap is fixed in 0.7.4, but persisting it is still your app's job.
  • Native chrome, optionally: render the agent and comments UIs yourself in React Native instead of inside the WebView.
  • PDF export ingredients (getExportSnapshot()) — no PDF library ships here, but you get everything needed to render one on-device (e.g. expo-print) or server-side. See Exporting to PDF.
  • Plugins for anything else.

Plugins

npx expo install @shashimadushan/docx-editor-react-native-agent
npx expo install @shashimadushan/docx-editor-react-native-legal
import { DocxEditorView } from '@shashimadushan/docx-editor-react-native';
import { agentPlugin } from '@shashimadushan/docx-editor-react-native-agent';
import { legalTemplatesPlugin } from '@shashimadushan/docx-editor-react-native-legal';

<DocxEditorView
  plugins={[agentPlugin({ baseUrl: AGENT_URL }), legalTemplatesPlugin()]}
/>;

Each package ships a prebuilt JS chunk plus its RN-side factory. The chunk is injected ahead of the core bundle, with React, ReactDOM and the editor package left external and bound to globals the core already exposes — so a plugin is tens of KB, and there's exactly one React/TipTap/ProseMirror instance in the page.

The set of plugins is fixed at mount; their options ride the config channel, so changing them afterwards reaches the running plugin with no reload. A plugin that fails to load reports one message through onError and is skipped — the editor still mounts.

Writing your own uses the same mechanism (createPluginScript, PLUGIN_CHUNK_EXTERNALS/PLUGIN_CHUNK_GLOBALS, a setup(ctx) export). See the guide; packages/react-native-legal is the smallest complete example.

Deprecated since 0.4.0

agentBaseUrl / agentHeaders / agentTools / agentPresentation and legalTemplates are superseded by the two plugins. They still feed the plugins' config as a fallback, but on their own they no longer enable anything — that code isn't in the core bundle to switch on — and they warn once naming the package to install. Removal no earlier than 0.5.0. Migration diff.

API

  • <DocxEditorView /> — the editor. ref should be a React.RefObject<DocxEditorHandle | null>, typically from useDocxEditorHandle(). Full prop table.
  • useDocxEditorHandle() — convenience hook returning that typed ref.
  • DocxEditorHandle:
    • loadDocx(base64): Promise<void>
    • saveDocx(): Promise<string> — base64 .docx
    • sendAgentMessage(prompt): Promise<void> — with native agent chrome
    • sendCommentsHostCommand(command): Promise<void> — with native comments chrome
    • getExportSnapshot(): Promise<DocxEditorExportSnapshot> — ingredients for a PDF export (HTML, live stylesheet, theme vars, watermark, header/footer). Pair with onExportPdfRequested to implement "Export PDF…" — see Exporting to PDF for the exact DOM contract required and a worked expo-print example.
  • FileSystemDraftStorageAdapter, DraftStorageAdapter — autosave.
  • AgentSheet, CommentsSheet, useAgentActivityLog — the optional native chrome implementations.
  • createPluginScript, PLUGIN_CHUNK_EXTERNALS, PLUGIN_CHUNK_GLOBALS, HOST_RUNTIME_VERSION and the WebPlugin* types — for authoring plugins.

How it works

webui/                 Vite + React app rendering <ReactDocxEditor layout="mobile" />
                        with an RPC transport to the RN host.
  ↓ `vite build` (vite-plugin-singlefile inlines all JS/CSS into one HTML file)
scripts/build-webui.mjs
  ↓ reads webui/dist/index.html, writes it as an escaped template string
src/generated-html.ts   `export const EDITOR_HTML = "...";`
  ↓ imported by
src/DocxEditorView.tsx  cached to a local file, loaded as source={{ uri }}

Communication between DocxEditorView and webui/src/main.tsx runs over a versioned request/response/event RPC (src/protocol/, createRpc()) — a correlation id on every call means concurrent loadDocx()/saveDocx() calls are safe and a failure only ever rejects its own caller. (bridge.ts's InMessage/OutMessage remain exported as deprecated aliases; nothing puts that shape on the wire anymore.)

  • RN → WebView methods: doc.load, doc.save, config.patch, agent.send, comments.hostCommand
  • WebView → RN methods: host.exportPdf, host.agent.tool, host.templates.get, host.comments.{list,save,remove}
  • WebView → RN events: ready, dirty, error, toolbar.customPressed, menu.customPressed, agent.activity, comment.opened, plugin.error

Settings travel separately, over a config channel: DocxEditorView injects a DocxEditorConfig before the page's own script runs, then patches it live via config.patch when props change — which is why theme, injectedCss, templates, toolbarItems, menuSections and every plugin's options update without a reload.

webui/src/main.tsx imports protocol/ and config/ via relative paths so the two sides can't drift apart; only the built HTML ships at runtime, so this is a build-time-only shared contract.

Building from source

pnpm --filter @shashimadushan/docx-editor-react-native build
# node scripts/build-webui.mjs   → vite build + regenerate generated-html.ts
# tsup                           → src/ → dist/ (ESM + CJS + types; wipes dist/ first)
# node scripts/copy-webui-assets.mjs → dist/webui.html + dist/webui.meta.json

A change in packages/editor is invisible here until both packages are rebuilt, editor first. That's the most common "I edited the toolbar and nothing changed" trap. For faster iteration run pnpm --filter webui dev and preview at phone width in a browser — it renders the identical component tree.

dist/webui.html is the same HTML generated-html.ts bakes in, as a real file, for apps that would rather load it as a Metro asset than pay the string-in-JS parse cost. This package can't require() it for you — Metro only resolves a static literal path at the call site in your source. Pass the resolved URI to htmlSource={{ uri }}. dist/webui.meta.json carries { packageVersion, protocolVersion, hash, byteLength } for sanity-checking whatever you load.

Known limitations

  • No native file picker or expo-asset integration ships here — obtain a base64 .docx however suits your app (see examples/expo-demo for the expo-document-picker + expo-file-system pattern).
  • No branding (radius/density) tokens — see ARCHITECTURE_PLAN.md §5.2 for why a partial implementation would be worse than none.
  • Host templates support HTML content only, not base64 .docx.
  • Toolbar items are label-only and always append to the Insert tab.
  • In native comments mode the toggle bubble and "Add comment" trigger still render in-page (their position depends on document layout), and the native agent composer has no "@" mention autocomplete.
  • CommentsPanel's drag-to-reposition isn't touch-adapted — the panel opens at a clamped, usable position but can't be dragged.

License

MIT