/* * toolbar.ts — toolbar manager for the ribbit editor. * * Resolves tags and macros into toolbar buttons. Renders the toolbar * DOM. Manages button state (active/disabled/visible). * * Usage: * const toolbar = editor.toolbar; * toolbar.buttons.get('bold').click(); * toolbar.buttons.get('table').hide(); * document.body.prepend(toolbar.render()); */ import type { Tag, ToolbarSlot, Button } from './types'; import type { MacroDef } from './macros'; const CSS_CLASS_ACTIVE = 'active'; const CSS_CLASS_DISABLED = 'disabled'; const CSS_CLASS_TOOLBAR = 'ribbit-toolbar'; const CSS_CLASS_SPACER = 'spacer'; const CSS_CLASS_GROUP = 'ribbit-btn-group'; const CSS_CLASS_DROPDOWN = 'ribbit-dropdown'; const CSS_DISPLAY_NONE = 'none'; const MACRO_ID_PREFIX = 'macro:'; const DROPDOWN_INDICATOR = ' ▾'; /** IDs of buttons that belong in the utility section, not the tag/macro area. */ const UTILITY_BUTTON_IDS = ['save', 'toggle', 'markdown']; const MAX_HEADING_LEVEL = 6; const EDITOR_STATE_VIEW = 'view'; const EDITOR_STATE_EDIT = 'edit'; /** * Concrete implementation of the Button interface. * * Wraps a button definition with DOM element tracking and * visibility toggling. Created internally by ToolbarManager. * * @example * const button = new ButtonImpl({ id: 'bold', label: 'Bold', action: 'wrap', delimiter: '**' }); * button.hide(); * button.show(); */ class ButtonImpl implements Button { id: string; label: string; icon?: string; shortcut?: string; action: 'wrap' | 'prefix' | 'insert' | 'custom'; delimiter?: string; template?: string; replaceSelection: boolean; visible: boolean; element?: HTMLElement; handler?: () => void; constructor(definition: Partial