CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/npm-remirror--react

Hooks and components for consuming remirror with your fave framework React.

Overall
score

36%

Evaluation36%

1.09x

Agent success when using this tile

Overview
Eval results
Files

advanced-hooks.mddocs/

Advanced Hooks

Extended hooks for sophisticated editor interactions including positioning, suggestions, keyboard handling, and event management.

Capabilities

Positioning Hooks

Hooks for managing floating UI elements and positioning.

/**
 * Hook for managing a single positioned element with floating UI
 * @param options - Positioning configuration options
 * @returns Positioning state and control functions
 */
function usePositioner(options?: PositionerOptions): UsePositionerReturn;

interface UsePositionerReturn {
  /** Whether the positioner is currently active */
  active: boolean;
  /** Current position coordinates */
  position: { x: number; y: number };
  /** Show the positioned element */
  show: () => void;
  /** Hide the positioned element */
  hide: () => void;
  /** Toggle visibility */
  toggle: () => void;
  /** Update position */
  update: () => void;
}

interface PositionerOptions {
  /** Placement preference */
  placement?: Placement;
  /** Offset from reference element */
  offset?: number;
  /** Whether to flip when space is limited */
  flip?: boolean;
}

/**
 * Hook for managing multiple positioned elements
 * @returns Multi-positioner management interface
 */
function useMultiPositioner(): MultiPositionerReturn;

interface MultiPositionerReturn {
  /** Create a new positioner */
  create: (id: string, options?: PositionerOptions) => UsePositionerReturn;
  /** Remove a positioner */
  remove: (id: string) => void;
  /** Get a specific positioner */
  get: (id: string) => UsePositionerReturn | undefined;
  /** Hide all positioners */
  hideAll: () => void;
}

Usage Example:

import React, { useState } from 'react';
import { usePositioner } from '@remirror/react';

function FloatingMenu() {
  const [visible, setVisible] = useState(false);
  const positioner = usePositioner({
    placement: 'top',
    offset: 10,
  });

  return (
    <div>
      <button 
        onClick={() => {
          setVisible(!visible);
          positioner.toggle();
        }}
      >
        Toggle Menu
      </button>
      {positioner.active && (
        <div style={{ 
          position: 'absolute',
          left: positioner.position.x,
          top: positioner.position.y,
        }}>
          Floating menu content
        </div>
      )}
    </div>
  );
}

Suggestion Hooks

Hooks for implementing suggestion systems like mentions, emoji, and custom suggestions.

/**
 * General-purpose suggestion hook for autocomplete functionality
 * @param options - Suggestion configuration
 * @returns Suggestion state and control functions
 */
function useSuggest<T = any>(options: SuggestOptions<T>): SuggestReturn<T>;

interface SuggestOptions<T> {
  /** Trigger character(s) */
  char: string | string[];
  /** Function to fetch suggestions */
  items: (query: string) => T[] | Promise<T[]>;
  /** Function to render each suggestion */
  render: (item: T) => React.ReactNode;
  /** Function to handle selection */
  onSelect: (item: T) => void;
}

interface SuggestReturn<T> {
  /** Current suggestions */
  items: T[];
  /** Currently highlighted index */
  index: number;
  /** Whether suggestions are active */
  active: boolean;
  /** Current query string */
  query: string;
  /** Select highlighted item */
  selectHighlighted: () => void;
  /** Navigate suggestions */
  next: () => void;
  previous: () => void;
}

/**
 * Hook for mention functionality
 * @param options - Mention configuration
 * @returns Mention state and handlers
 */
function useMention(options?: MentionOptions): MentionState;

interface MentionOptions {
  /** Mention trigger character */
  char?: string;
  /** Function to fetch mention suggestions */
  items?: (query: string) => MentionItem[] | Promise<MentionItem[]>;
  /** Custom mention matcher */
  matcher?: RegExp;
}

interface MentionState {
  /** Current mention query */
  query: string;
  /** Available mention items */
  items: MentionItem[];
  /** Currently active mention */
  active: boolean;
  /** Highlighted item index */
  index: number;
  /** Insert a mention */
  insertMention: (item: MentionItem) => void;
}

interface MentionItem {
  /** Unique identifier */
  id: string;
  /** Display label */
  label: string;
  /** Optional avatar URL */
  avatar?: string;
  /** Additional data */
  data?: any;
}

