Files
tools/vue/writekit/src/commands/util.ts
T
robonen 263c32002f feat(writekit): rename @robonen/editor to @robonen/writekit
Rename the rich-text editor package and all Editor* exports to Writekit*;
remove the old vue/editor tree.
2026-06-15 16:54:06 +07:00

60 lines
2.1 KiB
TypeScript

import type { Attrs, Node } from '../model';
import { blockById, isCollapsed, marksAt, nodeInline, orderedSelection, rangeHasMarkType } from '../model';
import type { WritekitState } from '../state';
/** Block id the selection's focus is in (or the first node-selected block). */
export function selectionBlockId(state: WritekitState): string | undefined {
const sel = state.selection;
return sel.kind === 'text' ? sel.focus.blockId : sel.ids[0];
}
/** The block the selection currently focuses, or `null`. */
export function focusBlock(state: WritekitState): Node | null {
const id = selectionBlockId(state);
return id ? blockById(state.doc, id) : null;
}
/** Whether a block type holds inline (text) content. */
export function isTextBlockType(state: WritekitState, type: string): boolean {
return state.schema.nodeSpec(type)?.content.kind === 'text';
}
/**
* Whether a mark is active for the current selection — used by `toggleMark` and
* by toolbars (call a command without `dispatch` for the same answer).
*/
export function isMarkActive(state: WritekitState, type: string): boolean {
const sel = state.selection;
if (sel.kind !== 'text')
return false;
if (isCollapsed(sel)) {
if (state.storedMarks)
return state.storedMarks.some(mark => mark.type === type);
const block = blockById(state.doc, sel.focus.blockId);
return block ? marksAt(nodeInline(block), sel.focus.offset).some(mark => mark.type === type) : false;
}
if (sel.anchor.blockId !== sel.focus.blockId)
return false;
const { from, to } = orderedSelection(sel, state.doc);
const block = blockById(state.doc, sel.focus.blockId);
return block ? rangeHasMarkType(nodeInline(block), from.offset, to.offset, type) : false;
}
/** Whether the focused block matches a type (and optionally a subset of attrs). */
export function isBlockActive(state: WritekitState, type: string, attrs?: Attrs): boolean {
const block = focusBlock(state);
if (!block || block.type !== type)
return false;
if (!attrs)
return true;
return Object.keys(attrs).every(key => block.attrs[key] === attrs[key]);
}