@blocksuite/block-std
Advanced tools
Comparing version 0.0.0-20230801164049-94862d4d-nightly to 0.0.0-20230802170305-bdf398b9-nightly
@@ -0,1 +1,2 @@ | ||
import { assertExists } from '@blocksuite/global/utils'; | ||
import { UIEventState, UIEventStateContext } from '../base.js'; | ||
@@ -50,3 +51,3 @@ export class RangeControl { | ||
.map(blockView => { | ||
return this._dispatcher.blockStore.viewStore.blockViewMap.getPath(blockView); | ||
return blockView.path; | ||
}) | ||
@@ -70,5 +71,7 @@ .filter((path) => !!path); | ||
const ancestor = range.commonAncestorContainer; | ||
const getBlockView = this._dispatcher.blockStore.config.getBlockViewByNode; | ||
const getBlockView = this._dispatcher.blockStore.viewStore.getNodeView; | ||
if (ancestor.nodeType === Node.TEXT_NODE) { | ||
return [getBlockView(ancestor)]; | ||
const view = getBlockView(ancestor)?.view; | ||
assertExists(view); | ||
return [view]; | ||
} | ||
@@ -104,3 +107,3 @@ const nodes = new Set(); | ||
nodes.forEach(node => { | ||
const blockView = getBlockView(node); | ||
const blockView = getBlockView(node)?.view; | ||
if (!blockView) { | ||
@@ -107,0 +110,0 @@ return; |
@@ -115,3 +115,3 @@ import { DisposableGroup } from '@blocksuite/global/utils'; | ||
scope.paths.forEach(path => { | ||
const instance = this.blockStore.viewStore.blockViewMap.get(path); | ||
const instance = this.blockStore.viewStore.getViewByPath(path); | ||
if (instance) { | ||
@@ -148,4 +148,3 @@ targetMap.set(path, instance); | ||
return; | ||
const blockView = this.blockStore.config.getBlockViewByNode(target); | ||
const path = this.blockStore.viewStore.blockViewMap.getPath(blockView); | ||
const path = this.blockStore.viewStore.getNodeView(target)?.path; | ||
if (!path) | ||
@@ -152,0 +151,0 @@ return; |
@@ -9,9 +9,8 @@ import type { Page, Workspace } from '@blocksuite/store'; | ||
} | ||
export interface BlockStoreOptions<BlockViewType = unknown> { | ||
export interface BlockStoreOptions { | ||
root: HTMLElement; | ||
workspace: Workspace; | ||
page: Page; | ||
config: BlockStoreConfig<BlockViewType>; | ||
} | ||
export declare class BlockStore<ComponentType = unknown, BlockViewType = unknown, WidgetViewType = unknown> { | ||
export declare class BlockStore<ComponentType = unknown, NodeView = unknown> { | ||
page: Page; | ||
@@ -23,5 +22,4 @@ readonly workspace: Workspace; | ||
readonly specStore: SpecStore<ComponentType>; | ||
readonly viewStore: ViewStore<BlockViewType, WidgetViewType>; | ||
readonly config: BlockStoreConfig<BlockViewType>; | ||
constructor(options: BlockStoreOptions<BlockViewType>); | ||
readonly viewStore: ViewStore<NodeView>; | ||
constructor(options: BlockStoreOptions); | ||
mount(): void; | ||
@@ -28,0 +26,0 @@ unmount(): void; |
@@ -10,7 +10,6 @@ import { UIEventDispatcher } from '../event/index.js'; | ||
this.page = options.page; | ||
this.config = options.config; | ||
this.uiEventDispatcher = new UIEventDispatcher(this); | ||
this.selectionManager = new SelectionManager(this); | ||
this.specStore = new SpecStore(this); | ||
this.viewStore = new ViewStore(); | ||
this.viewStore = new ViewStore(this); | ||
} | ||
@@ -20,2 +19,3 @@ mount() { | ||
this.uiEventDispatcher.mount(); | ||
this.viewStore.mount(); | ||
} | ||
@@ -25,3 +25,3 @@ unmount() { | ||
this.selectionManager.unmount(); | ||
this.viewStore.clear(); | ||
this.viewStore.unmount(); | ||
this.specStore.dispose(); | ||
@@ -28,0 +28,0 @@ } |
@@ -1,7 +0,40 @@ | ||
import { PathMap } from './path-map.js'; | ||
export declare class ViewStore<BlockView = unknown, WidgetView = unknown> { | ||
readonly blockViewMap: PathMap<BlockView>; | ||
readonly widgetViewMap: PathMap<WidgetView>; | ||
clear(): void; | ||
import type { BlockStore } from './block-store.js'; | ||
export type NodeView<T = unknown> = { | ||
id: string; | ||
path: string[]; | ||
view: T; | ||
}; | ||
export type NodeViewLeaf<T> = NodeView<T> & { | ||
type: BlockSuiteViewType; | ||
}; | ||
export type NodeViewTree<T> = NodeViewLeaf<T> & { | ||
children: NodeViewTree<T>[]; | ||
}; | ||
export interface BlockSuiteViewSpec<T = unknown> { | ||
fromDOM: (node: Node) => null | NodeView<T>; | ||
toDOM: (nodeView: NodeView<T>) => Element; | ||
getChildren: (node: Element) => Element[]; | ||
} | ||
export declare class ViewStore<NodeViewType = unknown> { | ||
blockStore: BlockStore; | ||
private _cachedTree; | ||
private _cachedPath; | ||
private _observer; | ||
readonly viewSpec: Map<BlockSuiteViewType, BlockSuiteViewValue<BlockSuiteViewType>>; | ||
constructor(blockStore: BlockStore); | ||
register<T extends BlockSuiteViewType>(type: T, spec: BlockSuiteView[T]): void; | ||
getNodeView: (node: Node) => NodeViewLeaf<NodeViewType> | null; | ||
calculatePath: (node: Node) => string[]; | ||
calculateNodeViewPath: (node: Node) => NodeViewLeaf<NodeViewType>[]; | ||
getNodeViewTree: () => NodeViewTree<NodeViewType>; | ||
getViewByPath: (path: string[]) => NodeViewLeaf<NodeViewType> | null; | ||
mount(): void; | ||
unmount(): void; | ||
} | ||
declare global { | ||
interface BlockSuiteView { | ||
} | ||
type BlockSuiteViewType = string & keyof BlockSuiteView; | ||
type BlockSuiteViewValue<T extends BlockSuiteViewType = BlockSuiteViewType> = BlockSuiteView[T]; | ||
} | ||
//# sourceMappingURL=view-store.d.ts.map |
@@ -1,12 +0,112 @@ | ||
import { PathMap } from './path-map.js'; | ||
import { assertExists } from '@blocksuite/global/utils'; | ||
const observeOptions = { | ||
childList: true, | ||
subtree: true, | ||
}; | ||
export class ViewStore { | ||
constructor() { | ||
this.blockViewMap = new PathMap(); | ||
this.widgetViewMap = new PathMap(); | ||
constructor(blockStore) { | ||
this.blockStore = blockStore; | ||
this._cachedTree = null; | ||
this._cachedPath = new Map(); | ||
this.viewSpec = new Map(); | ||
this.getNodeView = (node) => { | ||
for (const [type, spec] of this.viewSpec.entries()) { | ||
const view = spec.fromDOM(node); | ||
if (view) { | ||
return { | ||
type, | ||
...view, | ||
}; | ||
} | ||
} | ||
return null; | ||
}; | ||
this.calculatePath = (node) => { | ||
const path = this.calculateNodeViewPath(node); | ||
return path.map(x => x.id); | ||
}; | ||
this.calculateNodeViewPath = (node) => { | ||
if (this._cachedPath.has(node)) { | ||
return this._cachedPath.get(node); | ||
} | ||
const root = this.blockStore.root; | ||
const iterate = (node, path) => { | ||
if (!node || node === root) | ||
return path; | ||
const nodeView = this.getNodeView(node); | ||
if (!nodeView) { | ||
return path; | ||
} | ||
const spec = this.viewSpec.get(nodeView.type); | ||
assertExists(spec); | ||
const next = spec.toDOM(nodeView).parentElement; | ||
if (!next) { | ||
return path; | ||
} | ||
return iterate(next, path.concat(nodeView)); | ||
}; | ||
const path = iterate(node, []).reverse(); | ||
this._cachedPath.set(node, path); | ||
return path; | ||
}; | ||
this.getNodeViewTree = () => { | ||
if (this._cachedTree) { | ||
return this._cachedTree; | ||
} | ||
const iterate = (node) => { | ||
const nodeView = this.getNodeView(node); | ||
if (!nodeView) { | ||
throw new Error('nodeView not found'); | ||
} | ||
const spec = this.viewSpec.get(nodeView.type); | ||
assertExists(spec); | ||
const children = spec | ||
.getChildren(spec.toDOM(nodeView)) | ||
.map(child => iterate(child)); | ||
return { | ||
...nodeView, | ||
children, | ||
}; | ||
}; | ||
const firstBlock = this.blockStore.root.firstElementChild; | ||
assertExists(firstBlock); | ||
const tree = { | ||
id: '__root__', | ||
path: [], | ||
children: [iterate(firstBlock)], | ||
}; | ||
this._cachedTree = tree; | ||
return tree; | ||
}; | ||
this.getViewByPath = (path) => { | ||
const tree = this.getNodeViewTree(); | ||
return path.reduce((curr, id) => { | ||
if (!curr) { | ||
return null; | ||
} | ||
const child = curr.children.find(x => x.id === id); | ||
if (!child) { | ||
return null; | ||
} | ||
return child; | ||
}, tree); | ||
}; | ||
this._observer = new MutationObserver(() => { | ||
this._cachedPath.clear(); | ||
this._cachedTree = null; | ||
}); | ||
} | ||
clear() { | ||
this.blockViewMap.clear(); | ||
this.widgetViewMap.clear(); | ||
register(type, spec) { | ||
this.viewSpec.set(type, spec); | ||
} | ||
mount() { | ||
this._observer.observe(this.blockStore.root, observeOptions); | ||
} | ||
unmount() { | ||
this._cachedPath.clear(); | ||
this._cachedTree = null; | ||
this._observer.disconnect(); | ||
this.viewSpec.clear(); | ||
} | ||
} | ||
//# sourceMappingURL=view-store.js.map |
{ | ||
"name": "@blocksuite/block-std", | ||
"version": "0.0.0-20230801164049-94862d4d-nightly", | ||
"version": "0.0.0-20230802170305-bdf398b9-nightly", | ||
"description": "Std for blocksuite blocks", | ||
@@ -12,10 +12,10 @@ "main": "dist/index.js", | ||
"peerDependencies": { | ||
"@blocksuite/store": "0.0.0-20230801164049-94862d4d-nightly" | ||
"@blocksuite/store": "0.0.0-20230802170305-bdf398b9-nightly" | ||
}, | ||
"dependencies": { | ||
"w3c-keyname": "^2.2.8", | ||
"@blocksuite/global": "0.0.0-20230801164049-94862d4d-nightly" | ||
"@blocksuite/global": "0.0.0-20230802170305-bdf398b9-nightly" | ||
}, | ||
"devDependencies": { | ||
"@blocksuite/store": "0.0.0-20230801164049-94862d4d-nightly" | ||
"@blocksuite/store": "0.0.0-20230802170305-bdf398b9-nightly" | ||
}, | ||
@@ -22,0 +22,0 @@ "exports": { |
@@ -0,1 +1,4 @@ | ||
import { assertExists } from '@blocksuite/global/utils'; | ||
import type { BlockElement } from '@blocksuite/lit'; | ||
import { UIEventState, UIEventStateContext } from '../base.js'; | ||
@@ -83,8 +86,6 @@ import type { | ||
private _buildEventScopeByNativeRange(name: EventName, range: Range) { | ||
const blocks = this._findBlockElement(range); | ||
const blocks = this._findBlockElement(range) as BlockElement[]; | ||
const paths = blocks | ||
.map(blockView => { | ||
return this._dispatcher.blockStore.viewStore.blockViewMap.getPath( | ||
blockView | ||
); | ||
return blockView.path; | ||
}) | ||
@@ -114,5 +115,7 @@ .filter((path): path is string[] => !!path); | ||
const ancestor = range.commonAncestorContainer; | ||
const getBlockView = this._dispatcher.blockStore.config.getBlockViewByNode; | ||
const getBlockView = this._dispatcher.blockStore.viewStore.getNodeView; | ||
if (ancestor.nodeType === Node.TEXT_NODE) { | ||
return [getBlockView(ancestor)]; | ||
const view = getBlockView(ancestor)?.view; | ||
assertExists(view); | ||
return [view]; | ||
} | ||
@@ -152,3 +155,3 @@ const nodes = new Set<Node>(); | ||
nodes.forEach(node => { | ||
const blockView = getBlockView(node); | ||
const blockView = getBlockView(node)?.view; | ||
if (!blockView) { | ||
@@ -155,0 +158,0 @@ return; |
@@ -167,3 +167,3 @@ import { DisposableGroup } from '@blocksuite/global/utils'; | ||
scope.paths.forEach(path => { | ||
const instance = this.blockStore.viewStore.blockViewMap.get(path); | ||
const instance = this.blockStore.viewStore.getViewByPath(path); | ||
if (instance) { | ||
@@ -213,4 +213,3 @@ targetMap.set(path, instance); | ||
const blockView = this.blockStore.config.getBlockViewByNode(target); | ||
const path = this.blockStore.viewStore.blockViewMap.getPath(blockView); | ||
const path = this.blockStore.viewStore.getNodeView(target)?.path; | ||
if (!path) return; | ||
@@ -217,0 +216,0 @@ |
@@ -12,14 +12,9 @@ import type { Page, Workspace } from '@blocksuite/store'; | ||
export interface BlockStoreOptions<BlockViewType = unknown> { | ||
export interface BlockStoreOptions { | ||
root: HTMLElement; | ||
workspace: Workspace; | ||
page: Page; | ||
config: BlockStoreConfig<BlockViewType>; | ||
} | ||
export class BlockStore< | ||
ComponentType = unknown, | ||
BlockViewType = unknown, | ||
WidgetViewType = unknown | ||
> { | ||
export class BlockStore<ComponentType = unknown, NodeView = unknown> { | ||
page: Page; | ||
@@ -31,14 +26,12 @@ readonly workspace: Workspace; | ||
readonly specStore: SpecStore<ComponentType>; | ||
readonly viewStore: ViewStore<BlockViewType, WidgetViewType>; | ||
readonly config: BlockStoreConfig<BlockViewType>; | ||
readonly viewStore: ViewStore<NodeView>; | ||
constructor(options: BlockStoreOptions<BlockViewType>) { | ||
constructor(options: BlockStoreOptions) { | ||
this.root = options.root; | ||
this.workspace = options.workspace; | ||
this.page = options.page; | ||
this.config = options.config; | ||
this.uiEventDispatcher = new UIEventDispatcher(this); | ||
this.selectionManager = new SelectionManager(this); | ||
this.specStore = new SpecStore<ComponentType>(this); | ||
this.viewStore = new ViewStore<BlockViewType, WidgetViewType>(); | ||
this.viewStore = new ViewStore<NodeView>(this); | ||
} | ||
@@ -49,2 +42,3 @@ | ||
this.uiEventDispatcher.mount(); | ||
this.viewStore.mount(); | ||
} | ||
@@ -55,5 +49,5 @@ | ||
this.selectionManager.unmount(); | ||
this.viewStore.clear(); | ||
this.viewStore.unmount(); | ||
this.specStore.dispose(); | ||
} | ||
} |
@@ -1,11 +0,159 @@ | ||
import { PathMap } from './path-map.js'; | ||
import { assertExists } from '@blocksuite/global/utils'; | ||
export class ViewStore<BlockView = unknown, WidgetView = unknown> { | ||
readonly blockViewMap = new PathMap<BlockView>(); | ||
readonly widgetViewMap = new PathMap<WidgetView>(); | ||
import type { BlockStore } from './block-store.js'; | ||
clear() { | ||
this.blockViewMap.clear(); | ||
this.widgetViewMap.clear(); | ||
export type NodeView<T = unknown> = { | ||
id: string; | ||
path: string[]; | ||
view: T; | ||
}; | ||
export type NodeViewLeaf<T> = NodeView<T> & { | ||
type: BlockSuiteViewType; | ||
}; | ||
export type NodeViewTree<T> = NodeViewLeaf<T> & { | ||
children: NodeViewTree<T>[]; | ||
}; | ||
export interface BlockSuiteViewSpec<T = unknown> { | ||
fromDOM: (node: Node) => null | NodeView<T>; | ||
toDOM: (nodeView: NodeView<T>) => Element; | ||
getChildren: (node: Element) => Element[]; | ||
} | ||
const observeOptions = { | ||
childList: true, | ||
subtree: true, | ||
}; | ||
export class ViewStore<NodeViewType = unknown> { | ||
private _cachedTree: NodeViewTree<NodeViewType> | null = null; | ||
private _cachedPath: Map<Node, NodeViewLeaf<NodeViewType>[]> = new Map(); | ||
private _observer: MutationObserver; | ||
readonly viewSpec = new Map<BlockSuiteViewType, BlockSuiteViewValue>(); | ||
constructor(public blockStore: BlockStore) { | ||
this._observer = new MutationObserver(() => { | ||
this._cachedPath.clear(); | ||
this._cachedTree = null; | ||
}); | ||
} | ||
register<T extends BlockSuiteViewType>(type: T, spec: BlockSuiteView[T]) { | ||
this.viewSpec.set(type, spec); | ||
} | ||
getNodeView = (node: Node): NodeViewLeaf<NodeViewType> | null => { | ||
for (const [type, spec] of this.viewSpec.entries()) { | ||
const view = spec.fromDOM(node); | ||
if (view) { | ||
return { | ||
type, | ||
...view, | ||
} as NodeViewLeaf<NodeViewType>; | ||
} | ||
} | ||
return null; | ||
}; | ||
calculatePath = (node: Node) => { | ||
const path = this.calculateNodeViewPath(node); | ||
return path.map(x => x.id); | ||
}; | ||
calculateNodeViewPath = (node: Node) => { | ||
if (this._cachedPath.has(node)) { | ||
return this._cachedPath.get(node) as NodeViewLeaf<NodeViewType>[]; | ||
} | ||
const root = this.blockStore.root; | ||
const iterate = ( | ||
node: Node | null, | ||
path: Array<NodeViewLeaf<NodeViewType>> | ||
): Array<NodeViewLeaf<NodeViewType>> => { | ||
if (!node || node === root) return path; | ||
const nodeView = this.getNodeView(node); | ||
if (!nodeView) { | ||
return path; | ||
} | ||
const spec = this.viewSpec.get(nodeView.type); | ||
assertExists(spec); | ||
const next = spec.toDOM(nodeView as never).parentElement; | ||
if (!next) { | ||
return path; | ||
} | ||
return iterate(next, path.concat(nodeView)); | ||
}; | ||
const path = iterate(node, []).reverse(); | ||
this._cachedPath.set(node, path); | ||
return path; | ||
}; | ||
getNodeViewTree = (): NodeViewTree<NodeViewType> => { | ||
if (this._cachedTree) { | ||
return this._cachedTree; | ||
} | ||
const iterate = (node: Node): NodeViewTree<NodeViewType> => { | ||
const nodeView = this.getNodeView(node); | ||
if (!nodeView) { | ||
throw new Error('nodeView not found'); | ||
} | ||
const spec = this.viewSpec.get(nodeView.type); | ||
assertExists(spec); | ||
const children = spec | ||
.getChildren(spec.toDOM(nodeView as never)) | ||
.map(child => iterate(child)); | ||
return { | ||
...nodeView, | ||
children, | ||
}; | ||
}; | ||
const firstBlock = this.blockStore.root.firstElementChild; | ||
assertExists(firstBlock); | ||
const tree = { | ||
id: '__root__', | ||
path: [], | ||
children: [iterate(firstBlock)], | ||
} as Partial<NodeViewTree<NodeViewType>> as NodeViewTree<NodeViewType>; | ||
this._cachedTree = tree; | ||
return tree; | ||
}; | ||
getViewByPath = (path: string[]) => { | ||
const tree = this.getNodeViewTree(); | ||
return path.reduce((curr: NodeViewTree<NodeViewType> | null, id) => { | ||
if (!curr) { | ||
return null; | ||
} | ||
const child = curr.children.find(x => x.id === id); | ||
if (!child) { | ||
return null; | ||
} | ||
return child; | ||
}, tree) as NodeViewLeaf<NodeViewType> | null; | ||
}; | ||
mount() { | ||
this._observer.observe(this.blockStore.root, observeOptions); | ||
} | ||
unmount() { | ||
this._cachedPath.clear(); | ||
this._cachedTree = null; | ||
this._observer.disconnect(); | ||
this.viewSpec.clear(); | ||
} | ||
} | ||
declare global { | ||
// eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
interface BlockSuiteView {} | ||
type BlockSuiteViewType = string & keyof BlockSuiteView; | ||
type BlockSuiteViewValue<T extends BlockSuiteViewType = BlockSuiteViewType> = | ||
BlockSuiteView[T]; | ||
} |
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
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
391749
3023
+ Added@blocksuite/global@0.0.0-20230802170305-bdf398b9-nightly(transitive)
+ Added@blocksuite/store@0.0.0-20230802170305-bdf398b9-nightly(transitive)
+ Added@blocksuite/virgo@0.0.0-20230802170305-bdf398b9-nightly(transitive)
+ Addedintl-segmenter-polyfill-rs@0.1.7(transitive)
- Removed@blocksuite/global@0.0.0-20230801164049-94862d4d-nightly(transitive)
- Removed@blocksuite/store@0.0.0-20230801164049-94862d4d-nightly(transitive)
- Removed@blocksuite/virgo@0.0.0-20230801164049-94862d4d-nightly(transitive)
Updated@blocksuite/global@0.0.0-20230802170305-bdf398b9-nightly