Skip to content

[Feature] Introduce RichTextEditor (RTE) component with compound controls and responsive media embeds #1824

Description

@neo0007777

Current Behavior

Currently, Sistent only provides read-only markdown rendering through RenderMarkdown (src/custom/Markdown). Downstream consumers like Meshery UI and Meshery Cloud have no standardized, design-system-native Rich Text Editor:

  1. Unresolved Component Migration: Issue Migrate Markdown Editor (MDEditor) Component #1296 ("Migrate Markdown Editor (MDEditor) Component") was closed during cleanup without an editor component landing in Sistent. Meshery UI still relies on an unmaintained @uiw/react-md-editor loaded with next/dynamic to avoid SSR hydration bugs.
  2. Poor Authoring UX in Meshery Catalog & Designs: When users write design documentation, publish Meshery Catalog items, create patterns, or write collaboration notes, they must type raw markdown in unformatted textareas without WYSIWYG feedback or inline formatting.
  3. No Interactive Media Embeds: Meshery design walk-throughs frequently reference YouTube tutorials and architecture videos, but there is no native embed harness with aspect-ratio preservation or in-place resizing.

Desired Behavior

Introduce an extensible, headless-backed RichTextEditor compound component into Sistent that provides:

  • WYSIWYG Formatting: Headings (H1–H6), bold, italic, underline, strike, lists (bullet, ordered, task list), blockquotes, inline code, and code blocks with syntax highlighting.
  • Contextual Bubble Menu: Fast inline text styling and code language selection when text or code blocks are selected.
  • Responsive Media Embeds: Resizable video/YouTube embeds with 16:9 aspect-ratio locking, preset width buttons (25%, 50%, 75%, 100%), and bidirectional drag handles.
  • Sistent MUI Theme Native: Adapts seamlessly to Sistent's MUI v9 palette and theme tokens (light/dark mode, elevation, surface colors).
  • Safe Packaging & Barrel Architecture: Conforms to Sistent's strict barrel and dependency isolation rules (heavy editor dependencies isolated as optional peers or opt-in entry point so non-editor consumers incur zero bundle overhead).

Implementation

  1. Compound Component API:

    import { RichTextEditor } from '@sistent/sistent';
    
    <RichTextEditor editor={editor} variant="default">
      <RichTextEditor.Toolbar sticky>
        <RichTextEditor.ControlsGroup>
          <RichTextEditor.Bold />
          <RichTextEditor.Italic />
          <RichTextEditor.Link />
          <RichTextEditor.CodeBlock />
        </RichTextEditor.ControlsGroup>
        <RichTextEditor.ControlsGroup>
          <RichTextEditor.YouTubeEmbed />
        </RichTextEditor.ControlsGroup>
      </RichTextEditor.Toolbar>
    
      <RichTextEditor.BubbleMenu editor={editor} />
      <RichTextEditor.Content />
      <RichTextEditor.Footer showWordCount />
    </RichTextEditor>
  2. Theming & Token Compatibility:

    • Built using Emotion / MUI styled components mapping directly to Sistent's theme.palette.
    • Native dark/light mode toggle responsiveness without hardcoded color variables.
  3. Dependency & Barrel Safety:

    • In accordance with Sistent's AGENTS.md guidelines on optional peers, declare the core editor engine appropriately so importing unrelated components from @sistent/sistent does not throw for consumers who don't need the editor.

Acceptance Tests

  • RichTextEditor compound component exported from Sistent with full TypeScript declarations in dist/index.d.ts.
  • Native dark/light mode switching works seamlessly with Sistent theme context.
  • YouTube/video embeds support alignment (left/center/right), presets (25%, 50%, 75%, 100%), and drag resizing with 16:9 ratio lock.
  • Jest unit tests covering controls, state selectors, and barrel export integrity.
  • Zero SSR hydration warnings when consumed in Next.js applications (e.g. Meshery UI).

Contributor Guide

Activity

  1. neo0007777 commented on Sep 2, 2026

    @neo0007777
    Author

    Architectural & Implementation Clarification

    Following up with key technical constraints specific to Sistent's build and dependency architecture:

    1. Single-Entry Packaging via React.lazy (Following the DateTimePicker Pattern)

    Sistent's build relies on a single entry point (tsup.config.ts -> src/index.tsx) without subpath exports. To ensure consumers who do not use the editor incur zero bundle overhead and zero module-resolution errors:

    • The editor engine will be declared as an optional peer dependency in package.json (peerDependenciesMeta).
    • The heavy editor core will be loaded dynamically on first render via React.lazy(async () => import(...)) within an internal suspense boundary, exactly mirroring src/base/DateTimePicker/DateTimePicker.tsx.

    2. Declaration Bundle Integrity (dist/index.d.ts)

    In accordance with Sistent's AGENTS.md guidelines on optional peers and the fix established in #1754:

    • No external optional peer types will leak into Sistent's public .d.ts surface.
    • Sistent will publish its own structurally typed RichTextEditorInstance interface defining the exact contract consumed by the controls (e.g. .chain(), .isActive(), .isEditable, .storage).
    • This avoids TS2307 errors under skipLibCheck: false and prevents types from collapsing to any for consumers who do not install the optional peer.
  2. neo0007777 commented on Sep 9, 2026

    @neo0007777
    Author

    Hi @Maanvi212006 I raised this issue and would love to work on it myself, if that works for you could you take a look and assign it to me?

  3. Maanvi212006 commented on Sep 9, 2026

    @Maanvi212006
    Contributor

    Hi @neo0007777, thanks for bringing this up! Would you mind discussing this in Monday’s Website meeting? I believe the reviewers there are more familiar with this part of the Layer5 codebase and would be able to share their thoughts on whether this feature would be a good addition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions