Skip to content

Utility Types

Utility types and functions used across the notectl codebase. These are grouped here because each individual API surface is small.

Nominal types that prevent accidentally passing a raw string where a specific identifier is expected. Built on TypeScript’s branded type pattern.

import { blockId, nodeType, markType, inlineType, pluginId, commandName } from '@notectl/core';
TypeFactory FunctionExample
BlockIdblockId(id)blockId('b1')
NodeTypeNamenodeType(name)nodeType('heading')
MarkTypeNamemarkType(name)markType('bold')
InlineTypeNameinlineType(name)inlineType('emoji')
PluginIdpluginId(id)pluginId('my-plugin')
CommandNamecommandName(name)commandName('toggleBold')

Each factory returns the input string cast to the branded type. They are zero-cost at runtime.


Module-augmentable interfaces that let plugins declare type-safe block, mark, and inline node attributes.

interface NodeAttrRegistry {
paragraph: { align?: BlockAlignment };
}

Plugins augment this to add their own types:

declare module '@notectl/core' {
interface NodeAttrRegistry {
heading: { level: number };
code_block: { language: string };
}
}
interface MarkAttrRegistry {
bold: Record<string, never>;
italic: Record<string, never>;
underline: Record<string, never>;
}

Augment for marks with attributes:

declare module '@notectl/core' {
interface MarkAttrRegistry {
link: { href: string; title?: string };
textColor: { color: string };
}
}
interface InlineNodeAttrRegistry {
// Augment per inline node type
}
TypeDescription
NodeAttrsFor<T>Resolves to NodeAttrRegistry[T] for known types, Record<string, unknown> otherwise
MarkAttrsFor<T>Resolves to MarkAttrRegistry[T] for known types, Record<string, unknown> otherwise
InlineNodeAttrsFor<T>Resolves to InlineNodeAttrRegistry[T] for known types, Record<string, unknown> otherwise
import { isNodeOfType, isMarkOfType, isInlineNodeOfType } from '@notectl/core';
FunctionSignatureDescription
isNodeOfType<T>(node, type) => node is ...Narrows BlockNode to a specific type with typed attrs
isMarkOfType<T>(mark, type) => mark is ...Narrows Mark to a specific type with typed attrs
isInlineNodeOfType<T>(node, type) => node is ...Narrows InlineNode to a specific type with typed attrs

Example:

if (isNodeOfType(block, 'heading')) {
block.attrs.level; // number — type-safe
}
type BlockAlignment = 'left' | 'center' | 'right' | 'justify';

Type-safe keys for the plugin event bus and service registry. See also Plugin Interface.

import { EventKey } from '@notectl/core';
const SearchChanged = new EventKey<{ query: string }>('search-changed');
import { ServiceKey } from '@notectl/core';
interface SpellChecker { check(text: string): string[]; }
const SpellCheckerKey = new ServiceKey<SpellChecker>('spell-checker');

Standalone event bus class. See Plugin Interface for full API.

import { EventBus } from '@notectl/core';
const bus = new EventBus();
const unsub = bus.on(SearchChanged, (payload) => {
console.log(payload.query); // type-safe
});
bus.emit(SearchChanged, { query: 'hello' });
unsub();

Unicode-aware functions for traversing text by grapheme cluster (not code unit). Essential for correct cursor movement with emoji, combining characters, and other multi-code-unit graphemes.

import { nextGraphemeSize, prevGraphemeSize } from '@notectl/core';

Returns the number of UTF-16 code units in the grapheme cluster starting at offset:

nextGraphemeSize('Hello', 0); // 1 (H)
nextGraphemeSize('👨‍👩‍👧', 0); // 8 (family emoji)

Returns the number of UTF-16 code units in the grapheme cluster ending at offset:

prevGraphemeSize('Hello', 5); // 1 (o)

Escapes &, <, >, and " for safe HTML insertion:

import { escapeHTML } from '@notectl/core';
escapeHTML('<script>alert("xss")</script>');
// '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'

Pretty-prints HTML with indentation for block-level elements:

import { formatHTML } from '@notectl/core';
formatHTML('<div><p>Hello</p></div>');
// '<div>\n <p>Hello</p>\n</div>'

The default indent is two spaces.


Types and utilities for paper dimensions, used by the print plugin and paper mode.

import { PaperSize, getPaperDimensions, getPaperCSSSize, isValidPaperSize } from '@notectl/core';
const PaperSize = {
DINA4: 'din-a4',
DINA5: 'din-a5',
USLetter: 'us-letter',
USLegal: 'us-legal',
} as const;
type PaperSize = 'din-a4' | 'din-a5' | 'us-letter' | 'us-legal';
interface PaperDimensions {
readonly widthMm: number;
readonly heightMm: number;
readonly widthPx: number;
readonly heightPx: number;
}
FunctionSignatureDescription
getPaperDimensions(size: PaperSize) => PaperDimensionsGet dimensions in mm and px
getPaperCSSSize(size: PaperSize) => stringGet CSS @page size value (e.g. '210mm 297mm')
isValidPaperSize(value: string) => value is PaperSizeType guard for PaperSize values
ConstantValueDescription
PAPER_MARGIN_TOP_PX48Top margin in paper mode
PAPER_MARGIN_HORIZONTAL_PX56Horizontal margins in paper mode
PAPER_VIEWPORT_PADDING_PX24Viewport padding around paper

Supported locale identifiers:

const Locale = {
EN: 'en',
DE: 'de',
ES: 'es',
FR: 'fr',
ZH: 'zh',
RU: 'ru',
AR: 'ar',
HI: 'hi',
PT: 'pt',
BROWSER: 'browser',
} as const;
type Locale = 'en' | 'de' | 'es' | 'fr' | 'zh' | 'ru' | 'ar' | 'hi' | 'pt' | 'browser';

Use Locale.BROWSER to auto-detect from navigator.language.

Service that provides the current locale to plugins:

import { LocaleService, LocaleServiceKey } from '@notectl/core';
const service = new LocaleService('en');
service.getLocale(); // 'en'

Access from a plugin:

const locale = context.getService(LocaleServiceKey);
if (locale) {
const lang = locale.getLocale();
}

Returns a human-readable label for a block type name. Used internally by the announcer for screen reader output.

import { getBlockTypeLabel } from '@notectl/core';
getBlockTypeLabel('paragraph'); // 'Paragraph'
getBlockTypeLabel('heading'); // 'Heading'
getBlockTypeLabel('heading', { level: 2 }); // 'Heading 2'
getBlockTypeLabel('code_block'); // 'Code Block'
getBlockTypeLabel('unknown_type'); // 'unknown_type' (fallback)
function getBlockTypeLabel(typeName: string, attrs?: Record<string, unknown>): string