You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
3.3 KiB
138 lines
3.3 KiB
import type { ComputedRef, InjectionKey, UnwrapNestedRefs } from 'vue'
|
|
import { computed, inject, provide } from 'vue'
|
|
import type { Block, Category, Module, Page } from './types'
|
|
import { valueOf } from './utils'
|
|
|
|
/** 画布配置 */
|
|
export interface CanvasConfig {
|
|
/** 画布是否聚焦 */
|
|
focused: boolean
|
|
/** 画布缩放比例 */
|
|
scale: number
|
|
}
|
|
|
|
export interface PageConfig extends Omit<Page, 'body'> {}
|
|
|
|
export type ConfiguratorType =
|
|
| 'page'
|
|
| 'block'
|
|
| 'view'
|
|
|
|
export interface Exported {
|
|
attrs: PageConfig
|
|
data: Record<string, Record<string, unknown>>
|
|
}
|
|
|
|
export interface EngineContext {
|
|
/** 目标 */
|
|
target?: 'app' | 'routine'
|
|
/** 当前选中的模板 */
|
|
activeBlockId?: string
|
|
/** 当前选中的可编辑组件 */
|
|
activeViewId?: string
|
|
/** 鼠标进入的可编辑组件 */
|
|
hoverViewId?: string
|
|
/** 正在被拖拽的模板 */
|
|
draggingViewId?: string
|
|
/** 当前配置 */
|
|
configurator?: ConfiguratorType
|
|
/** 页面配置 */
|
|
page: PageConfig
|
|
/** 画布配置 */
|
|
canvas: CanvasConfig
|
|
/** 可以分类 */
|
|
categories: Category[]
|
|
/** 布局视图列表 */
|
|
blocks: Block[]
|
|
/** 内部唯一标识 */
|
|
nextId: number
|
|
/** 数据源 */
|
|
sources: Record<string, Record<string, unknown>>
|
|
/** 到处数据 */
|
|
export: () => Exported
|
|
}
|
|
|
|
export const contextKey: InjectionKey<UnwrapNestedRefs<EngineContext>> = Symbol.for('ddd:engine')
|
|
export const parentViewIdKey: InjectionKey<string> = Symbol.for('ddd:view:parent:id')
|
|
const blockIdKey: InjectionKey<string> = Symbol.for('ddd:block:id')
|
|
|
|
export function useContext(): UnwrapNestedRefs<EngineContext> {
|
|
const config = inject(contextKey)
|
|
if (config == null)
|
|
throw new Error('no config found')
|
|
|
|
return config
|
|
}
|
|
|
|
export function useParentViewId(): string | undefined {
|
|
return inject(parentViewIdKey)
|
|
}
|
|
|
|
export function provideParentViewId(id: string | undefined): void {
|
|
if (id)
|
|
provide(parentViewIdKey, id)
|
|
}
|
|
|
|
export function useBlockId(): string | undefined {
|
|
return inject(blockIdKey)
|
|
}
|
|
|
|
export function provideBlockId(id: string): void {
|
|
provide(blockIdKey, id)
|
|
}
|
|
|
|
export function useModule() {
|
|
const ctx = useContext()
|
|
return computed((): Module | undefined => {
|
|
for (const block of ctx.blocks) {
|
|
if (block.vid !== ctx.activeBlockId)
|
|
continue
|
|
|
|
for (const category of ctx.categories) {
|
|
for (const module of category.modules) {
|
|
if (module.mid === block.mid)
|
|
return module
|
|
}
|
|
}
|
|
break
|
|
}
|
|
return undefined
|
|
})
|
|
}
|
|
|
|
export function useScale() {
|
|
const ctx = useContext()
|
|
|
|
const minScaleValue = 0.6
|
|
const maxScaleValue = 3.0
|
|
const scaleStep = 0.2
|
|
const setScale = (delta: number): void => {
|
|
ctx.canvas.scale = Math.max(
|
|
Math.min(
|
|
ctx.canvas.scale + scaleStep * delta,
|
|
maxScaleValue,
|
|
),
|
|
minScaleValue,
|
|
)
|
|
}
|
|
|
|
return {
|
|
min: minScaleValue,
|
|
max: maxScaleValue,
|
|
step: scaleStep,
|
|
incr: () => setScale(1),
|
|
decr: () => setScale(-1),
|
|
}
|
|
}
|
|
|
|
export function useSource<T = unknown>(source: string | undefined, fallback?: T): ComputedRef<T | undefined> {
|
|
const ctx = useContext()
|
|
const blockId = useBlockId()
|
|
return computed<T | undefined>(() => {
|
|
if (!blockId)
|
|
throw new Error('without block')
|
|
if (!source)
|
|
return fallback
|
|
return valueOf(ctx.sources[blockId], source) ?? fallback
|
|
})
|
|
}
|
|
|