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

@huongda-group/react-lexical-file-manager

v0.1.1

Published

Lexical plugin for professional file management — image viewer, video player, file attachments

Readme

react-lexical-file-manager

A Lexical editor plugin that brings a full media library experience — image viewer, video player, and file attachments — backed by your own data source.

Features

  • Insert images, videos, and file attachments directly into the Lexical editor
  • Modal and fullscreen display modes
  • Single-click selection with Insert button, or double-click to preview
  • Callback-based data layer — return FileItem[] from your own API calls
  • Custom adapter interface for full control
  • Fine-grained permissions to enable/disable individual actions (copy, rename, compress, etc.)
  • appearance prop for theme, primary color, font, and custom CSS
  • language prop — 24 locales (ar, de, en, es, fr, ja, ko, ru, vi, zh-cn, and more)
  • labels prop — override all modal UI strings for full i18n control
  • Serializable Lexical nodes with full importJSON / exportJSON support
  • TypeScript-first

Installation

npm install @huongda-group/react-lexical-file-manager

Peer dependencies:

npm install lexical @lexical/react react react-dom

Import the styles in your app entry:

import '@huongda-group/react-lexical-file-manager/style.css';

Quick Start

import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import {
  LexicalFileManagerPlugin,
  FileManagerToolbarButton,
  FILE_MANAGER_NODES,
} from '@huongda-group/react-lexical-file-manager';
import type { FileItem } from '@huongda-group/react-lexical-file-manager';

async function fetchFiles(path: string): Promise<FileItem[]> {
  const res = await fetch(`/api/files?path=${path}`);
  const data = await res.json();
  // map your API shape to FileItem
  return data.map(f => ({
    id: f.id,
    name: f.name,
    type: f.isFolder ? 'folder' : 'file',
    path: f.directory,
    mimeType: f.mimeType,
    url: f.url,
    thumbnailUrl: f.thumbnail,
    size: f.size,
  }));
}

export function Editor() {
  return (
    <LexicalComposer initialConfig={{ namespace: 'my-editor', nodes: [...FILE_MANAGER_NODES], onError: console.error }}>
      <FileManagerToolbarButton />
      <RichTextPlugin
        contentEditable={<ContentEditable />}
        placeholder={<div>Start typing…</div>}
        ErrorBoundary={LexicalErrorBoundary}
      />
      <LexicalFileManagerPlugin onFetchFiles={fetchFiles} />
    </LexicalComposer>
  );
}

FILE_MANAGER_NODES must be passed to LexicalComposer — it registers ImageNode, VideoNode, and FileNode.

LexicalFileManagerPlugin Props

| Prop | Type | Description | |------|------|-------------| | onFetchFiles | (path: string) => Promise<FileItem[]> | Required (unless adapter is provided). Return files at the given path. | | onUpload | (files: File[]) => Promise<FileItem[]> | Handle file uploads. Return the uploaded FileItem[]. | | onDelete | (items: FileItem[]) => Promise<void> | Handle file/folder deletion. | | onCreateFolder | (name: string, path: string) => Promise<void> | Handle folder creation. | | adapter | FileManagerAdapter | Provide a fully custom adapter instead of individual callbacks. | | defaultDisplayMode | 'modal' \| 'fullscreen' | Initial display mode. Default: 'modal'. | | onFileSelect | (file: FileItem, editor: LexicalEditor) => void | Override default node insertion with custom logic. | | permissions | FileManagerPermissions | Enable/disable individual actions. See Permissions. | | appearance | FileManagerAppearance | Theme, color, and style overrides. See Appearance. | | language | string | UI locale. See Language for supported codes. | | labels | FileManagerLabels | Override modal header strings. See Labels. |

FileItem Type

Map your API response to this shape:

interface FileItem {
  id: string;
  name: string;
  type: 'file' | 'folder';
  path: string;            // parent directory, e.g. '/' or '/photos'
  mimeType?: string;       // drives which node gets inserted
  url?: string;
  size?: number;
  thumbnailUrl?: string;
}