/**
 * Hook for atomic mention handling (indivisible mentions)
 * @param options - Atomic mention options
 * @returns Atomic mention interface
 */
function useMentionAtom(options?: MentionAtomOptions): MentionAtomState;

interface MentionAtomOptions {
  /** Mention character trigger */
  char?: string;
  /** Mention data provider */
  items?: (query: string) => MentionItem[] | Promise<MentionItem[]>;
}

interface MentionAtomState {
  /** Create new mention */
  createMention: (item: MentionItem) => void;
  /** Update existing mention */
  updateMention: (id: string, data: Partial<MentionItem>) => void;
  /** Remove mention */
  removeMention: (id: string) => void;
  /** Get all mentions in document */
  getMentions: () => MentionItem[];
}

/**
 * Hook for emoji suggestion functionality
 * @param options - Emoji configuration
 * @returns Emoji suggestion state
 */
function useEmoji(options?: EmojiOptions): EmojiState;

interface EmojiOptions {
  /** Emoji trigger character */
  char?: string;
  /** Custom emoji dataset */
  emojiData?: EmojiData[];
}

interface EmojiState {
  /** Current emoji query */
  query: string;
  /** Matching emoji results */
  results: EmojiData[];
  /** Insert selected emoji */
  insertEmoji: (emoji: EmojiData) => void;
  /** Whether emoji picker is active */
  active: boolean;
}

interface EmojiData {
  /** Emoji unicode character */
  emoji: string;
  /** Emoji name/description */
  name: string;
  /** Category */
  category: string;
  /** Keywords for searching */
  keywords: string[];
}

Usage Example:

import React from 'react';
import { useMention } from '@remirror/react';

function MentionSupport() {
  const mention = useMention({
    char: '@',
    items: async (query) => {
      // Fetch users matching query
      const users = await fetchUsers(query);
      return users.map(user => ({
        id: user.id,
        label: user.name,
        avatar: user.avatar,
      }));
    },
  });

  return mention.active ? (
    <div className="mention-popup">
      {mention.items.map((item, index) => (
        <div
          key={item.id}
          className={index === mention.index ? 'highlighted' : ''}
          onClick={() => mention.insertMention(item)}
        >
          {item.avatar && <img src={item.avatar} alt="" />}
          {item.label}
        </div>
      ))}
    </div>
  ) : null;
}

Keyboard Handling Hooks

Hooks for managing keyboard shortcuts and navigation.

/**
 * Hook for binding a single keymap
 * @param keymap - Key binding configuration
 */
function useKeymap(keymap: ProsemirrorKeyBindings): void;

/**
 * Hook for binding multiple keymaps
 * @param keymaps - Array of key binding configurations
 */
function useKeymaps(keymaps: ProsemirrorKeyBindings[]): void;

interface ProsemirrorKeyBindings {
  [key: string]: (state: EditorState, dispatch?: any) => boolean;
}

/**
 * Hook for keyboard navigation in menus and lists
 * @param options - Navigation configuration
 * @returns Navigation state and handlers
 */
function useMenuNavigation(options: MenuNavigationOptions): MenuNavigationReturn;

interface MenuNavigationOptions {
  /** Total number of items */
  items: number;
  /** Initial selected index */
  initialIndex?: number;
  /** Whether to loop at ends */
  loop?: boolean;
  /** Custom key mappings */
  keys?: {
    up?: string;
    down?: string;
    select?: string;
    escape?: string;
  };
}

interface MenuNavigationReturn {
  /** Currently selected index */
  index: number;
  /** Move to next item */
  next: () => void;
  /** Move to previous item */
  previous: () => void;
  /** Select current item */
  select: () => void;
  /** Reset to initial state */
  reset: () => void;
  /** Set specific index */
  setIndex: (index: number) => void;
}

Usage Example:

import React, { useEffect } from 'react';
import { useKeymap, useMenuNavigation } from '@remirror/react';

function CustomDropdown({ items, onSelect }) {
  const navigation = useMenuNavigation({
    items: items.length,
    loop: true,
  });

  useKeymap({
    'ArrowUp': () => {
      navigation.previous();
      return true;
    },
    'ArrowDown': () => {
      navigation.next();
      return true;
    },
    'Enter': () => {
      onSelect(items[navigation.index]);
      return true;
    },
  });

  return (
    <div className="dropdown">
      {items.map((item, index) => (
        <div
          key={index}
          className={index === navigation.index ? 'selected' : ''}
          onClick={() => onSelect(item)}
        >
          {item.label}
        </div>
      ))}
    </div>
  );
}

