or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

command-system.mdconfiguration.mdcore-plugin.mddocument-structure.mdediting-engine.mdindex.mdui-components.md
tile.json

command-system.mddocs/

Command System

The heading command system provides programmatic control over heading application and state management. Commands enable both UI components and external code to apply heading formats and query the current heading state.

Capabilities

HeadingCommand

Command for applying headings to selected blocks and tracking the current heading state.

/**
 * Command for applying headings. Used by the heading feature to apply headings.
 */
class HeadingCommand extends Command {
    /** Current heading level or false if not in heading */
    declare public value: false | string;
    
    /** Set of supported model element names */
    readonly modelElements: Array<string>;
    
    /**
     * Creates a heading command instance.
     * @param editor - Editor instance
     * @param modelElements - Array of supported heading model element names
     */
    constructor(editor: Editor, modelElements: Array<string>);
    
    /**
     * Updates command state based on selection.
     * Called automatically when selection changes to update value and isEnabled properties.
     */
    refresh(): void;
    
    /**
     * Applies heading to selected blocks.
     * @param options - Command options
     * @param options.value - Heading level to apply (e.g., 'heading1', 'paragraph')
     */
    execute(options: { value: string }): void;
}

Usage Examples:

// Get the heading command
const headingCommand = editor.commands.get('heading');

// Apply different heading levels
editor.execute('heading', { value: 'heading1' });
editor.execute('heading', { value: 'heading2' });
editor.execute('heading', { value: 'heading3' });

// Convert to paragraph
editor.execute('heading', { value: 'paragraph' });

// Check current state
console.log(headingCommand.value); // 'heading1', 'heading2', etc., or false
console.log(headingCommand.isEnabled); // boolean - whether command can be executed

// Listen for command state changes
headingCommand.on('change:value', (evt, propertyName, newValue, oldValue) => {
    console.log(`Heading changed from ${oldValue} to ${newValue}`);
});

headingCommand.on('change:isEnabled', (evt, propertyName, newValue) => {
    console.log(`Heading command enabled: ${newValue}`);
});

Command State Management

The HeadingCommand automatically tracks the current heading state:

Value Property:

  • Returns the current heading level ('heading1', 'heading2', etc.) when in a heading
  • Returns false when in a paragraph or other non-heading element
  • Updates automatically when selection changes

IsEnabled Property:

  • Returns true when the command can be executed (valid selection)
  • Returns false when the command cannot be executed (invalid context)
// Example state tracking:
// User selects text in an h2 element:
console.log(headingCommand.value); // 'heading1' (assuming heading1 maps to h2)
console.log(headingCommand.isEnabled); // true

// User selects text in a paragraph:
console.log(headingCommand.value); // false
console.log(headingCommand.isEnabled); // true

// User selects an unsupported element:
console.log(headingCommand.value); // false  
console.log(headingCommand.isEnabled); // false

Command Execution

The execute() method applies heading formats to the current selection:

Single Block Selection:

  • Converts the selected block to the specified heading level
  • Preserves inline formatting within the block

Multiple Block Selection:

  • Converts all selected blocks to the specified heading level
  • Each block is converted individually

Mixed Selection:

  • Handles selections that span multiple block types
  • Converts all applicable blocks to the target heading level
// Example executions:
// Before: <paragraph>Selected text|</paragraph>
editor.execute('heading', { value: 'heading1' });
// After: <heading1>Selected text|</heading1>

// Before: 
// <paragraph>First block|</paragraph>
// <heading2>Second block</heading2>
editor.execute('heading', { value: 'heading3' });
// After:
// <heading3>First block|</heading3>
// <heading3>Second block</heading3>

// Convert heading back to paragraph:
editor.execute('heading', { value: 'paragraph' });

Model Element Support

The command works with the model elements defined in the heading configuration:

// Default model elements:
const defaultModelElements = ['paragraph', 'heading1', 'heading2', 'heading3'];

// Custom model elements:
const customConfig = {
    heading: {
        options: [
            { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
            { model: 'title', view: 'h1', title: 'Title', class: 'ck-heading_title' },
            { model: 'subtitle', view: 'h2', title: 'Subtitle', class: 'ck-heading_subtitle' }
        ]
    }
};

// Command will support: ['paragraph', 'title', 'subtitle']
editor.execute('heading', { value: 'title' });
editor.execute('heading', { value: 'subtitle' });

Integration with UI Components

The HeadingCommand is used by both UI components:

HeadingUI Dropdown:

  • Dropdown options execute the command with their respective values
  • Dropdown shows active state based on command value
  • Dropdown enabled/disabled state reflects command.isEnabled

HeadingButtonsUI Buttons:

  • Each button executes the command with its corresponding value
  • Button active state reflects whether command.value matches the button's value
  • Button enabled/disabled state reflects command.isEnabled
// UI component integration example:
// When user clicks "Heading 1" in dropdown:
// → editor.execute('heading', { value: 'heading1' });

// When user clicks the heading1 button:
// → editor.execute('heading', { value: 'heading1' });

// UI components update their state based on:
// → headingCommand.value and headingCommand.isEnabled

Error Handling

The command includes validation and error handling:

  • Invalid values: Attempting to execute with unsupported heading values is ignored
  • Invalid selection: Command is disabled when selection doesn't support headings
  • Schema validation: Respects editor schema rules for where headings can be placed
// Error handling examples:
editor.execute('heading', { value: 'invalidHeading' }); // Ignored - invalid value

// In a context where headings aren't allowed:
console.log(headingCommand.isEnabled); // false
editor.execute('heading', { value: 'heading1' }); // No effect