Node selection by mimeType:

  • image/*ImageNode (inline <img>)
  • video/*VideoNode (inline <video>)
  • anything else → FileNode (download link chip)

Upload Example

async function handleUpload(files: File[]): Promise<FileItem[]> {
  const form = new FormData();
  files.forEach(f => form.append('files', f));
  const res = await fetch('/api/upload', { method: 'POST', body: form });
  const data = await res.json();
  return data.map(f => ({ id: f.id, name: f.name, type: 'file', path: f.path, mimeType: f.mimeType, url: f.url }));
}

<LexicalFileManagerPlugin onFetchFiles={fetchFiles} onUpload={handleUpload} />

Permissions

Control which actions are available in the file manager UI. All permissions default to true (enabled).

import type { FileManagerPermissions } from '@huongda-group/react-lexical-file-manager';

const permissions: FileManagerPermissions = {
  create: true,       // create folder
  upload: true,       // upload files
  move: true,         // cut / paste (move)
  copy: true,         // copy / paste
  rename: true,       // rename files and folders
  download: false,    // download button
  delete: true,       // delete files and folders
  chmod: false,       // change permissions (Unix-style)
  compress: false,    // compress to archive
  decompress: false,  // extract archive
};

<LexicalFileManagerPlugin onFetchFiles={fetchFiles} permissions={permissions} />

Appearance

Customize the file manager's visual style.

import type { FileManagerAppearance } from '@huongda-group/react-lexical-file-manager';

const appearance: FileManagerAppearance = {
  theme: 'dark',             // 'light' | 'dark'
  primaryColor: '#3182ce',   // accent color (buttons, highlights)
  fontFamily: 'Inter, sans-serif',
  className: 'my-fm',        // extra CSS class on the root element
  style: { borderRadius: 8 },
};

<LexicalFileManagerPlugin onFetchFiles={fetchFiles} appearance={appearance} />

Language

Pass a locale code via the language prop to localize the file manager UI.

<LexicalFileManagerPlugin onFetchFiles={fetchFiles} language="vi-vn" />

Supported locales:

| Code | Language | |------|----------| | ar-sa | العربية | | da-dk | Dansk | | de-de | Deutsch | | en-us | English | | es-es | Español | | fa-ir | فارسی | | fi-fi | Suomi | | fr-fr | Français | | he-il | עברית | | hi-in | हिन्दी | | it-it | Italiano | | ja-jp | 日本語 | | ko-kr | 한국어 | | nb-no | Norsk bokmål | | pl-pl | Polski | | pt-br | Português (Brasil) | | pt-pt | Português | | ru-ru | Русский | | sv-se | Svenska | | tr-tr | Türkçe | | uk-ua | Українська | | ur-ur | اردو | | vi-vn | Tiếng Việt | | zh-cn | 中文 (简体) |

Default: en-us.

Labels

Override the modal header strings added by this plugin (separate from the file manager's own i18n).

import type { FileManagerLabels } from '@huongda-group/react-lexical-file-manager';

const labels: FileManagerLabels = {
  title: 'Thư viện media',
  insert: 'Chèn',
  fullscreen: 'Toàn màn hình',
  exitFullscreen: 'Thoát toàn màn hình',
  close: 'Đóng',
  retry: 'Thử lại',
};

<LexicalFileManagerPlugin onFetchFiles={fetchFiles} labels={labels} />

| Key | Default | |-----|---------| | title | 'Media Library' | | insert | 'Insert' | | fullscreen | 'Fullscreen' | | exitFullscreen | 'Exit fullscreen' | | close | 'Close' | | retry | 'Retry' |

Custom Adapter

For full control, implement FileManagerAdapter and pass it via the adapter prop:

import type { FileManagerAdapter } from '@huongda-group/react-lexical-file-manager';

const myAdapter: FileManagerAdapter = {
  fetchFiles: async (path) => { /* return FileItem[] */ },
  upload: async (files) => { /* return FileItem[] */ },
  delete: async (items) => { /* ... */ },
  createFolder: async (name, path) => { /* ... */ },
};

<LexicalFileManagerPlugin adapter={myAdapter} />

Toolbar Button

FileManagerToolbarButton opens the file manager on click. Must render inside LexicalComposer.

<FileManagerToolbarButton label="Media" icon={<MyIcon />} />

| Prop | Type | Default | |------|------|---------| | label | string | 'Media' | | icon | ReactNode | '📁' | | style | CSSProperties | — | | className | string | — |

useFileManager Hook

Programmatic control from any component inside LexicalComposer:

import { useFileManager } from '@huongda-group/react-lexical-file-manager';

function MyButton() {
  const { open, insert } = useFileManager();
  return <button onClick={open}>Open media library</button>;
}

| Method | Signature | Description | |--------|-----------|-------------| | open | () => void | Open the file manager modal | | insert | (file: FileItem) => void | Insert a file node at the current selection |

Commands

Dispatch Lexical commands directly:

import { OPEN_FILE_MANAGER_COMMAND, INSERT_FILE_COMMAND } from '@huongda-group/react-lexical-file-manager';

editor.dispatchCommand(OPEN_FILE_MANAGER_COMMAND, undefined);
editor.dispatchCommand(INSERT_FILE_COMMAND, fileItem);

Nodes

All three nodes are exported for custom serialization or transforms:

import {
  ImageNode, $createImageNode, $isImageNode,
  VideoNode, $createVideoNode, $isVideoNode,
  FileNode, $createFileNode, $isFileNode,
} from '@huongda-group/react-lexical-file-manager';

Development

npm run dev          # build in watch mode
npm test             # unit tests
npm run test:e2e     # E2E tests (starts example app on :5176)
npm run example      # run example app