Editor Event Hooks

Hooks for handling various editor events and interactions.

/**
 * Hook for handling general editor events
 * @param event - Event name to listen for
 * @param handler - Event handler function
 * @param options - Event options
 */
function useEditorEvent<T = any>(
  event: string,
  handler: (params: T) => void,
  options?: EventOptions
): void;

interface EventOptions {
  /** Event priority */
  priority?: number;
  /** Whether to capture the event */
  capture?: boolean;
  /** Event filter function */
  filter?: (params: any) => boolean;
}

/**
 * Hook for managing editor focus state
 * @param options - Focus configuration
 * @returns Focus state and control functions
 */
function useEditorFocus(options?: FocusOptions): EditorFocusReturn;

interface FocusOptions {
  /** Auto focus on mount */
  autoFocus?: boolean;
  /** Focus delay in milliseconds */
  delay?: number;
  /** Callback when focus changes */
  onFocusChange?: (focused: boolean) => void;
}

interface EditorFocusReturn {
  /** Whether editor is currently focused */
  focused: boolean;
  /** Focus the editor */
  focus: () => void;
  /** Blur the editor */
  blur: () => void;
  /** Toggle focus state */
  toggle: () => void;
}

/**
 * Hook for handling hover interactions
 * @param options - Hover configuration
 * @returns Hover state and handlers
 */
function useHover(options?: HoverOptions): HoverReturn;

interface HoverOptions {
  /** Hover delay in milliseconds */
  delay?: number;
  /** Element selector to monitor */
  selector?: string;
  /** Callback when hover state changes */
  onHoverChange?: (hovering: boolean) => void;
}

interface HoverReturn {
  /** Whether currently hovering */
  hovering: boolean;
  /** Hover event handlers */
  handlers: {
    onMouseEnter: () => void;
    onMouseLeave: () => void;
  };
}

/**
 * Hook for managing editor history (undo/redo)
 * @returns History state and control functions
 */
function useHistory(): HistoryReturn;

interface HistoryReturn {
  /** Whether undo is available */
  canUndo: boolean;
  /** Whether redo is available */
  canRedo: boolean;
  /** Perform undo */
  undo: () => void;
  /** Perform redo */
  redo: () => void;
  /** Clear history */
  clearHistory: () => void;
}

Usage Example:

import React from 'react';
import { useEditorFocus, useHistory, useHover } from '@remirror/react';

function EditorControls() {
  const { focused, focus, blur } = useEditorFocus();
  const { canUndo, canRedo, undo, redo } = useHistory();
  const { hovering, handlers } = useHover({
    delay: 200,
  });

  return (
    <div className="editor-controls" {...handlers}>
      <div>
        Editor focused: {focused ? 'Yes' : 'No'}
        <button onClick={focused ? blur : focus}>
          {focused ? 'Blur' : 'Focus'}
        </button>
      </div>
      
      <div>
        <button onClick={undo} disabled={!canUndo}>
          Undo
        </button>
        <button onClick={redo} disabled={!canRedo}>
          Redo
        </button>
      </div>
      
      {hovering && <div>Hovering over controls</div>}
    </div>
  );
}

Utility Hooks

Additional utility hooks for common operations.

/**
 * Calculate index from arrow key navigation
 * @param current - Current index
 * @param total - Total items
 * @param direction - Navigation direction
 * @param loop - Whether to loop at boundaries
 * @returns New index after navigation
 */
function indexFromArrowPress(
  current: number,
  total: number,
  direction: 'up' | 'down',
  loop?: boolean
): number;

Types

Common Hook Types

type Placement = 
  | 'top'
  | 'top-start'
  | 'top-end'
  | 'bottom'
  | 'bottom-start'
  | 'bottom-end'
  | 'left'
  | 'left-start'
  | 'left-end'
  | 'right'
  | 'right-start'
  | 'right-end';

interface Position {
  x: number;
  y: number;
}

interface Bounds {
  top: number;
  left: number;
  bottom: number;
  right: number;
  width: number;
  height: number;
}

Install with Tessl CLI

npx tessl i tessl/npm-remirror--react@2.0.0
What are skills?

docs

advanced-hooks.md

component-extensions.md

content-rendering.md

core-integration.md

editor-hooks.md

index.md

table-extensions.md

ui-components.md

utilities.md

tile.json