@blocksuite/block-std
Advanced tools
Comparing version 0.0.0-20230901235404-5365e5eb-nightly to 0.0.0-20230902132629-a4a41d59-nightly
import type { BlockStore } from '../store/index.js'; | ||
export interface CommandCtx { | ||
export interface InitCommandCtx { | ||
blockStore: BlockStore; | ||
data: Partial<BlockSuite.CommandData>; | ||
} | ||
export type Command<Options = void> = (ctx: CommandCtx, options?: Options) => boolean; | ||
type ToInnerCommand<T> = T extends Command<infer Options> ? InnerCommand<Options> : never; | ||
type InnerCommands = { | ||
[Key in BlockSuite.CommandName]: ToInnerCommand<BlockSuite.Commands[Key]>; | ||
export type CommandKeyToData<K extends BlockSuite.CommandDataName> = Pick<BlockSuite.CommandData, K>; | ||
export type Command<In extends BlockSuite.CommandDataName = never, Out extends BlockSuite.CommandDataName = never, InData extends object = {}> = (ctx: CommandKeyToData<In> & InitCommandCtx & InData, next: (ctx: CommandKeyToData<Out>) => Promise<void>) => Promise<void>; | ||
type Omit1<A, B> = [keyof Omit<A, keyof B>] extends [never] ? void : Omit<A, keyof B>; | ||
type InDataOfCommand<C> = C extends Command<infer K, any, infer R> ? CommandKeyToData<K> & R : never; | ||
type OutDataOfCommand<C> = C extends Command<any, infer K, any> ? CommandKeyToData<K> : never; | ||
type CommonMethods<In extends object = {}> = { | ||
run(): Promise<void>; | ||
with<T extends Partial<BlockSuite.CommandData>>(value: T): Chain<In & T>; | ||
inline: <InlineOut extends BlockSuite.CommandDataName = never>(command: Command<Extract<keyof In, BlockSuite.CommandDataName>, InlineOut>) => Chain<In & CommandKeyToData<InlineOut>>; | ||
}; | ||
type InnerCommand<Options = void> = (options?: Options) => Chain; | ||
type InlineCommand = (fn: Command) => Chain; | ||
type RunCommand = () => boolean; | ||
interface Chain extends InnerCommands { | ||
run: RunCommand; | ||
inline: InlineCommand; | ||
} | ||
type Chain<In extends object = {}> = CommonMethods<In> & { | ||
[K in keyof BlockSuite.Commands]: (data: Omit1<InDataOfCommand<BlockSuite.Commands[K]>, In>) => Chain<In & OutDataOfCommand<BlockSuite.Commands[K]>>; | ||
}; | ||
export declare class CommandManager { | ||
@@ -24,7 +24,8 @@ blockStore: BlockStore; | ||
add<N extends BlockSuite.CommandName>(name: N, command: BlockSuite.Commands[N]): CommandManager; | ||
pipe: () => Chain; | ||
createChain: (methods: Record<BlockSuite.CommandName, unknown>, cmds: Command[]) => Chain; | ||
pipe: () => Chain<InitCommandCtx>; | ||
} | ||
declare global { | ||
namespace BlockSuite { | ||
interface CommandData { | ||
interface CommandData extends InitCommandCtx { | ||
} | ||
@@ -34,2 +35,3 @@ interface Commands { | ||
type CommandName = keyof Commands; | ||
type CommandDataName = keyof CommandData; | ||
} | ||
@@ -36,0 +38,0 @@ } |
@@ -0,1 +1,2 @@ | ||
const cmdSymbol = Symbol('cmds'); | ||
export class CommandManager { | ||
@@ -8,37 +9,41 @@ constructor(blockStore) { | ||
blockStore: this.blockStore, | ||
data: {}, | ||
}; | ||
}; | ||
this.pipe = () => { | ||
const ctx = this._getCommandCtx(); | ||
const queue = []; | ||
// @ts-ignore | ||
const mapping = { | ||
this.createChain = (methods, cmds) => { | ||
return { | ||
[cmdSymbol]: cmds, | ||
run: () => { | ||
for (const command of queue) { | ||
const result = command(); | ||
if (!result) { | ||
return false; | ||
const ctx = this._getCommandCtx(); | ||
const runCmds = async (ctx, [cmd, ...rest]) => { | ||
if (cmd) { | ||
await cmd(ctx, data => runCmds({ ...ctx, ...data }, rest)); | ||
} | ||
} | ||
return true; | ||
}; | ||
return runCmds(ctx, cmds); | ||
}, | ||
inline: (fn) => { | ||
queue.push(() => { | ||
return fn(ctx); | ||
}); | ||
return mapping; | ||
with: value => { | ||
return this.createChain(methods, [ | ||
...cmds, | ||
(_, next) => next(value), | ||
]); | ||
}, | ||
inline: command => { | ||
return this.createChain(methods, [...cmds, command]); | ||
}, | ||
...methods, | ||
}; | ||
for (const [commandName, command] of this._commands.entries()) { | ||
const innerCommand = options => { | ||
queue.push(() => { | ||
return command(ctx, options); | ||
}); | ||
return mapping; | ||
}; | ||
this.pipe = () => { | ||
const methods = {}; | ||
const createChain = this.createChain; | ||
for (const [name, command] of this._commands.entries()) { | ||
methods[name] = function (data) { | ||
const cmds = this[cmdSymbol]; | ||
return createChain(methods, [ | ||
...cmds, | ||
(ctx, next) => command({ ...ctx, ...data }, next), | ||
]); | ||
}; | ||
// @ts-expect-error force inject command | ||
mapping[commandName] = innerCommand; | ||
} | ||
return mapping; | ||
return createChain(methods, []); | ||
}; | ||
@@ -45,0 +50,0 @@ } |
@@ -1,7 +0,10 @@ | ||
import type { UIEventDispatcher } from '../dispatcher.js'; | ||
import type { UIEventHandler } from '../base.js'; | ||
import type { EventOptions, UIEventDispatcher } from '../dispatcher.js'; | ||
export declare class KeyboardControl { | ||
private _dispatcher; | ||
private composition; | ||
constructor(_dispatcher: UIEventDispatcher); | ||
private _createContext; | ||
listen(): void; | ||
bindHotkey(keymap: Record<string, UIEventHandler>, options?: EventOptions): () => void; | ||
private _down; | ||
@@ -8,0 +11,0 @@ private _up; |
import { UIEventState, UIEventStateContext } from '../base.js'; | ||
import { bindKeymap } from '../keymap.js'; | ||
import { KeyboardEventState } from '../state/index.js'; | ||
@@ -6,2 +7,3 @@ export class KeyboardControl { | ||
this._dispatcher = _dispatcher; | ||
this.composition = false; | ||
this._down = (event) => { | ||
@@ -26,4 +28,19 @@ const keyboardEventState = new KeyboardEventState({ | ||
this._dispatcher.disposables.addFromEvent(document, 'keyup', this._up); | ||
this._dispatcher.disposables.addFromEvent(document, 'compositionstart', () => { | ||
this.composition = true; | ||
}); | ||
this._dispatcher.disposables.addFromEvent(document, 'compositionend', () => { | ||
this.composition = false; | ||
}); | ||
} | ||
bindHotkey(keymap, options) { | ||
return this._dispatcher.add('keyDown', ctx => { | ||
if (this.composition) { | ||
return false; | ||
} | ||
const binding = bindKeymap(keymap); | ||
return binding(ctx); | ||
}, options); | ||
} | ||
} | ||
//# sourceMappingURL=keyboard.js.map |
@@ -35,3 +35,3 @@ import { DisposableGroup } from '@blocksuite/global/utils'; | ||
add(name: EventName, handler: UIEventHandler, options?: EventOptions): () => void; | ||
bindHotkey(keymap: Record<string, UIEventHandler>, options?: EventOptions): () => void; | ||
bindHotkey: (keymap: Record<string, UIEventHandler>, options?: EventOptions | undefined) => () => void; | ||
private get _currentSelections(); | ||
@@ -38,0 +38,0 @@ private _getEventScope; |
@@ -8,3 +8,2 @@ import { DisposableGroup } from '@blocksuite/global/utils'; | ||
import { RangeControl } from './control/range.js'; | ||
import { bindKeymap } from './keymap.js'; | ||
import { toLowerCase } from './utils.js'; | ||
@@ -46,2 +45,3 @@ const bypassEventNames = [ | ||
this._handlersMap = Object.fromEntries(eventNames.map((name) => [name, []])); | ||
this.bindHotkey = (...args) => this._keyboardControl.bindHotkey(...args); | ||
this._pointerControl = new PointerControl(this); | ||
@@ -93,5 +93,2 @@ this._keyboardControl = new KeyboardControl(this); | ||
} | ||
bindHotkey(keymap, options) { | ||
return this.add('keyDown', bindKeymap(keymap), options); | ||
} | ||
get _currentSelections() { | ||
@@ -98,0 +95,0 @@ return this.blockStore.selectionManager.value; |
{ | ||
"name": "@blocksuite/block-std", | ||
"version": "0.0.0-20230901235404-5365e5eb-nightly", | ||
"version": "0.0.0-20230902132629-a4a41d59-nightly", | ||
"description": "Std for blocksuite blocks", | ||
@@ -12,10 +12,10 @@ "main": "dist/index.js", | ||
"peerDependencies": { | ||
"@blocksuite/store": "0.0.0-20230901235404-5365e5eb-nightly" | ||
"@blocksuite/store": "0.0.0-20230902132629-a4a41d59-nightly" | ||
}, | ||
"dependencies": { | ||
"w3c-keyname": "^2.2.8", | ||
"@blocksuite/global": "0.0.0-20230901235404-5365e5eb-nightly" | ||
"@blocksuite/global": "0.0.0-20230902132629-a4a41d59-nightly" | ||
}, | ||
"devDependencies": { | ||
"@blocksuite/store": "0.0.0-20230901235404-5365e5eb-nightly" | ||
"@blocksuite/store": "0.0.0-20230902132629-a4a41d59-nightly" | ||
}, | ||
@@ -22,0 +22,0 @@ "exports": { |
import type { BlockStore } from '../store/index.js'; | ||
export interface CommandCtx { | ||
export interface InitCommandCtx { | ||
blockStore: BlockStore; | ||
data: Partial<BlockSuite.CommandData>; | ||
} | ||
export type Command<Options = void> = ( | ||
ctx: CommandCtx, | ||
options?: Options | ||
) => boolean; | ||
type ToInnerCommand<T> = T extends Command<infer Options> | ||
? InnerCommand<Options> | ||
export type CommandKeyToData<K extends BlockSuite.CommandDataName> = Pick< | ||
BlockSuite.CommandData, | ||
K | ||
>; | ||
export type Command< | ||
In extends BlockSuite.CommandDataName = never, | ||
Out extends BlockSuite.CommandDataName = never, | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
InData extends object = {}, | ||
> = ( | ||
ctx: CommandKeyToData<In> & InitCommandCtx & InData, | ||
next: (ctx: CommandKeyToData<Out>) => Promise<void> | ||
) => Promise<void>; | ||
type Omit1<A, B> = [keyof Omit<A, keyof B>] extends [never] | ||
? void | ||
: Omit<A, keyof B>; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type InDataOfCommand<C> = C extends Command<infer K, any, infer R> | ||
? CommandKeyToData<K> & R | ||
: never; | ||
type InnerCommands = { | ||
[Key in BlockSuite.CommandName]: ToInnerCommand<BlockSuite.Commands[Key]>; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type OutDataOfCommand<C> = C extends Command<any, infer K, any> | ||
? CommandKeyToData<K> | ||
: never; | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
type CommonMethods<In extends object = {}> = { | ||
run(): Promise<void>; | ||
with<T extends Partial<BlockSuite.CommandData>>(value: T): Chain<In & T>; | ||
inline: <InlineOut extends BlockSuite.CommandDataName = never>( | ||
command: Command<Extract<keyof In, BlockSuite.CommandDataName>, InlineOut> | ||
) => Chain<In & CommandKeyToData<InlineOut>>; | ||
}; | ||
const cmdSymbol = Symbol('cmds'); | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
type Chain<In extends object = {}> = CommonMethods<In> & { | ||
[K in keyof BlockSuite.Commands]: ( | ||
data: Omit1<InDataOfCommand<BlockSuite.Commands[K]>, In> | ||
) => Chain<In & OutDataOfCommand<BlockSuite.Commands[K]>>; | ||
}; | ||
type InnerCommand<Options = void> = (options?: Options) => Chain; | ||
type InlineCommand = (fn: Command) => Chain; | ||
type RunCommand = () => boolean; | ||
interface Chain extends InnerCommands { | ||
run: RunCommand; | ||
inline: InlineCommand; | ||
} | ||
export class CommandManager { | ||
@@ -37,6 +52,5 @@ private _commands = new Map<string, Command>(); | ||
private _getCommandCtx = () => { | ||
private _getCommandCtx = (): InitCommandCtx => { | ||
return { | ||
blockStore: this.blockStore, | ||
data: {}, | ||
}; | ||
@@ -54,36 +68,52 @@ }; | ||
pipe = () => { | ||
const ctx = this._getCommandCtx(); | ||
const queue: Array<() => boolean> = []; | ||
// @ts-ignore | ||
const mapping: Chain = { | ||
createChain = ( | ||
methods: Record<BlockSuite.CommandName, unknown>, | ||
cmds: Command[] | ||
): Chain => { | ||
return { | ||
[cmdSymbol]: cmds, | ||
run: () => { | ||
for (const command of queue) { | ||
const result = command(); | ||
if (!result) { | ||
return false; | ||
const ctx = this._getCommandCtx(); | ||
const runCmds = async ( | ||
ctx: BlockSuite.CommandData, | ||
[cmd, ...rest]: Command[] | ||
) => { | ||
if (cmd) { | ||
await cmd(ctx, data => runCmds({ ...ctx, ...data }, rest)); | ||
} | ||
} | ||
return true; | ||
}; | ||
return runCmds(ctx, cmds); | ||
}, | ||
inline: (fn: Command) => { | ||
queue.push(() => { | ||
return fn(ctx); | ||
}); | ||
return mapping; | ||
with: value => { | ||
return this.createChain(methods, [ | ||
...cmds, | ||
(_, next) => next(value), | ||
]) as never; | ||
}, | ||
}; | ||
for (const [commandName, command] of this._commands.entries()) { | ||
const innerCommand: InnerCommand = options => { | ||
queue.push(() => { | ||
return command(ctx, options); | ||
}); | ||
return mapping; | ||
inline: command => { | ||
return this.createChain(methods, [...cmds, command]) as never; | ||
}, | ||
...methods, | ||
} as Chain; | ||
}; | ||
pipe = (): Chain<InitCommandCtx> => { | ||
const methods = {} as Record< | ||
string, | ||
(data: Record<string, unknown>) => Chain | ||
>; | ||
const createChain = this.createChain; | ||
for (const [name, command] of this._commands.entries()) { | ||
methods[name] = function ( | ||
this: { [cmdSymbol]: Command[] }, | ||
data: Record<string, unknown> | ||
) { | ||
const cmds = this[cmdSymbol]; | ||
return createChain(methods, [ | ||
...cmds, | ||
(ctx, next) => command({ ...ctx, ...data }, next), | ||
]); | ||
}; | ||
// @ts-expect-error force inject command | ||
mapping[commandName] = innerCommand; | ||
} | ||
return mapping; | ||
return createChain(methods, []); | ||
}; | ||
@@ -94,7 +124,9 @@ } | ||
namespace BlockSuite { | ||
interface CommandData {} | ||
interface CommandData extends InitCommandCtx {} | ||
interface Commands {} | ||
type CommandName = keyof Commands; | ||
type CommandDataName = keyof CommandData; | ||
} | ||
} |
@@ -0,6 +1,9 @@ | ||
import type { UIEventHandler } from '../base.js'; | ||
import { UIEventState, UIEventStateContext } from '../base.js'; | ||
import type { UIEventDispatcher } from '../dispatcher.js'; | ||
import type { EventOptions, UIEventDispatcher } from '../dispatcher.js'; | ||
import { bindKeymap } from '../keymap.js'; | ||
import { KeyboardEventState } from '../state/index.js'; | ||
export class KeyboardControl { | ||
private composition = false; | ||
constructor(private _dispatcher: UIEventDispatcher) {} | ||
@@ -15,4 +18,32 @@ | ||
this._dispatcher.disposables.addFromEvent(document, 'keyup', this._up); | ||
this._dispatcher.disposables.addFromEvent( | ||
document, | ||
'compositionstart', | ||
() => { | ||
this.composition = true; | ||
} | ||
); | ||
this._dispatcher.disposables.addFromEvent( | ||
document, | ||
'compositionend', | ||
() => { | ||
this.composition = false; | ||
} | ||
); | ||
} | ||
bindHotkey(keymap: Record<string, UIEventHandler>, options?: EventOptions) { | ||
return this._dispatcher.add( | ||
'keyDown', | ||
ctx => { | ||
if (this.composition) { | ||
return false; | ||
} | ||
const binding = bindKeymap(keymap); | ||
return binding(ctx); | ||
}, | ||
options | ||
); | ||
} | ||
private _down = (event: KeyboardEvent) => { | ||
@@ -19,0 +50,0 @@ const keyboardEventState = new KeyboardEventState({ |
@@ -11,3 +11,2 @@ import { DisposableGroup } from '@blocksuite/global/utils'; | ||
import { RangeControl } from './control/range.js'; | ||
import { bindKeymap } from './keymap.js'; | ||
import { toLowerCase } from './utils.js'; | ||
@@ -139,5 +138,4 @@ | ||
bindHotkey(keymap: Record<string, UIEventHandler>, options?: EventOptions) { | ||
return this.add('keyDown', bindKeymap(keymap), options); | ||
} | ||
bindHotkey = (...args: Parameters<KeyboardControl['bindHotkey']>) => | ||
this._keyboardControl.bindHotkey(...args); | ||
@@ -144,0 +142,0 @@ private get _currentSelections() { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
274493
3774
+ Added@blocksuite/global@0.0.0-20230902132629-a4a41d59-nightly(transitive)
+ Added@blocksuite/store@0.0.0-20230902132629-a4a41d59-nightly(transitive)
+ Added@blocksuite/virgo@0.0.0-20230902132629-a4a41d59-nightly(transitive)
- Removed@blocksuite/global@0.0.0-20230901235404-5365e5eb-nightly(transitive)
- Removed@blocksuite/store@0.0.0-20230901235404-5365e5eb-nightly(transitive)
- Removed@blocksuite/virgo@0.0.0-20230901235404-5365e5eb-nightly(transitive)
Updated@blocksuite/global@0.0.0-20230902132629-a4a41d59-nightly