JSPM

  • Created
  • Published
  • Downloads 93
  • Score
    100M100P100Q84328F
  • License MIT

Package Exports

  • react-textflux
  • react-textflux/dist/react-textflux.css

Readme

React Textflux

🚀 What's New

  • Production ready: All major bugs fixed, UX polished
  • Mention dropdown: Keyboard navigation auto-scrolls, dark/light theme highlight, visible text always
  • Media skeleton loader: Shows animated skeleton while uploading/inserting images/videos
  • Unified media handling: Paste, drag-and-drop, and toolbar all use the same upload logic
  • Accessibility: All dropdowns and toolbars are keyboard accessible
  • CSS isolation: All classes prefixed with tf- (no conflicts)
  • Media fullscreen control: You can now control whether images/videos are clickable for fullscreen preview using the mediaFullscreen prop on the Editor component.
  • Smart cursor positioning: Cursor automatically moves to the end after inserting media, mentions, or emojis
  • Improved button reliability: Fixed image/video insert buttons that sometimes didn't work
  • Enhanced error handling: Better error handling for file operations and media uploads
  • Focus management: Improved focus handling between editor and toolbar
  • Existing media support: All existing images/videos in editor content are automatically clickable for fullscreen preview
  • Code block support: Insert code blocks via toolbar or Ctrl+K, and paste code from IDE for auto-formatting

A minimal, modular, and customizable React rich text editor component with:

  • Basic formatting (bold, italic, underline, strikethrough, blockquote, lists)
  • @mention with profile pic/initials
  • Emoji picker (hundreds of emojis)
  • Media rendering (image/video) with fullscreen preview
  • Code block support with text wrapping and monospace font
  • Dark/light theme support
  • Custom upload logic via callback
  • No CSS framework dependency (pure CSS, all classes prefixed with tf- for isolation)
  • Optional fullscreen media preview
  • Smart cursor positioning for seamless writing experience
  • Existing media support for fullscreen preview

Code Block Support

  • Insert code blocks using the toolbar button (</>) or keyboard shortcut Ctrl+K (Cmd+K on Mac)
  • Paste code from any IDE and it will auto-format as a code block
  • Text wrapping and horizontal scroll for long lines
  • Monospace font for code clarity
  • Continue typing after code: After pasting/inserting code, a new line is added so you can keep writing
  • Highlighting: Toolbar button is highlighted when your cursor is inside a code block

Install

npm install react-textflux

Usage

// Only default import is supported:
import Editor from 'react-textflux';
import "react-textflux/dist/react-textflux.css";
function App() {
  // Example: controlled usage with backend value
  const [description, setDescription] = React.useState('');

  // Simulate fetching from backend
  React.useEffect(() => {
    // fetch description from backend
    setTimeout(() => setDescription('<p>Initial <b>description</b> from backend</p>'), 1000);
  }, []);

  // Example: custom upload logic (S3, base64, etc.)
  const handleMediaUpload = async (file, type) => {
    // Upload file to your server or S3, return { url, type, name }
    // Or fallback to base64:
    const toBase64 = file => new Promise((res, rej) => {
      const reader = new FileReader();
      reader.onload = () => res(reader.result);
      reader.onerror = rej;
      reader.readAsDataURL(file);
    });
    const url = await toBase64(file);
    return { url, type, name: file.name };
  };

  // Example: mention data
  const mentions = [
    { id: 1, name: 'John Doe', profile_pic: 'https://example.com/john.jpg' },
    { id: 2, name: 'Jane Smith', profile_pic: 'https://example.com/jane.jpg' },
    { id: 3, name: 'Bob Johnson' } // without profile_pic
  ];

  // Example: custom API call and clear on Enter
  const handleEnter = async (e) => {
    // 1. API call
    await fetch('/your-api', { method: 'POST', body: JSON.stringify({ content: description }) });
    // 2. Clear editor (controlled mode)
    setDescription('');
    // (Uncontrolled: e.target.innerHTML = '';) 
  };

  return (
    <Editor
      theme="light" // or "dark"
      mentions={mentions}
      onMediaUpload={handleMediaUpload}
      value={description} // controlled value
      onChange={setDescription} // updates state on any content change
      mediaFullscreen={true} // <-- Add this line to enable fullscreen media preview
      onEnter={handleEnter} // <-- Called when Enter is pressed
    />
  );
}

Note: The value prop makes the editor controlled, just like a textarea. Pass your HTML string to value, and update it via onChange. All content changes (typing, media insert, mentions, formatting) will trigger onChange with the latest HTML.

Note: The onEnter prop is called whenever the user presses Enter in the editor. You can use it for custom actions like submitting, saving, or clearing the editor. In controlled mode, clear the editor by setting your value state to ''. In uncontrolled mode, use e.target.innerHTML = '' inside onEnter.


Media Fullscreen Preview

  • Media Fullscreen Preview: Click any image or video in the editor to open a fullscreen overlay preview. Click the close (×) button or outside the media to exit preview.
  • Works with all media: Both newly inserted and existing media (from database, etc.) are clickable for fullscreen preview when mediaFullscreen={true} is enabled.

Tip: You can customize the fullscreen overlay style by editing the relevant CSS in the source.


Smart Cursor Positioning

