Core context management module for Milkdown editor providing dependency injection and state management
npx @tessl/cli install tessl/npm-milkdown--ctx@7.15.0@milkdown/ctx is the core context management module for the Milkdown editor framework. It provides a sophisticated dependency injection and state management system through Container and Slice patterns, along with timing/scheduling capabilities and comprehensive debugging tools. The package enables plugin-based architecture where components can inject dependencies, manage reactive state, and coordinate through a well-defined context system.
npm install @milkdown/ctximport {
Container,
Slice,
SliceType,
createSlice,
Ctx,
Clock,
Timer,
TimerType,
createTimer,
Inspector,
type Meta,
type MilkdownPlugin,
type Telemetry,
type TimerStatus
} from "@milkdown/ctx";For CommonJS:
const {
Container,
Slice,
SliceType,
createSlice,
Ctx,
Clock,
Timer,
TimerType,
createTimer,
Inspector
} = require("@milkdown/ctx");import { Container, createSlice, Ctx, Clock } from "@milkdown/ctx";
// Create a container and clock
const container = new Container();
const clock = new Clock();
// Create a slice type for state management
const counterSlice = createSlice(0, "counter");
// Create context and inject the slice
const ctx = new Ctx(container, clock);
ctx.inject(counterSlice, 5);
// Use the context to access and update state
const currentValue = ctx.get(counterSlice); // 5
ctx.update(counterSlice, (prev) => prev + 1);
console.log(ctx.get(counterSlice)); // 6
// React to state changes
const slice = ctx.use(counterSlice);
const unsubscribe = slice.on((value) => {
console.log("Counter changed to:", value);
});@milkdown/ctx is built around several key architectural patterns:
Core dependency injection and state management through Container and Slice system. Provides type-safe reactive state with watcher support for building plugin-based architectures.
class Container {
get<T, N extends string = string>(slice: SliceType<T, N> | N): Slice<T, N>;
remove<T, N extends string = string>(slice: SliceType<T, N> | N): void;
has<T, N extends string = string>(slice: SliceType<T, N> | N): boolean;
}
class Slice<T = any, N extends string = string> {
readonly type: SliceType<T, N>;
on(watcher: (value: T) => unknown): () => void;
once(watcher: (value: T) => unknown): () => void;
off(watcher: (value: T) => unknown): void;
offAll(): void;
set(value: T): void;
get(): T;
update(updater: (prev: T) => T): void;
}
class SliceType<T = any, N extends string = string> {
readonly id: symbol;
readonly name: N;
constructor(value: T, name: N);
create(container: SliceMap, value?: T): Slice<T, N>;
}
function createSlice<T = any, N extends string = string>(value: T, name: N): SliceType<T, N>;Central orchestration class providing unified access to containers, clocks, and debugging capabilities for plugin development and state coordination.
class Ctx {
readonly meta: Meta | undefined;
readonly inspector: Inspector | undefined;
constructor(container: Container, clock: Clock, meta?: Meta);
produce(meta?: Meta): Ctx;
inject<T>(sliceType: SliceType<T>, value?: T): Ctx;
remove<T, N extends string = string>(sliceType: SliceType<T, N> | N): Ctx;
record(timerType: TimerType): Ctx;
clearTimer(timerType: TimerType): Ctx;
isInjected<T, N extends string = string>(sliceType: SliceType<T, N> | N): boolean;
isRecorded(timerType: TimerType): boolean;
use<T, N extends string = string>(sliceType: SliceType<T, N> | N): Slice<T, N>;
get<T, N extends string>(sliceType: SliceType<T, N> | N): T;
set<T, N extends string>(sliceType: SliceType<T, N> | N, value: T): void;
update<T, N extends string>(sliceType: SliceType<T, N> | N, updater: (prev: T) => T): void;
timer(timer: TimerType): Timer;
done(timer: TimerType): void;
wait(timer: TimerType): Promise<void>;
waitTimers(slice: SliceType<TimerType[]>): Promise<void>;
}
type MilkdownPlugin = { meta?: Meta } & ((ctx: Ctx) => CtxRunner);Promise-based timer system with event-driven resolution for scheduling and synchronization in plugin architectures.
class Clock {
readonly store: TimerMap;
get(timer: TimerType): Timer;
remove(timer: TimerType): void;
has(timer: TimerType): boolean;
}
class Timer {
readonly type: TimerType;
readonly status: TimerStatus;
start(): Promise<void>;
done(): void;
}
class TimerType {
readonly id: symbol;
readonly name: string;
readonly timeout: number;
constructor(name: string, timeout?: number);
create(clock: TimerMap): Timer;
}
function createTimer(name: string, timeout?: number): TimerType;
type TimerStatus = 'pending' | 'resolved' | 'rejected';Debugging and telemetry system for monitoring ctx operations, slice usage, and timer execution in development and production environments.
class Inspector {
constructor(container: Container, clock: Clock, meta: Meta);
read(): Telemetry;
}
interface Meta {
displayName: string;
description?: string;
package: string;
group?: string;
additional?: Record<string, any>;
}
interface Telemetry {
metadata: Meta;
injectedSlices: { name: string; value: unknown }[];
consumedSlices: { name: string; value: unknown }[];
recordedTimers: { name: string; duration: number; status: TimerStatus }[];
waitTimers: { name: string; duration: number; status: TimerStatus }[];
}type SliceMap = Map<symbol, Slice>;
type TimerMap = Map<symbol, Timer>;
type Cleanup = () => void | Promise<void>;
type RunnerReturnType = void | Promise<void> | Cleanup | Promise<Cleanup>;
type CtxRunner = () => RunnerReturnType;