Slate Framework

repository·main·Indexed 12 days ago

https://github.com/ianstormtaylor/slate

A highly customizable framework for building rich text editors with a modular architecture. It includes core logic for document manipulation, state management, and operation handling, along with specialized sub-libraries like slate-react for React integration, slate-history for undo/redo functionality, and slate-hyperscript for creating documents using JSX.

Tokens
72K
Snippets
228
Records
350
Agent score
96%

What's inside Slate

  1. Overview of Slate React

    main
    Slate React is a sub-library that provides the React-specific logic for the Slate editor. It bridges the core Slate editor logic with React's component model, providing essential components like Slate and Editable, as well as specialized hooks and editor extensions to manage the editor state and user interactions within a React application.
  2. Understand the core logic of Slate

    main
    The slate package serves as the central engine for the Slate editor, containing the core logic required for document manipulation, state management, and operation handling. While it is the foundation for other packages like slate-react or slate-history, it is primarily focused on the underlying data model and transformation logic.
  3. Browser and device support for Slate

    main

    Slate aims to support modern desktop and mobile browsers.

    Desktop Support

    • Supported: Latest versions of Chrome, Edge, Firefox, and Safari.
    • Unsupported: Internet Explorer (IE).

    Mobile Support

    • iOS: Supported, but not regularly tested.
    • Android: Supported via Chrome. Note that Android uses compositions and mutations due to differences in beforeInput event support, which may result in a different development lifecycle and more bugs compared to other platforms.

    Legacy Browsers (e.g., IE11)

    Slate does not provide polyfills for missing native APIs (like el.closest). If you need to support older browsers, you are responsible for providing the necessary polyfills (e.g., via https://polyfill-fastly.io/). Even with polyfills, Slate makes no guarantees of functionality in IE11.

  4. Explore the structure of slate-react

    main

    The slate-react package provides React-specific logic for Slate editors. It is organized into the following functional directories:

    • Components: React components used for rendering Slate editors.
    • Hooks: React hooks designed for interacting with Slate editors.
    • Plugins: React-specific plugins that extend Slate editor functionality.
    • Utils: Private convenience modules used within the package.
  5. What is the Editor object?

    main

    The Editor object is the central state container for a Slate editor. It stores the document structure (children), the current user selection (selection), the history of changes (operations), and active text formatting (marks).

    Key characteristics:

    • It is a type of Node with a path of [].
    • It can be extended via plugins to add custom helpers and behaviors.
    • It serves as the primary interface for both querying the state and performing manipulations.
    interface Editor {
      children: Node[]
      selection: Range | null
      operations: Operation[]
      marks: Omit<Text, 'text'> | null
    
      // Schema-specific node behaviors.
      isInline: (element: Element) => boolean
      isVoid: (element: Element) => boolean
      markableVoid: (element: Element) => boolean
      normalizeNode: (entry: NodeEntry) => void
      onChange: (options?: { operation?: Operation }) => void
    
      // Overrideable core actions.
      addMark: (key: string, value: any) => void
      apply: (operation: Operation) => void
      deleteBackward: (unit: 'character' | 'word' | 'line' | 'block') => void
      deleteForward: (unit: 'character' | 'word' | 'line' | 'block') => void
      deleteFragment: () => void
      insertBreak: () => void
      insertFragment: (fragment: Node[]) => void
      insertNode: (node: Node) => void
      insertText: (text: string) => void
      removeMark: (key: string) => void
    }
  6. What is Normalizing in Slate

    main

    Normalizing is the process of ensuring your editor's content always adheres to a specific, valid data structure. Unlike validation, which only identifies invalid states, normalizing actively fixes the content to make it valid again. This is crucial when handling complex, nested data or when users paste arbitrary rich text that might break your schema.

    Slate uses a multi-pass approach: when you apply a fix via a Transform, it triggers a new normalization pass. This allows you to write simple normalizers that focus on fixing a single specific invalid state at a time, trusting that Slate will re-run the process until the entire document is valid.

  7. Use Point locations for text offsets

    main

    A Point refers to a specific position within a text node. It combines a Path (to locate the node) and an offset (to locate the position within that node's text string).

    Important: Points always refer to text nodes. They cannot be used to point to non-text elements directly; they represent the 'cursors' or 'carets' within the text.

    Example for a text node at path [0, 0] containing 'A line of text!':

    • Start of the node: { path: [0, 0], offset: 0 }
    • End of the sentence: { path: [0, 0], offset: 15 }
    interface Point {
      path: Path
      offset: number
    }
  8. What are Slate operations and when to use them

    main

    Operations are the granular, low-level actions that occur when invoking transforms. While a single high-level transform (like a user typing a word) might trigger multiple operations, Slate's core automatically converts complex transforms into these low-level operations and applies them to the editor.

    Most developers will interact with high-level transforms. You only need to work directly with operations if you are implementing advanced features like collaborative editing, where you need to define, apply, compose, or undo specific, discrete changes to the document.

    // Example of applying a low-level operation directly
    editor.apply({
      type: 'insert_text',
      path: [0, 0],
      offset: 15,
      text: 'A new string of text to be inserted.',
    })
  9. How Plugins work in Slate 0.50.x

    main

    In the current architecture, plugins are plain functions that receive an Editor object, augment it, and return it. This uses standard function composition (wrapping) instead of the previous middleware stack.

    Plugins can:

    • Augment command execution by composing the editor.exec function.
    • Listen to operations by composing editor.apply.

    This approach allows plugins to focus purely on rich-text logic, leaving rendering and event handling to React.