The editor now automatically positions the cursor in the most logical place after various operations:

  • Media Insertion: After inserting images/videos via toolbar, drag & drop, or paste, the cursor moves to the end so you can continue typing
  • Mention Insertion: After selecting a mention from the dropdown, cursor moves to the end
  • Emoji Insertion: After inserting an emoji, cursor moves to the end
  • Seamless Writing: No more manual cursor positioning - just keep typing naturally
  • Code Block Paste: After pasting code, a new line is added so you can keep typing outside the code block

Features

  • Formatting: Bold, Italic, Underline, Strikethrough, Blockquote, Lists
  • @Mention: User list with profile pic/initials, keyboard navigation, auto-scroll
  • Emoji Picker: 200+ emojis, fast search, outside click to close
  • Media: Render images/videos (upload logic is up to you), click to fullscreen preview
  • Media Skeleton: Animated skeleton loader while uploading/inserting
  • Code Block: Insert code blocks via toolbar or Ctrl+K, auto-format on paste, text wrapping, monospace font
  • Theme: Light & dark mode (prop)
  • Keyboard Shortcuts: Tooltips show shortcuts (e.g. Ctrl+B, Ctrl+K)
  • Custom CSS: No Tailwind/Bootstrap required
  • CSS Isolation: All classes prefixed with tf- (no conflicts with other frameworks)
  • Dark Theme Polish: Selected toolbar/mention is deep blue for better contrast
  • Emoji/Mention Scrollbar: Thin, theme-aware, and modern
  • Accessibility: All dropdowns and toolbars are keyboard accessible
  • Optional Media Fullscreen: Enable fullscreen preview for images/videos by setting mediaFullscreen={true} on the Editor. If not set, media is not clickable by default.
  • Smart Cursor Positioning: Automatic cursor positioning after media, mention, emoji, and code block insertion
  • Reliable Button Operation: Fixed image/video insert buttons for consistent functionality
  • Enhanced Error Handling: Better error handling and debugging for file operations
  • Existing Media Support: All existing images/videos in editor content automatically get fullscreen functionality

Keyboard Shortcuts

Action Shortcut
Bold Ctrl+B / Cmd+B
Italic Ctrl+I / Cmd+I
Underline Ctrl+U / Cmd+U
Strikethrough Ctrl+Shift+S / Cmd+Shift+S
Blockquote Ctrl+Q / Cmd+Q
Ordered List Ctrl+Shift+L / Cmd+Shift+L
Unordered List Ctrl+Shift+U / Cmd+Shift+U
Code Block Ctrl+K / Cmd+K

Props

Prop Type Default Description
theme string 'light' 'light' or 'dark'
mentions array [] Array of user objects: [{id, name, profile_pic?}]
onMediaUpload function undefined Custom upload handler: (file, type) => Promise<{url, type, name}>
value string undefined Controlled value: HTML string to display in the editor. Use with onChange for controlled usage.
onChange function undefined Called with latest HTML string on any content change (typing, media, mentions, formatting, etc).
mediaFullscreen boolean false If true, images/videos are clickable and open in fullscreen overlay. If false or not set, media is not clickable.
onEnter function undefined Called with the keyboard event when Enter is pressed in the editor. Use for custom submit, save, or clear logic.

onEnter: API Call & Clear Example

Controlled mode:

<Editor
  value={description}
  onChange={setDescription}
  onEnter={async () => {
    await fetch('/api/save', { method: 'POST', body: JSON.stringify({ content: description }) });
    setDescription(''); // clear editor
  }}
/>

Uncontrolled mode:

<Editor
  onEnter={async (e) => {
    await fetch('/api/save', { method: 'POST', body: JSON.stringify({ content: e.target.innerHTML }) });
    e.target.innerHTML = '';
  }}
/>

Customization

  • Mentions: Pass your user list as mentions prop
  • Emoji List: Edit Toolbar.jsx emojis array
  • CSS: Edit src/index.css for full style control (all classes use tf- prefix)
  • Toolbar/Theme: Update colors in src/index.css for your brand
  • Media Fullscreen: Use the mediaFullscreen prop to control whether media is clickable for fullscreen preview.

Troubleshooting

Image/Video Insert Buttons Not Working

  • Fixed in latest version: The buttons now use proper event handling and should work reliably
  • If issues persist, check browser console for error messages
  • Ensure file input permissions are granted

[plugin:vite:import-analysis] Failed to resolve entry for package

  • Make sure your package.json has correct main, module, and exports fields.
  • Both dist/index.es.js and dist/index.umd.js must exist after build.

React Context/JSX Runtime Errors

  • Ensure your library's Vite config has:
    external: [
      'react',
      'react-dom',
      'react/jsx-runtime',
      'react/jsx-dev-runtime'
    ]
  • And output.globals includes:
    globals: {
      react: 'React',
      'react-dom': 'ReactDOM',
      'react/jsx-runtime': 'jsxRuntime',
      'react/jsx-dev-runtime': 'jsxDevRuntime'
    }
  • Consumer app and library must use the same React version.

Recent Bug Fixes

  • Fixed image/video insert buttons - Now work reliably every time
  • Improved cursor positioning - Automatically moves to end after media insertion
  • Enhanced error handling - Better error handling for file operations
  • Fixed focus management - Editor doesn't lose focus when clicking toolbar buttons
  • Improved event handling - Better event propagation and button responsiveness
  • Added existing media support - All existing images/videos in content are now clickable for fullscreen
  • Code block paste/toolbar - Code blocks are now easy to insert, auto-format, and support text wrapping

License

MIT