@ease-forge/designer 1.0.29 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DesignCanvas.vue.d.ts +16 -0
- package/dist/components/DesignCanvas.vue.d.ts.map +1 -0
- package/dist/components/DragGhost.vue.d.ts +9 -0
- package/dist/components/DragGhost.vue.d.ts.map +1 -0
- package/dist/components/Workbench.vue.d.ts +14 -0
- package/dist/components/Workbench.vue.d.ts.map +1 -0
- package/dist/components/panels/MaterialPanel.vue.d.ts +14 -0
- package/dist/components/panels/MaterialPanel.vue.d.ts.map +1 -0
- package/dist/components/panels/OutlinePanel.vue.d.ts +9 -0
- package/dist/components/panels/OutlinePanel.vue.d.ts.map +1 -0
- package/dist/components/panels/SetterAdvancedPanel.vue.d.ts +15 -0
- package/dist/components/panels/SetterAdvancedPanel.vue.d.ts.map +1 -0
- package/dist/components/panels/SetterEventPanel.vue.d.ts +15 -0
- package/dist/components/panels/SetterEventPanel.vue.d.ts.map +1 -0
- package/dist/components/panels/SetterPropsGroup.vue.d.ts +12 -0
- package/dist/components/panels/SetterPropsGroup.vue.d.ts.map +1 -0
- package/dist/components/panels/SetterPropsPanel.vue.d.ts +12 -0
- package/dist/components/panels/SetterPropsPanel.vue.d.ts.map +1 -0
- package/dist/components/panels/SetterStyleGroup.vue.d.ts +12 -0
- package/dist/components/panels/SetterStyleGroup.vue.d.ts.map +1 -0
- package/dist/components/panels/SetterStylePanel.vue.d.ts +12 -0
- package/dist/components/panels/SetterStylePanel.vue.d.ts.map +1 -0
- package/dist/components/panels/style/StyleGroups.d.ts +35 -0
- package/dist/components/panels/style/StyleGroups.d.ts.map +1 -0
- package/dist/components/setter/BoolSetter.vue.d.ts +5 -0
- package/dist/components/setter/BoolSetter.vue.d.ts.map +1 -0
- package/dist/components/setter/ColorSetter.vue.d.ts +5 -0
- package/dist/components/setter/ColorSetter.vue.d.ts.map +1 -0
- package/dist/components/setter/DateSetter.vue.d.ts +5 -0
- package/dist/components/setter/DateSetter.vue.d.ts.map +1 -0
- package/dist/components/setter/EditorSetter.vue.d.ts +5 -0
- package/dist/components/setter/EditorSetter.vue.d.ts.map +1 -0
- package/dist/components/setter/NumberSetter.vue.d.ts +5 -0
- package/dist/components/setter/NumberSetter.vue.d.ts.map +1 -0
- package/dist/components/setter/SelectSetter.vue.d.ts +5 -0
- package/dist/components/setter/SelectSetter.vue.d.ts.map +1 -0
- package/dist/components/setter/StringSetter.vue.d.ts +5 -0
- package/dist/components/setter/StringSetter.vue.d.ts.map +1 -0
- package/dist/components/setter/TimeSetter.vue.d.ts +5 -0
- package/dist/components/setter/TimeSetter.vue.d.ts.map +1 -0
- package/dist/core/DesignerDriver.d.ts +36 -0
- package/dist/core/DesignerDriver.d.ts.map +1 -0
- package/dist/core/DesignerEffect.d.ts +30 -0
- package/dist/core/DesignerEffect.d.ts.map +1 -0
- package/dist/core/DesignerEngine.d.ts +95 -0
- package/dist/core/DesignerEngine.d.ts.map +1 -0
- package/dist/core/DesignerModule.d.ts +28 -0
- package/dist/core/DesignerModule.d.ts.map +1 -0
- package/dist/core/EventBus.d.ts +37 -0
- package/dist/core/EventBus.d.ts.map +1 -0
- package/dist/drivers/DragDropDriver.d.ts +48 -0
- package/dist/drivers/DragDropDriver.d.ts.map +1 -0
- package/dist/drivers/KeyboardDriver.d.ts +18 -0
- package/dist/drivers/KeyboardDriver.d.ts.map +1 -0
- package/dist/drivers/MouseClickDriver.d.ts +14 -0
- package/dist/drivers/MouseClickDriver.d.ts.map +1 -0
- package/dist/drivers/MouseMoveDriver.d.ts +14 -0
- package/dist/drivers/MouseMoveDriver.d.ts.map +1 -0
- package/dist/ease-forge-designer.cjs.js +2 -0
- package/dist/ease-forge-designer.cjs.js.map +1 -0
- package/dist/ease-forge-designer.cjs.prod.js +1 -0
- package/dist/ease-forge-designer.css +2 -0
- package/dist/ease-forge-designer.esm.js +3434 -0
- package/dist/ease-forge-designer.esm.js.map +1 -0
- package/dist/ease-forge-designer.esm.prod.js +3432 -0
- package/dist/effects/AuxToolEffect.d.ts +52 -0
- package/dist/effects/AuxToolEffect.d.ts.map +1 -0
- package/dist/effects/CursorEffect.d.ts +29 -0
- package/dist/effects/CursorEffect.d.ts.map +1 -0
- package/dist/effects/DraggingEffect.d.ts +17 -0
- package/dist/effects/DraggingEffect.d.ts.map +1 -0
- package/dist/events/DesignerEvent.d.ts +26 -0
- package/dist/events/DesignerEvent.d.ts.map +1 -0
- package/dist/events/cursor/AbstractCursorEvent.d.ts +22 -0
- package/dist/events/cursor/AbstractCursorEvent.d.ts.map +1 -0
- package/dist/events/cursor/DragMoveEvent.d.ts +10 -0
- package/dist/events/cursor/DragMoveEvent.d.ts.map +1 -0
- package/dist/events/cursor/DragStartEvent.d.ts +17 -0
- package/dist/events/cursor/DragStartEvent.d.ts.map +1 -0
- package/dist/events/cursor/DragStopEvent.d.ts +10 -0
- package/dist/events/cursor/DragStopEvent.d.ts.map +1 -0
- package/dist/events/cursor/MouseClickEvent.d.ts +10 -0
- package/dist/events/cursor/MouseClickEvent.d.ts.map +1 -0
- package/dist/events/cursor/MouseDoubleClickEvent.d.ts +10 -0
- package/dist/events/cursor/MouseDoubleClickEvent.d.ts.map +1 -0
- package/dist/events/cursor/MouseMoveEvent.d.ts +10 -0
- package/dist/events/cursor/MouseMoveEvent.d.ts.map +1 -0
- package/dist/events/designer/CommandEvent.d.ts +20 -0
- package/dist/events/designer/CommandEvent.d.ts.map +1 -0
- package/dist/events/designer/DragDropEvent.d.ts +29 -0
- package/dist/events/designer/DragDropEvent.d.ts.map +1 -0
- package/dist/events/engine/EngineMountEvent.d.ts +21 -0
- package/dist/events/engine/EngineMountEvent.d.ts.map +1 -0
- package/dist/events/engine/EngineUnmountEvent.d.ts +16 -0
- package/dist/events/engine/EngineUnmountEvent.d.ts.map +1 -0
- package/dist/events/keyboard/ShortcutKeyEvent.d.ts +32 -0
- package/dist/events/keyboard/ShortcutKeyEvent.d.ts.map +1 -0
- package/dist/history/Command.d.ts +21 -0
- package/dist/history/Command.d.ts.map +1 -0
- package/dist/history/CommandStack.d.ts +46 -0
- package/dist/history/CommandStack.d.ts.map +1 -0
- package/dist/index.d.ts +89 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/models/Cursor.d.ts +44 -0
- package/dist/models/Cursor.d.ts.map +1 -0
- package/dist/models/DesignerState.d.ts +76 -0
- package/dist/models/DesignerState.d.ts.map +1 -0
- package/dist/models/DraggingCmpMetas.d.ts +41 -0
- package/dist/models/DraggingCmpMetas.d.ts.map +1 -0
- package/dist/models/HoverDashed.d.ts +41 -0
- package/dist/models/HoverDashed.d.ts.map +1 -0
- package/dist/models/Insertion.d.ts +57 -0
- package/dist/models/Insertion.d.ts.map +1 -0
- package/dist/models/Selection.d.ts +8 -0
- package/dist/models/Selection.d.ts.map +1 -0
- package/dist/models/SetterShareState.d.ts +32 -0
- package/dist/models/SetterShareState.d.ts.map +1 -0
- package/dist/operations/NodeOperationEffect.d.ts +25 -0
- package/dist/operations/NodeOperationEffect.d.ts.map +1 -0
- package/dist/operations/NodePosition.d.ts +55 -0
- package/dist/operations/NodePosition.d.ts.map +1 -0
- package/dist/operations/NodeSerialize.d.ts +8 -0
- package/dist/operations/NodeSerialize.d.ts.map +1 -0
- package/dist/operations/commands/AddNodesCommand.d.ts +34 -0
- package/dist/operations/commands/AddNodesCommand.d.ts.map +1 -0
- package/dist/operations/commands/MoveNodesCommand.d.ts +42 -0
- package/dist/operations/commands/MoveNodesCommand.d.ts.map +1 -0
- package/dist/operations/commands/RemoveNodesCommand.d.ts +50 -0
- package/dist/operations/commands/RemoveNodesCommand.d.ts.map +1 -0
- package/dist/operations/commands/UpdateListenersCommand.d.ts +42 -0
- package/dist/operations/commands/UpdateListenersCommand.d.ts.map +1 -0
- package/dist/operations/commands/UpdatePropsCommand.d.ts +53 -0
- package/dist/operations/commands/UpdatePropsCommand.d.ts.map +1 -0
- package/dist/register/RegisterSetter.d.ts +8 -0
- package/dist/register/RegisterSetter.d.ts.map +1 -0
- package/dist/types/Designer.d.ts +153 -0
- package/dist/types/Designer.d.ts.map +1 -0
- package/dist/utils/ComponentMetaUtils.d.ts +13 -0
- package/dist/utils/ComponentMetaUtils.d.ts.map +1 -0
- package/dist/utils/DesignerUtils.d.ts +11 -0
- package/dist/utils/DesignerUtils.d.ts.map +1 -0
- package/dist/utils/PositionCalc.d.ts +27 -0
- package/dist/utils/PositionCalc.d.ts.map +1 -0
- package/dist/utils/SetterUtils.d.ts +59 -0
- package/dist/utils/SetterUtils.d.ts.map +1 -0
- package/dist/utils/StyleUtils.d.ts +34 -0
- package/dist/utils/StyleUtils.d.ts.map +1 -0
- package/package.json +10 -4
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ease-forge-designer.cjs.js","names":["$attrs","$attrs","$attrs","$attrs","$attrs","$attrs","$attrs"],"sources":["../src/types/Designer.ts","../src/events/DesignerEvent.ts","../src/events/engine/EngineMountEvent.ts","../src/events/engine/EngineUnmountEvent.ts","../src/events/cursor/AbstractCursorEvent.ts","../src/events/cursor/DragStartEvent.ts","../src/events/cursor/DragMoveEvent.ts","../src/events/cursor/DragStopEvent.ts","../src/events/cursor/MouseClickEvent.ts","../src/events/cursor/MouseDoubleClickEvent.ts","../src/events/cursor/MouseMoveEvent.ts","../src/events/keyboard/ShortcutKeyEvent.ts","../src/events/designer/DragDropEvent.ts","../src/events/designer/CommandEvent.ts","../src/core/EventBus.ts","../src/core/DesignerModule.ts","../src/core/DesignerDriver.ts","../src/core/DesignerEffect.ts","../src/utils/PositionCalc.ts","../src/models/Cursor.ts","../src/models/DraggingCmpMetas.ts","../src/models/Insertion.ts","../src/utils/ComponentMetaUtils.ts","../src/models/HoverDashed.ts","../src/models/Selection.ts","../src/history/CommandStack.ts","../src/models/SetterShareState.ts","../src/models/DesignerState.ts","../src/core/DesignerEngine.ts","../src/drivers/DragDropDriver.ts","../src/drivers/KeyboardDriver.ts","../src/drivers/MouseClickDriver.ts","../src/drivers/MouseMoveDriver.ts","../src/effects/CursorEffect.ts","../src/effects/DraggingEffect.ts","../src/utils/DesignerUtils.ts","../src/effects/AuxToolEffect.ts","../src/operations/NodePosition.ts","../src/operations/commands/AddNodesCommand.ts","../src/operations/commands/MoveNodesCommand.ts","../src/operations/NodeSerialize.ts","../src/operations/commands/RemoveNodesCommand.ts","../src/operations/NodeOperationEffect.ts","../src/operations/commands/UpdatePropsCommand.ts","../src/operations/commands/UpdateListenersCommand.ts","../src/components/DesignCanvas.vue","../src/components/DesignCanvas.vue","../src/components/DragGhost.vue","../src/components/DragGhost.vue","../src/components/panels/SetterPropsGroup.vue","../src/components/panels/SetterPropsGroup.vue","../src/components/panels/SetterPropsPanel.vue","../src/components/panels/SetterPropsPanel.vue","../src/components/panels/style/StyleGroups.ts","../src/utils/StyleUtils.ts","../src/components/panels/SetterStyleGroup.vue","../src/components/panels/SetterStyleGroup.vue","../src/components/panels/SetterStylePanel.vue","../src/components/panels/SetterStylePanel.vue","../src/components/panels/SetterEventPanel.vue","../src/components/panels/SetterEventPanel.vue","../src/components/panels/SetterAdvancedPanel.vue","../src/components/panels/SetterAdvancedPanel.vue","../src/components/panels/MaterialPanel.vue","../src/components/panels/MaterialPanel.vue","../src/components/panels/OutlinePanel.vue","../src/components/panels/OutlinePanel.vue","../src/components/Workbench.vue","../src/components/Workbench.vue","../src/utils/SetterUtils.ts","../src/components/setter/StringSetter.vue","../src/components/setter/StringSetter.vue","../src/components/setter/NumberSetter.vue","../src/components/setter/NumberSetter.vue","../src/components/setter/BoolSetter.vue","../src/components/setter/BoolSetter.vue","../src/components/setter/SelectSetter.vue","../src/components/setter/SelectSetter.vue","../src/components/setter/ColorSetter.vue","../src/components/setter/ColorSetter.vue","../src/components/setter/DateSetter.vue","../src/components/setter/DateSetter.vue","../src/components/setter/TimeSetter.vue","../src/components/setter/TimeSetter.vue","../src/components/setter/EditorSetter.vue","../src/components/setter/EditorSetter.vue","../src/register/RegisterSetter.ts","../src/index.ts"],"sourcesContent":["/** 监听事件的DOM元素(含Window) */\ntype EventContainer = HTMLElement | Document;\n\n/** 光标拖拽状态 */\nenum CursorStatus {\n /** 常规 */\n Normal = 'normal',\n /** 开始拖拽 */\n DragStart = 'drag_start',\n /** 拖拽中 */\n Dragging = 'dragging',\n /** 拖拽结束 */\n DragStop = 'drag_stop',\n}\n\n/** 光标位置 */\ninterface CursorPosition {\n /** 光标位置相对于浏览器窗口左上角的水平坐标(单位像素) */\n clientX: number;\n /** 光标位置相对于浏览器窗口左上角的垂直坐标(单位像素) */\n clientY: number;\n /** 光标位置与文档左侧边缘的距离,包括文档不可见的部分(单位像素) */\n pageX: number;\n /** 光标位置与文档上侧边缘的距离,包括文档不可见的部分(单位像素) */\n pageY: number;\n /** 光标位置相对于最外层(考虑iframe存在的情况)浏览器窗口左上角的水平坐标(单位像素) */\n topClientX: number;\n /** 光标位置相对于最外层(考虑iframe存在的情况)浏览器窗口左上角的垂直坐标(单位像素) */\n topClientY: number;\n /** 光标位置与最外层(考虑iframe存在的情况)文档左侧边缘的距离,包括文档不可见的部分(单位像素) */\n topPageX: number;\n /** 光标位置与最外层(考虑iframe存在的情况)文档上侧边缘的距离,包括文档不可见的部分(单位像素) */\n topPageY: number;\n}\n\n/** 设计器光标模式 */\nenum DesignerCursorMode {\n /** 拖拽 */\n DragDrop = 'dragdrop',\n /** 自由选择 */\n Selection = 'selection',\n}\n\n/** 设计器布局类型 */\nenum DesignerLayout {\n /** PC端 */\n PC = 'pc',\n /** 移动端 */\n Mobile = 'mobile',\n}\n\n/** 设计器叶签类型 */\nenum DesignerTab {\n /** 设计器 */\n Designer = 'Designer',\n /** 源码 */\n Code = 'Code',\n /** 预览 */\n Preview = 'Preview',\n}\n\n/**\n * html元素矩形。\n * 视口左上角距离,不随页面滚动而改变。\n */\ninterface ElementRect {\n /** \"html元素左上角\"离\"视口左上角\"垂直方向的距离(像素) */\n top: number;\n /** \"html元素左上角\"离\"视口左上角\"水平方向的距离(像素) */\n left: number;\n /** html元素宽(像素) */\n width: number;\n /** html元素高(像素) */\n height: number;\n}\n\n/** 辅助工具的位置 */\ninterface AuxToolPosition extends ElementRect {\n /** 是否在容器顶部 */\n isTop: boolean;\n /** 是否在容器底部 */\n isBottom: boolean;\n}\n\n/** 上下左右四个方向 */\nenum Direction {\n top = \"top\",\n bottom = \"bottom\",\n left = \"left\",\n right = \"right\",\n}\n\n/** 四个角的方向 */\nenum PointDirection {\n leftTop = \"leftTop\",\n leftBottom = \"leftBottom\",\n rightTop = \"rightTop\",\n rightBottom = \"rightBottom\",\n}\n\n/** 渲染节点与光标的距离信息 */\ninterface NodeToCursorDistance {\n /** 渲染节点的dom */\n element: Element;\n /** html元素宽(像素) */\n width: number;\n /** html元素高(像素) */\n height: number;\n /** 光标与渲染节点上边框的距离 */\n top: number;\n /** 光标与渲染节点下边框的距离 */\n bottom: number;\n /** 光标与渲染节点左边框的距离 */\n left: number;\n /** 光标与渲染节点右边框的距离 */\n right: number;\n /** 光标是否在渲染节点的在垂直区域内 */\n vInside: boolean;\n /** 光标是否在渲染节点的在水平区域内 */\n hInside: boolean;\n /** 光标是否在渲染节点里面 */\n bothInside: boolean;\n /** 最近的边 */\n direction: Direction;\n /** 光标与渲染节点左上角的距离 */\n leftTop: number;\n /** 光标与渲染节点左下角的距离 */\n leftBottom: number;\n /** 光标与渲染节点右上角的距离 */\n rightTop: number;\n /** 光标与渲染节点右下角的距离 */\n rightBottom: number;\n /** 最近的点 */\n point: PointDirection;\n /** 渲染节点是否是行级块(独占一行) */\n rowBlock: boolean;\n /** 渲染节点是否是内联块(独占一行) */\n inlineBlock: boolean;\n}\n\n/**\n * 设计器插入组件的位置信息\n */\ninterface InsertionData {\n /** 渲染节点与光标的距离信息 */\n distance: NodeToCursorDistance;\n /** 插入区域位置 */\n position: AuxToolPosition;\n /** 容器组件节点id(值是:RuntimeNode.id) */\n containerId: string;\n /** 插入容器节点的插槽名称(子节点是一种特殊的插槽,名为:default) */\n slotName: string;\n /** 离插入位置最近的组件节点id(值是:RuntimeNode.id) */\n nodeId: string;\n /** 当期 node 属于占位组件 */\n placeholder: boolean;\n /** 是否允许拖拽 */\n allowDrag: boolean;\n /** 是否在 nodeId 之前插入 */\n before: boolean;\n}\n\nexport type {\n EventContainer,\n CursorPosition,\n ElementRect,\n AuxToolPosition,\n NodeToCursorDistance,\n InsertionData,\n}\n\nexport {\n CursorStatus,\n DesignerCursorMode,\n DesignerLayout,\n DesignerTab,\n Direction,\n PointDirection,\n}\n","/**\n * 设计器事件构造函数(约束子类必须定义静态 eventType)\n */\ninterface DesignerEventConstructor<Event extends DesignerEvent = DesignerEvent> {\n /** 事件类型标识(必须全局唯一, 推荐 \"域:事件名\" 格式, 如 \"cursor:drag-start\") */\n readonly eventType: string;\n new(...args: any[]): Event;\n}\n\n/**\n * 设计器事件基类: 事件类型标识使用子类显式声明的静态 eventType 属性而非 constructor.name,\n * 代码压缩混淆后事件路由依然稳定\n */\nabstract class DesignerEvent<Data = any> {\n /** 事件类型标识(子类必须覆盖, 全局唯一) */\n static readonly eventType: string = \"\";\n /** 事件类型标识(实例侧, 构造时从当前子类的静态 eventType 获取) */\n readonly type: string;\n /** 事件数据 */\n data?: Data;\n /** 事件上下文 */\n context?: any;\n\n constructor(data?: Data, context?: any) {\n this.type = (this.constructor as DesignerEventConstructor).eventType;\n if (!this.type) {\n console.warn(`[DesignerEvent] 事件类 \"${this.constructor.name}\" 未定义静态 eventType 属性`);\n }\n if (data !== undefined) this.data = data;\n if (context !== undefined) this.context = context;\n }\n}\n\nexport type {\n DesignerEventConstructor,\n}\n\nexport {\n DesignerEvent,\n}\n","import { type EventContainer } from \"../../types/Designer\";\nimport { DesignerEvent } from \"../DesignerEvent\";\n\n/** 引擎挂载完成事件数据 */\ninterface EngineMountEventData {\n /** 引擎监听的事件容器 */\n container: EventContainer;\n /** 引擎关联的 window 对象 */\n window: Window;\n /** 挂载完成的时间戳(毫秒) */\n timestamp: number;\n}\n\n/**\n * 引擎挂载完成事件\n * 分发时机: DesignerEngine.mount() 中所有 driver 已 attach、effect 已订阅之后\n */\nclass EngineMountEvent extends DesignerEvent<EngineMountEventData> {\n static readonly eventType = \"engine:mount\";\n}\n\nexport type {\n EngineMountEventData,\n}\n\nexport {\n EngineMountEvent,\n}\n","import { DesignerEvent } from \"../DesignerEvent\";\n\n/** 引擎卸载完成事件数据 */\ninterface EngineUnmountEventData {\n /** 卸载完成的时间戳(毫秒) */\n timestamp: number;\n}\n\n/**\n * 引擎卸载事件\n * 分发时机: DesignerEngine.unmount() 清理订阅之前(保证订阅者仍能收到并做资源释放)\n */\nclass EngineUnmountEvent extends DesignerEvent<EngineUnmountEventData> {\n static readonly eventType = \"engine:unmount\";\n}\n\nexport type {\n EngineUnmountEventData,\n}\n\nexport {\n EngineUnmountEvent,\n}\n","import { globalThisPolyfill } from \"@ease-forge/shared\";\nimport type { CursorPosition } from \"../../types/Designer\";\nimport { DesignerEvent } from \"../DesignerEvent\";\n\n/**\n * 光标事件数据\n */\ninterface CursorEventData extends CursorPosition {\n /** 指向触发该事件的实际DOM元素(iframe 场景下可能是外层窗口的元素) */\n target: EventTarget;\n /** 生成事件的 document.defaultView 对象,在浏览器中,就是事件所在的 Window 对象(在 iframe 中很有用) */\n view: Window;\n\n [name: string]: any;\n}\n\n/**\n * 光标事件基类\n * 构造时完成坐标转换: 计算相对于\"最外层窗口\"的坐标(考虑 iframe 存在的场景)\n */\nabstract class AbstractCursorEvent<Data extends CursorEventData = CursorEventData> extends DesignerEvent<Data> {\n constructor(event: MouseEvent) {\n super();\n this.data = transformCoordinates(event) as Data;\n }\n}\n\n/**\n * 坐标转换(iframe 场景), 参考: https://juejin.cn/post/7063073539191996453\n */\nfunction transformCoordinates(event: MouseEvent): CursorEventData {\n const data: CursorEventData = {\n clientX: event.clientX,\n clientY: event.clientY,\n pageX: event.pageX,\n pageY: event.pageY,\n target: event.target!,\n view: event.view!,\n topClientX: event.clientX,\n topClientY: event.clientY,\n topPageX: event.pageX,\n topPageY: event.pageY,\n };\n // 当前脚本运行在 iframe 中时\n const { frameElement } = event.view || {};\n if (frameElement && data.view !== globalThisPolyfill) {\n // DOMRect 对象,是包含整个元素的最小矩形(包括 padding 和 border-width)\n const frameRect = frameElement.getBoundingClientRect();\n // frameRect.width 是元素在视口中的实际渲染宽度(包括任何CSS变换如缩放的影响)\n // frameElement.offsetWidth 属性则返回元素的内容区域(不包括边框和内填充)的实际CSS宽度\n // scale 描述了元素在渲染时被放大或缩小的程度\n const scale = frameRect.width / (frameElement as HTMLElement).offsetWidth;\n // iframe存在的情况计算出:以\"最外层窗口\"左上角为原点的坐标位置\n data.topClientX = data.clientX * scale + frameRect.x;\n data.topClientY = data.clientY * scale + frameRect.y;\n data.topPageX = data.pageX + frameRect.x - data.view.scrollX;\n data.topPageY = data.pageY + frameRect.y - data.view.scrollY;\n // 获取\"最外层窗口\"下的HTML元素\n const topElement = document.elementFromPoint(data.topPageX, data.topClientY);\n if (topElement !== frameElement) data.target = topElement!;\n }\n return data;\n}\n\nexport type {\n CursorEventData,\n}\n\nexport {\n AbstractCursorEvent,\n}\n","import type { ComponentMeta } from \"@ease-forge/runtime\";\nimport { AbstractCursorEvent, type CursorEventData } from \"./AbstractCursorEvent\";\n\n/** 开始拖动事件数据 */\nexport interface DragStartEventData extends CursorEventData {\n /** 正在拖拽的组件元信息集合 Map<nodeId, ComponentMeta>(拖拽物料时 nodeId 为 emptyNodeId) */\n componentMetas: Map<string, ComponentMeta>;\n}\n\n/**\n * 开始拖动事件\n * 产生者: DragDropDriver\n */\nclass DragStartEvent extends AbstractCursorEvent<DragStartEventData> {\n static readonly eventType = \"cursor:drag-start\";\n\n constructor(event: MouseEvent, componentMetas: Map<string, ComponentMeta>) {\n super(event);\n this.data!.componentMetas = componentMetas;\n }\n}\n\nexport {\n DragStartEvent,\n}\n","import { AbstractCursorEvent } from \"./AbstractCursorEvent\";\n\n/**\n * 拖动中事件\n * 产生者: DragDropDriver\n */\nclass DragMoveEvent extends AbstractCursorEvent {\n static readonly eventType = \"cursor:drag-move\";\n}\n\nexport {\n DragMoveEvent,\n}\n","import { AbstractCursorEvent } from \"./AbstractCursorEvent\";\n\n/**\n * 拖拽结束事件\n * 产生者: DragDropDriver\n */\nclass DragStopEvent extends AbstractCursorEvent {\n static readonly eventType = \"cursor:drag-stop\";\n}\n\nexport {\n DragStopEvent,\n}\n","import { AbstractCursorEvent } from \"./AbstractCursorEvent\";\n\n/**\n * 鼠标单击事件\n * 产生者: MouseClickDriver(仅在设计器画布区域内的点击)\n */\nclass MouseClickEvent extends AbstractCursorEvent {\n static readonly eventType = \"cursor:mouse-click\";\n}\n\nexport {\n MouseClickEvent,\n}\n","import { AbstractCursorEvent } from \"./AbstractCursorEvent\";\n\n/**\n * 鼠标双击事件\n * 产生者: MouseClickDriver(仅在设计器画布区域内的双击)\n */\nclass MouseDoubleClickEvent extends AbstractCursorEvent {\n static readonly eventType = \"cursor:mouse-double-click\";\n}\n\nexport {\n MouseDoubleClickEvent,\n}\n","import { AbstractCursorEvent } from \"./AbstractCursorEvent\";\n\n/**\n * 鼠标移动事件(rAF 节流)\n * 产生者: MouseMoveDriver\n */\nclass MouseMoveEvent extends AbstractCursorEvent {\n static readonly eventType = \"cursor:mouse-move\";\n}\n\nexport {\n MouseMoveEvent,\n}\n","import { DesignerEvent } from \"../DesignerEvent\";\n\n/** 键盘快捷键事件数据 */\ninterface ShortcutKeyEventData {\n /** 事件类型 */\n type: \"keydown\" | \"keyup\";\n /** 按键值(小写, 如 \"s\"、\"escape\"、\"arrowup\") */\n key: string;\n /** 是否按下 Ctrl 键 */\n ctrlKey: boolean;\n /** 是否按下 Shift 键 */\n shiftKey: boolean;\n /** 是否按下 Alt 键 */\n altKey: boolean;\n /** 是否按下 Meta 键(macOS 的 Command 键) */\n metaKey: boolean;\n /** 当前按下的物理按键集合(小写) */\n pressedKeys: ReadonlySet<string>;\n /** 原始键盘事件(订阅者可执行 preventDefault 等操作) */\n rawEvent: KeyboardEvent;\n}\n\n/**\n * 键盘快捷键事件: 只承载按键状态, 不绑定具体快捷键动作,\n * 订阅者根据 ctrlKey/key 等字段自行匹配并执行。\n * 产生者: KeyboardDriver\n */\nclass ShortcutKeyEvent extends DesignerEvent<ShortcutKeyEventData> {\n static readonly eventType = \"keyboard:shortcut\";\n\n constructor(rawEvent: KeyboardEvent, pressedKeys: ReadonlySet<string>) {\n super({\n type: rawEvent.type as \"keydown\" | \"keyup\",\n key: rawEvent.key.toLowerCase(),\n ctrlKey: rawEvent.ctrlKey,\n shiftKey: rawEvent.shiftKey,\n altKey: rawEvent.altKey,\n metaKey: rawEvent.metaKey,\n pressedKeys,\n rawEvent,\n });\n }\n}\n\nexport type {\n ShortcutKeyEventData,\n}\n\nexport {\n ShortcutKeyEvent,\n}\n","import type { ComponentMeta } from \"@ease-forge/runtime\";\nimport type { InsertionData } from \"../../types/Designer\";\nimport type { CursorEventData } from \"../cursor/AbstractCursorEvent\";\nimport { DesignerEvent } from \"../DesignerEvent\";\n\n/** 拖拽放下事件数据 */\ninterface DragDropEventData {\n /** 被拖拽的组件元信息集合(与 nodeIds 顺序一一对应) */\n componentMetas: Array<ComponentMeta>;\n /** 被拖拽的节点ID集合(拖拽物料时包含 emptyNodeId) */\n nodeIds: Array<string>;\n /** 拖拽结束时的光标数据 */\n cursor: CursorEventData;\n /**\n * 插入位置信息(容器节点/插槽/前后位置)\n * 由 DraggingEffect 在拖拽结束时计算填充; 拖出画布等无效场景为 undefined\n */\n insertion?: InsertionData;\n}\n\n/**\n * 拖拽放下事件\n * 拖拽结束(且存在拖拽物)时由 DraggingEffect 分发,\n * 由操作命令层(NodeOperationEffect)订阅并执行节点的移动/插入命令\n */\nclass DragDropEvent extends DesignerEvent<DragDropEventData> {\n static readonly eventType = \"designer:drag-drop\";\n}\n\nexport type {\n DragDropEventData,\n}\n\nexport {\n DragDropEvent,\n}\n","import { DesignerEvent } from \"../DesignerEvent\";\n\n/** 命令事件数据 */\ninterface CommandEventData {\n /** 命令操作类型 */\n type: \"execute\" | \"undo\" | \"redo\";\n /** 命令名称 */\n name: string;\n /** 命令所属的设计器页面路由路径 */\n path: string | undefined;\n}\n\n/**\n * 命令执行事件\n * 命令栈 execute/undo/redo 后分发, 历史面板/日志订阅此事件刷新\n */\nclass CommandEvent extends DesignerEvent<CommandEventData> {\n static readonly eventType = \"designer:command\";\n}\n\nexport type {\n CommandEventData,\n}\n\nexport {\n CommandEvent,\n}\n","import { DesignerEvent, type DesignerEventConstructor } from \"../events/DesignerEvent\";\n\n/** 事件订阅函数 */\ntype Subscriber<Event extends DesignerEvent = DesignerEvent> = (event: Event) => void;\n\n/** 带优先级的事件订阅函数 */\ninterface PrioritySubscriber {\n /** 优先级(越小越优先) */\n priority: number;\n /** 事件订阅函数 */\n fun: Subscriber;\n}\n\n/** 设计器事件总线: 事件路由使用事件类的静态 eventType 显式标识, 不依赖 constructor.name, 代码压缩混淆后依然稳定 */\nclass EventBus {\n /** 事件订阅函数集合 | eventType -> 按优先级升序排列的订阅函数 */\n private readonly subscribers: Map<string, Array<PrioritySubscriber>> = new Map();\n\n /**\n * 分发事件\n * @param event 事件对象\n */\n dispatch<Event extends DesignerEvent>(event: Event): void {\n const arr = this.subscribers.get(event.type);\n if (!arr || arr.length <= 0) return;\n // 遍历副本, 防止订阅函数执行中增删订阅影响本次分发\n const snapshot = arr.slice();\n for (const subscriber of snapshot) {\n try {\n subscriber.fun(event);\n } catch (err) {\n // 单个订阅函数异常不阻断其它订阅者\n console.error(`[EventBus] 事件 \"${event.type}\" 的订阅函数执行异常`, err);\n }\n }\n }\n\n /**\n * 订阅指定的事件\n * @param eventClass 事件构造函数(事件类型)\n * @param subscriber 事件订阅函数\n * @param priority 优先级(越小越优先, 默认: 0)\n * @return 返回取消订阅函数\n */\n subscribe<Event extends DesignerEvent>(\n eventClass: DesignerEventConstructor<Event>,\n subscriber: Subscriber<Event>,\n priority: number = 0,\n ): () => void {\n const eventType = eventClass.eventType;\n if (!eventType) {\n console.error(`[EventBus] 订阅的事件类 \"${eventClass.name}\" 未定义静态 eventType 属性`);\n return () => undefined;\n }\n let arr = this.subscribers.get(eventType);\n if (!arr) {\n arr = [];\n this.subscribers.set(eventType, arr);\n }\n // 按优先级升序插入(越小越优先, 相同优先级保持订阅顺序)\n const item: PrioritySubscriber = { priority, fun: subscriber as Subscriber };\n let insertIdx = arr.length;\n for (let i = 0; i < arr.length; i++) {\n if (arr[i].priority > priority) {\n insertIdx = i;\n break;\n }\n }\n arr.splice(insertIdx, 0, item);\n // 返回取消订阅函数(精确移除当前订阅, 任意时刻调用都有效)\n return () => this.unsubscribe(eventClass, subscriber);\n }\n\n /**\n * 取消指定的订阅函数\n * @param eventClass 事件构造函数(事件类型)\n * @param subscriber 事件订阅函数\n */\n unsubscribe<Event extends DesignerEvent>(eventClass: DesignerEventConstructor<Event>, subscriber: Subscriber<Event>): void {\n const arr = this.subscribers.get(eventClass.eventType);\n if (!arr) return;\n const idx = arr.findIndex(item => item.fun === (subscriber as Subscriber));\n if (idx >= 0) arr.splice(idx, 1);\n }\n\n /**\n * 取消指定事件类型的所有订阅函数\n * @param eventClass 事件构造函数(事件类型)\n */\n unsubscribeAll(eventClass: DesignerEventConstructor): void {\n this.subscribers.delete(eventClass.eventType);\n }\n\n /** 清除所有的订阅函数 */\n clearAllSubscribe(): void {\n this.subscribers.clear();\n }\n}\n\nexport type {\n Subscriber,\n}\n\nexport {\n EventBus,\n}\n","import type { Property } from \"csstype\";\nimport { type ComponentManage } from \"@ease-forge/runtime\";\nimport type { EventContainer } from \"../types/Designer\";\nimport type { DesignerEngine } from \"./DesignerEngine\";\nimport type { EventBus } from \"./EventBus\";\n\n/**\n * 设计器模块基类(Driver 与 Effect 的公共父类)\n * 提供模块上下文: 引擎、事件总线、组件管理器、事件容器、window 对象\n */\nabstract class DesignerModule {\n /** 设计器引擎 */\n readonly designerEngine: DesignerEngine;\n /** 设计器事件总线 */\n readonly eventbus: EventBus;\n /** 组件管理器 */\n readonly componentManage: ComponentManage;\n /** 当前模块监听事件的事件容器 */\n readonly container: EventContainer;\n /** 当前模块对应的 window 对象(考虑设计器运行在 iframe 中的场景) */\n readonly window: Window;\n\n constructor(designerEngine: DesignerEngine, container: EventContainer, window: Window) {\n this.designerEngine = designerEngine;\n this.eventbus = designerEngine.eventbus;\n this.componentManage = designerEngine.componentManage;\n this.container = container;\n this.window = window;\n }\n\n /** 获取事件容器的光标样式 */\n protected getContainerCursorStyle(): string {\n if (this.container instanceof Document) {\n return this.container.body.style.cursor;\n }\n return this.container.style.cursor;\n }\n\n /** 设置事件容器的光标样式(值可以是读取到的任意原始样式字符串) */\n protected setContainerCursorStyle(cursorStyle: Property.Cursor | string): void {\n if (this.container instanceof Document) {\n this.container.body.style.cursor = cursorStyle;\n } else {\n this.container.style.cursor = cursorStyle;\n }\n }\n}\n\nexport {\n DesignerModule,\n}\n","import type { EventContainer } from \"../types/Designer\";\nimport type { DesignerEngine } from \"./DesignerEngine\";\nimport { DesignerModule } from \"./DesignerModule\";\n\n/**\n * 设计器内部业务事件生产者\n * 监听 container 的 HTMLElement 原生事件, 转换成设计器业务事件分发到 EventBus\n */\nabstract class DesignerDriver extends DesignerModule {\n /**\n * 监听 container 的 HTMLElement 事件\n * @param type HTMLElement 事件类型\n * @param listener HTMLElement 事件执行函数\n * @param options 事件选项\n */\n protected addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;\n protected addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;\n protected addEventListener(type: any, listener: any, options?: any): void {\n this.container.addEventListener(type, listener, options);\n }\n\n /**\n * 取消 container 的 HTMLElement 事件监听\n * @param type HTMLElement 事件类型\n * @param listener HTMLElement 事件执行函数\n * @param options 事件选项\n */\n protected removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;\n protected removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;\n protected removeEventListener(type: any, listener: any, options?: any): void {\n this.container.removeEventListener(type, listener, options);\n }\n\n /** 阻止事件的默认动作 */\n protected preventDefault = (event: Event): void => {\n event.preventDefault();\n }\n\n /** 启动当前 DesignerDriver, 开始监听 HTMLElement 事件 */\n abstract attach(): void;\n\n /** 停止当前 DesignerDriver, 取消所有 HTMLElement 事件监听 */\n abstract detach(): void;\n}\n\n/** DesignerDriver 构造函数 */\ntype DesignerDriverConstructor = new (designerEngine: DesignerEngine, container: EventContainer, window: Window) => DesignerDriver;\n\nexport type {\n DesignerDriverConstructor,\n}\n\nexport {\n DesignerDriver,\n}\n","import type { EventContainer } from \"../types/Designer\";\nimport type { DesignerEngine } from \"./DesignerEngine\";\nimport { DesignerModule } from \"./DesignerModule\";\n\n/**\n * 设计器内部业务事件消费者\n * 订阅 EventBus 中的业务事件并做出响应(状态更新、UI 反馈等)\n */\nabstract class DesignerEffect extends DesignerModule {\n /** 当前效果是否已激活 */\n protected actived: boolean = false;\n\n /**\n * 开始消费 EventBus 中的事件(订阅)\n * 引擎 mount 时调用, 幂等(重复调用直接返回)\n */\n effect(): void {\n if (this.actived) return;\n this.actived = true;\n this.onEffect();\n }\n\n /**\n * 停止消费 EventBus 中的事件并释放资源\n * 引擎 unmount 时调用, 幂等(重复调用直接返回)\n */\n destroy(): void {\n if (!this.actived) return;\n this.actived = false;\n this.onDestroy();\n }\n\n /** 开始消费事件时的钩子(订阅逻辑写在这里) */\n protected abstract onEffect(): void;\n\n /** 停止消费事件时的钩子(取消订阅、释放资源写在这里) */\n protected abstract onDestroy(): void;\n}\n\n/** DesignerEffect 构造函数 */\ntype DesignerEffectConstructor = new (designerEngine: DesignerEngine, container: EventContainer, window: Window) => DesignerEffect;\n\nexport type {\n DesignerEffectConstructor,\n}\n\nexport {\n DesignerEffect,\n}\n","import lodash from \"lodash\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { type AuxToolPosition, type CursorPosition, Direction, type NodeToCursorDistance, PointDirection } from \"../types/Designer\";\n\n// 默认为 inline-block 的html标签\nconst inlineHtmlTags = new Set([\n 'a', 'abbr', 'acronym', 'audio', 'b', 'bdi', 'bdo', 'big', 'br', 'button', 'canvas', 'cite', 'code',\n 'data', 'datalist', 'del', 'dfn', 'em', 'embed', 'i', 'iframe', 'img', 'ins', 'kbd', 'label', 'map',\n 'mark', 'meter', 'noscript', 'object', 'output', 'picture', 'progress', 'q', 'ruby', 's', 'samp',\n 'select', 'slot', 'small', 'strong', 'sub', 'sup', 'svg', 'template', 'textarea', 'time', 'u', 'tt',\n 'var', 'video', 'wbr', 'input', 'span',\n]);\n\n/** 默认的光标位置 */\nconst defCursorPosition: CursorPosition = {\n clientX: 0,\n clientY: 0,\n pageX: 0,\n pageY: 0,\n topClientX: 0,\n topClientY: 0,\n topPageX: 0,\n topPageY: 0,\n};\n\n/**\n * 计算 html 元素的外部宽度\n */\nfunction calcElementOuterWidth(innerWidth: number, style: CSSStyleDeclaration): number {\n return (\n innerWidth +\n parseFloat(style.marginLeft) +\n parseFloat(style.marginRight) +\n parseFloat(style.paddingLeft) +\n parseFloat(style.paddingRight) +\n parseFloat(style.borderLeftWidth) +\n parseFloat(style.borderRightWidth)\n );\n}\n\n/**\n * 计算 html 元素是否是行内块\n */\nfunction calcElementIsInlineBlock(element: Element): boolean {\n if (!element) return false;\n const parent = element.parentElement;\n if (!parent) return false;\n const tagName = element.tagName.toLowerCase();\n const parentTagName = parent.tagName;\n const style = getComputedStyle(element);\n const parentStyle = getComputedStyle(parent);\n const isNotFullWidth = () => {\n const innerWidth = element.getBoundingClientRect().width;\n const outerWidth = calcElementOuterWidth(innerWidth, style);\n const parentInnerWidth = parent.getBoundingClientRect().width;\n return outerWidth.toFixed(0) < parentInnerWidth.toFixed(0);\n };\n if (tagName === 'th' || tagName === 'td') {\n if (parentTagName === 'tr') return true;\n }\n if (parentStyle.display === 'flex' && parentStyle.flexDirection === 'row') return true;\n if (parentStyle.display === 'grid') {\n if (isNotFullWidth()) return true;\n }\n if (inlineHtmlTags.has(tagName)) {\n if (style.display === 'block') {\n if (style.float === 'left' || style.float === 'right') {\n if (isNotFullWidth()) return true;\n }\n return false;\n }\n return true;\n }\n return style.display.startsWith(\"inline\");\n}\n\n/**\n * 计算辅助工具的位置\n * @param container 外层容器\n * @param element 内部dom节点\n */\nfunction calcAuxToolPosition(container: Element, element: Element): AuxToolPosition {\n const containerRect = container.getBoundingClientRect();\n const elementRect = element.getBoundingClientRect();\n return {\n height: elementRect.height - 2,\n width: elementRect.width - 2,\n top: elementRect.top - containerRect.top + container.scrollTop + 1,\n left: elementRect.left - containerRect.left + container.scrollLeft + 1,\n isTop: elementRect.top - containerRect.top < 28,\n isBottom: (containerRect.top + containerRect.height - elementRect.top - elementRect.height) < 28,\n };\n}\n\n/**\n * 计算渲染节点与光标的距离\n * @param position 鼠标位置\n * @param element 渲染节点dom\n */\nfunction calcNodeToCursorDistance(position: CursorPosition, element: Element): NodeToCursorDistance {\n const elementRect = element.getBoundingClientRect();\n // 计算四个边的距离\n const top = position.clientY - elementRect.top;\n const bottom = position.clientY - elementRect.top - elementRect.height;\n const left = position.clientX - elementRect.left;\n const right = position.clientX - elementRect.left - elementRect.width;\n const topAbs = Math.abs(top);\n const bottomAbs = Math.abs(bottom);\n const leftAbs = Math.abs(left);\n const rightAbs = Math.abs(right);\n // 光标是否在渲染节点里面\n const vInside = top >= 0 && bottom <= 0;\n const hInside = left >= 0 && right <= 0;\n const bothInside = vInside && hInside && elementRect.width > 0 && elementRect.height > 0;\n let direction: Direction | undefined;\n if (!bothInside) {\n if (top <= 0) {\n direction = Direction.top;\n } else if (bottom >= 0) {\n direction = Direction.bottom;\n } else if (left <= 0) {\n direction = Direction.left;\n } else if (right >= 0) {\n direction = Direction.right;\n }\n }\n const directionDistances = [\n { direction: Direction.top, value: topAbs },\n { direction: Direction.bottom, value: bottomAbs },\n { direction: Direction.left, value: leftAbs },\n { direction: Direction.right, value: rightAbs },\n ];\n if (!direction) {\n direction = lodash.minBy(directionDistances, item => item.value)!.direction;\n }\n // 处理 rowBlock inlineBlock 逻辑\n const inlineBlock = calcElementIsInlineBlock(element);\n const rowBlock = !inlineBlock;\n if (inlineBlock && [Direction.top, Direction.bottom].includes(direction)) {\n direction = leftAbs >= rightAbs ? Direction.right : Direction.left;\n }\n if (rowBlock && [Direction.left, Direction.right].includes(direction)) {\n direction = topAbs >= bottomAbs ? Direction.bottom : Direction.top;\n }\n // 如果离边框太近优先使用对应的边框\n if (bothInside) {\n const minDistance = lodash.minBy(directionDistances, item => item.value)!;\n if (minDistance.value <= 10) {\n direction = minDistance.direction;\n }\n }\n // 计算四个点的距离\n const leftTop = Math.abs(calcDistance(position.clientX, position.clientY, elementRect.left, elementRect.top));\n const leftBottom = Math.abs(calcDistance(position.clientX, position.clientY, elementRect.left, elementRect.top + elementRect.height));\n const rightTop = Math.abs(calcDistance(position.clientX, position.clientY, elementRect.left + elementRect.width, elementRect.top));\n const rightBottom = Math.abs(calcDistance(position.clientX, position.clientY, elementRect.left + elementRect.width, elementRect.top + elementRect.height));\n const { point } = lodash.minBy(\n [\n { point: PointDirection.leftTop, value: leftTop },\n { point: PointDirection.leftBottom, value: leftBottom },\n { point: PointDirection.rightTop, value: rightTop },\n { point: PointDirection.rightBottom, value: rightBottom },\n ],\n item => item.value,\n )!;\n return {\n element: element,\n width: elementRect.width,\n height: elementRect.height,\n top: topAbs,\n bottom: bottomAbs,\n left: leftAbs,\n right: rightAbs,\n vInside: vInside,\n hInside: hInside,\n bothInside: bothInside,\n direction: direction,\n leftTop: leftTop,\n leftBottom: leftBottom,\n rightTop: rightTop,\n rightBottom: rightBottom,\n point: point,\n rowBlock: rowBlock,\n inlineBlock: inlineBlock,\n };\n}\n\n/**\n * 计算两点之间的距离\n */\nfunction calcDistance(x1: number, y1: number, x2: number = 0, y2: number = 0): number {\n x2 = x2 ?? 0;\n y2 = y2 ?? 0;\n // 两点之间的距离公式\n return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));\n}\n\n/**\n * 计算位置增量\n * @param end 结束位置\n * @param start 开始位置\n */\nfunction calcPositionDelta(end: CursorPosition, start?: CursorPosition): CursorPosition {\n const position: any = {};\n for (const key in end) {\n if (Typeof.isValidNumber((end as any)[key]) && Typeof.isValidNumber((start as any)?.[key])) {\n position[key] = (end as any)[key] - (start as any)![key];\n } else {\n position[key] = (end as any)[key];\n }\n }\n return position;\n}\n\nexport {\n defCursorPosition,\n calcAuxToolPosition,\n calcNodeToCursorDistance,\n calcDistance,\n calcPositionDelta,\n}\n","import { computed, type ComputedRef, ref, type Ref } from \"vue\";\nimport { type CursorPosition, CursorStatus } from \"../types/Designer\";\nimport { calcPositionDelta, defCursorPosition } from \"../utils/PositionCalc\";\n\n/**\n * 设计器光标信息模型\n * 维护光标位置、拖拽状态以及拖拽过程的位置增量\n */\nclass Cursor {\n /** 光标拖拽状态 */\n protected readonly _status: Ref<CursorStatus> = ref<CursorStatus>(CursorStatus.Normal);\n /** 光标位置 */\n protected readonly _position: Ref<CursorPosition> = ref<CursorPosition>({ ...defCursorPosition });\n /** 拖动开始位置 */\n protected readonly _dragStartPosition: Ref<CursorPosition | undefined> = ref<CursorPosition | undefined>();\n /** 拖拽结束位置 */\n protected readonly _dragEndPosition: Ref<CursorPosition | undefined> = ref<CursorPosition | undefined>();\n /** 拖动的增量(与上一次的光标位置比较) */\n protected readonly _dragAtomDelta: Ref<CursorPosition> = ref<CursorPosition>({ ...defCursorPosition });\n /** 拖拽起点到当前位置的增量 */\n protected readonly _dragStartToCurrentDelta: ComputedRef<CursorPosition> = computed<CursorPosition>(() => {\n // \"拖动开始位置\"为空\n if (!this._dragStartPosition.value) return defCursorPosition;\n // 当前是\"拖动中\"\n if (this._status.value === CursorStatus.Dragging) return defCursorPosition;\n // 计算\"拖拽起点\"到\"当前位置\"的增量\n return calcPositionDelta(this._position.value, this._dragStartPosition.value);\n });\n /** 拖拽起点到终点位置的增量 */\n protected readonly _dragStartToEndDelta: ComputedRef<CursorPosition> = computed<CursorPosition>(() => {\n // \"拖动开始位置\"或\"拖拽结束位置\"为空\n if (!this._dragStartPosition.value || !this._dragEndPosition.value) return defCursorPosition;\n // 计算\"拖拽起点\"到\"拖拽结束\"的增量\n return calcPositionDelta(this._dragStartPosition.value, this._dragEndPosition.value);\n });\n\n /** 光标状态 */\n get status(): CursorStatus {\n return this._status.value;\n }\n\n set status(status: CursorStatus) {\n this._status.value = status;\n }\n\n /** 光标位置 */\n get position(): CursorPosition {\n return this._position.value;\n }\n\n set position(position: CursorPosition) {\n this._dragAtomDelta.value = calcPositionDelta(this._position.value, position);\n this._position.value = { ...position };\n }\n\n /** 拖动开始位置 */\n get dragStartPosition(): CursorPosition | undefined {\n return this._dragStartPosition.value;\n }\n\n set dragStartPosition(position: CursorPosition | undefined) {\n this._dragStartPosition.value = position ? { ...position } : undefined;\n }\n\n /** 拖拽结束位置 */\n get dragEndPosition(): CursorPosition | undefined {\n return this._dragEndPosition.value;\n }\n\n set dragEndPosition(position: CursorPosition | undefined) {\n this._dragEndPosition.value = position ? { ...position } : undefined;\n }\n\n /** 拖动的增量(与上一次的光标位置比较) */\n get dragAtomDelta(): CursorPosition {\n return this._dragAtomDelta.value;\n }\n\n /** 拖拽起点到当前位置的增量 */\n get dragStartToCurrentDelta(): CursorPosition {\n return this._dragStartToCurrentDelta.value;\n }\n\n /** 拖拽起点到终点位置的增量 */\n get dragStartToEndDelta(): CursorPosition {\n return this._dragStartToEndDelta.value;\n }\n\n /** 当前是否处于拖拽中 */\n isDragging(): boolean {\n return this._status.value === CursorStatus.Dragging;\n }\n}\n\nexport {\n Cursor,\n}\n","import { computed, type ComputedRef, shallowRef, type ShallowRef } from \"vue\";\nimport type { ComponentMeta } from \"@ease-forge/runtime\";\nimport type { AuxToolPosition, InsertionData } from \"../types/Designer\";\n\n/**\n * 正在拖拽的组件元信息模型\n * 由 DraggingEffect 维护: 拖拽开始时填充, 拖拽结束时清空\n */\nclass DraggingCmpMetas {\n /** 正在拖拽的节点ID集合(与 cmpMetas 顺序一一对应, 拖拽物料时为 emptyNodeId) */\n protected readonly _nodeIds: ShallowRef<Array<string>> = shallowRef<Array<string>>([]);\n /** 正在拖拽节点的区域位置 */\n protected readonly _positions: ShallowRef<Array<AuxToolPosition>> = shallowRef<Array<AuxToolPosition>>([]);\n /** 正在拖拽的组件元信息集合 */\n protected readonly _cmpMetas: ShallowRef<Array<ComponentMeta>> = shallowRef<Array<ComponentMeta>>([]);\n /** 存在拖拽的组件 */\n protected readonly _existsCmpMeta: ComputedRef<boolean> = computed<boolean>(() => this._cmpMetas.value.length > 0);\n /** 当前是否只有一个组件在拖拽 */\n protected readonly _onlyOne: ComputedRef<boolean> = computed<boolean>(() => this._cmpMetas.value.length === 1);\n /** 设计器插入组件的位置信息 */\n protected readonly _insertion: ShallowRef<InsertionData | undefined> = shallowRef<InsertionData | undefined>();\n\n /** 正在拖拽的节点ID集合(与 cmpMetas 顺序一一对应) */\n get nodeIds(): Array<string> {\n return this._nodeIds.value;\n }\n\n set nodeIds(value: Array<string>) {\n this._nodeIds.value = value;\n }\n\n /** 正在拖拽节点的区域位置 */\n get positions(): Array<AuxToolPosition> {\n return this._positions.value;\n }\n\n set positions(value: Array<AuxToolPosition>) {\n this._positions.value = value;\n }\n\n /** 正在拖拽的组件元信息集合 */\n get cmpMetas(): Array<ComponentMeta> {\n return this._cmpMetas.value;\n }\n\n set cmpMetas(value: Array<ComponentMeta>) {\n this._cmpMetas.value = value;\n }\n\n /** 存在拖拽的组件 */\n get existsCmpMeta(): boolean {\n return this._existsCmpMeta.value;\n }\n\n /** 当前是否只有一个组件在拖拽 */\n get onlyOne(): boolean {\n return this._onlyOne.value;\n }\n\n /** 设计器插入组件的位置信息 */\n get insertion(): InsertionData | undefined {\n return this._insertion.value;\n }\n\n set insertion(value: InsertionData | undefined) {\n this._insertion.value = value;\n }\n\n /** 清空拖拽状态 */\n clear(): void {\n this._cmpMetas.value = [];\n this._nodeIds.value = [];\n this._positions.value = [];\n this._insertion.value = undefined;\n }\n}\n\nexport {\n DraggingCmpMetas,\n}\n","import { ref, type Ref, shallowRef, type ShallowRef } from \"vue\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { type AuxToolPosition, Direction, type InsertionData, type NodeToCursorDistance } from \"../types/Designer\";\n\n/**\n * 设计器插入组件的位置信息模型\n * 拖拽过程中由 AuxToolEffect 计算, 记录\"放到哪个容器的哪个位置\"\n */\nclass Insertion {\n /** 渲染节点与光标的距离信息 */\n protected readonly _distance: ShallowRef<NodeToCursorDistance | undefined> = shallowRef<NodeToCursorDistance | undefined>();\n /** 插入区域位置 */\n protected readonly _position: ShallowRef<AuxToolPosition | undefined> = shallowRef<AuxToolPosition | undefined>();\n /** 容器组件节点id(值是:RuntimeNode.id) */\n protected readonly _containerId: Ref<string | undefined> = ref<string | undefined>();\n /** 插入容器节点的插槽名称(子节点是一种特殊的插槽,名为:default) */\n protected readonly _slotName: Ref<string | undefined> = ref<string | undefined>();\n /** 离插入位置最近的组件节点id(值是:RuntimeNode.id) */\n protected readonly _nodeId: Ref<string | undefined> = ref<string | undefined>();\n /** 当前 node 属于占位组件 */\n protected readonly _placeholder: Ref<boolean | undefined> = ref<boolean | undefined>();\n /** 是否允许拖拽(通过了 DragDropConfig 校验) */\n protected readonly _allowDrag: Ref<boolean> = ref<boolean>(false);\n\n /** 渲染节点与光标的距离信息 */\n get distance(): NodeToCursorDistance | undefined {\n return this._distance.value;\n }\n\n set distance(value: NodeToCursorDistance | undefined) {\n this._distance.value = value;\n }\n\n /** 插入区域位置 */\n get position(): AuxToolPosition | undefined {\n return this._position.value;\n }\n\n set position(value: AuxToolPosition | undefined) {\n this._position.value = value;\n }\n\n /** 容器组件节点id(值是:RuntimeNode.id) */\n get containerId(): string | undefined {\n return this._containerId.value;\n }\n\n set containerId(value: string | undefined) {\n this._containerId.value = value;\n }\n\n /** 插入容器节点的插槽名称(子节点是一种特殊的插槽,名为:default) */\n get slotName(): string | undefined {\n return this._slotName.value;\n }\n\n set slotName(value: string | undefined) {\n this._slotName.value = value;\n }\n\n /** 离插入位置最近的组件节点id(值是:RuntimeNode.id) */\n get nodeId(): string | undefined {\n return this._nodeId.value;\n }\n\n set nodeId(value: string | undefined) {\n this._nodeId.value = value;\n }\n\n /** 当前 node 属于占位组件 */\n get placeholder(): boolean | undefined {\n return this._placeholder.value;\n }\n\n set placeholder(value: boolean | undefined) {\n this._placeholder.value = value;\n }\n\n /** 是否允许拖拽(通过了 DragDropConfig 校验) */\n get allowDrag(): boolean {\n return this._allowDrag.value;\n }\n\n set allowDrag(value: boolean) {\n this._allowDrag.value = value;\n }\n\n /** 插入的方向 */\n get direction(): Direction | undefined {\n return this._distance.value?.direction;\n }\n\n /** 是否在 nodeId 之前插入 */\n isBefore(): boolean {\n const direction = this._distance.value?.direction;\n if (!direction) return false;\n return [Direction.top, Direction.left].includes(direction);\n }\n\n /** 是否是水平方向插入(left、right) */\n isHorizontal(): boolean {\n const direction = this._distance.value?.direction;\n if (!direction) return false;\n return [Direction.left, Direction.right].includes(direction);\n }\n\n /** 当前是否是空的(没有有效的插入位置) */\n isEmpty(): boolean {\n return Typeof.noValue(this._distance.value?.direction);\n }\n\n /** 生成设计器插入组件的位置信息(给 DragDropEvent / 操作命令层使用) */\n getInsertionData(): InsertionData | undefined {\n if (this.isEmpty()) return;\n return {\n distance: this.distance!,\n position: this.position!,\n containerId: this.containerId!,\n slotName: this.slotName!,\n nodeId: this.nodeId!,\n placeholder: this.placeholder!,\n allowDrag: this.allowDrag,\n before: this.isBefore(),\n };\n }\n\n /** 清除插入信息 */\n clear(): void {\n this._distance.value = undefined;\n this._position.value = undefined;\n this._containerId.value = undefined;\n this._slotName.value = undefined;\n this._nodeId.value = undefined;\n this._placeholder.value = undefined;\n this._allowDrag.value = false;\n }\n}\n\nexport {\n Insertion,\n}\n","import type { DesignNode } from \"@ease-forge/runtime\";\n\n/**\n * 判断组件的占位配置中是否存在有效的占位节点\n * (存在占位节点表示当前组件是容器组件, 可以容纳子组件)\n * @param placeholder 占位配置(值兼容 DesignNode 配置形态与 RuntimeNode 运行时形态)\n */\nfunction existsPlaceholder(placeholder?: Record<\"default\" | string, DesignNode | RuntimeNodePlaceholder | boolean>): boolean {\n if (!placeholder) return false;\n for (const name in placeholder) {\n const holder = placeholder[name];\n if (holder) return true;\n }\n return false;\n}\n\n/** RuntimeNode 形态的占位节点(只需要判断真值, 结构不关心) */\ninterface RuntimeNodePlaceholder {\n [name: string]: any;\n}\n\nexport {\n existsPlaceholder,\n}\n","import { ref, type Ref, shallowRef, type ShallowRef } from \"vue\";\nimport type { ComponentMeta } from \"@ease-forge/runtime\";\nimport { htmlExtAttr } from \"@ease-forge/runtime\";\nimport type { AuxToolPosition } from \"../types/Designer\";\nimport { calcAuxToolPosition } from \"../utils/PositionCalc\";\nimport { existsPlaceholder } from \"../utils/ComponentMetaUtils\";\nimport type { DesignerState } from \"./DesignerState\";\n\n/**\n * 设计器鼠标悬停时的虚线框模型\n * 记录悬停节点的元信息与虚线框位置\n */\nclass HoverDashed {\n /** 所属的设计器状态 */\n readonly designerState: DesignerState;\n /** 组件元信息 */\n protected readonly _componentMeta: ShallowRef<ComponentMeta | undefined> = shallowRef<ComponentMeta | undefined>();\n /** 父组件节点id(值是:RuntimeNode.id) */\n protected readonly _parentId: Ref<string | undefined> = ref<string | undefined>();\n /** 组件节点id(值是:RuntimeNode.id) */\n protected readonly _nodeId: Ref<string | undefined> = ref<string | undefined>();\n /** 虚线框区域位置 */\n protected readonly _position: ShallowRef<AuxToolPosition | undefined> = shallowRef<AuxToolPosition | undefined>();\n\n constructor(designerState: DesignerState) {\n this.designerState = designerState;\n }\n\n /** 组件元信息 */\n get componentMeta(): ComponentMeta | undefined {\n return this._componentMeta.value;\n }\n\n set componentMeta(value: ComponentMeta | undefined) {\n this._componentMeta.value = value;\n }\n\n /** 父组件节点id(值是:RuntimeNode.id) */\n get parentId(): string | undefined {\n return this._parentId.value;\n }\n\n set parentId(value: string | undefined) {\n this._parentId.value = value;\n }\n\n /** 组件节点id(值是:RuntimeNode.id) */\n get nodeId(): string | undefined {\n return this._nodeId.value;\n }\n\n set nodeId(value: string | undefined) {\n this._nodeId.value = value;\n }\n\n /** 虚线框区域位置 */\n get position(): AuxToolPosition | undefined {\n return this._position.value;\n }\n\n set position(value: AuxToolPosition | undefined) {\n this._position.value = value;\n }\n\n /** 当前悬停的组件是否是容器组件(存在占位插槽) */\n get isContainer(): boolean {\n const componentMeta = this._componentMeta.value;\n if (!componentMeta) return false;\n return existsPlaceholder(componentMeta.placeholder);\n }\n\n /** 重新计算虚线框的位置 */\n recalcPosition(): void {\n if (!this._nodeId.value) return;\n const designerContainer = this.designerState.designerContainer;\n if (!designerContainer) return;\n const node = designerContainer.querySelector(`[${htmlExtAttr.nodeId}=${this._nodeId.value}]`);\n if (node) {\n this._position.value = calcAuxToolPosition(designerContainer, node);\n } else {\n this._position.value = undefined;\n }\n }\n\n /** 清除悬停信息 */\n clear(): void {\n this._componentMeta.value = undefined;\n this._parentId.value = undefined;\n this._nodeId.value = undefined;\n this._position.value = undefined;\n }\n}\n\nexport {\n HoverDashed,\n}\n","import { HoverDashed } from \"./HoverDashed\";\n\n/**\n * 设计器选中组件的信息(在悬停虚线的基础上扩展)\n */\nclass Selection extends HoverDashed {\n}\n\nexport {\n Selection,\n}\n","import { shallowReactive, type ShallowReactive } from \"vue\";\nimport type { DesignCommand } from \"./Command\";\nimport type { DesignerState } from \"../models/DesignerState\";\nimport { CommandEvent, type CommandEventData } from \"../events/designer/CommandEvent\";\n\n/** 命令栈最大保存的历史条数(超过后丢弃最旧的历史) */\nconst maxHistorySize = 100;\n\n/** 命令合并时间窗(毫秒): 窗口内对同一目标的连续修改合并成一条历史 */\nconst mergeTimeWindow = 1000;\n\n/**\n * 设计器命令栈(undo/redo)\n * 每个设计器页面(DesignerState)拥有独立的命令栈\n */\nclass CommandStack {\n /** 所属的设计器页面状态 */\n readonly designerState: DesignerState;\n /** 可撤销的命令集合(按执行顺序) */\n readonly undoStack: ShallowReactive<Array<DesignCommand>> = shallowReactive<Array<DesignCommand>>([]);\n /** 可重做的命令集合(按撤销顺序) */\n readonly redoStack: ShallowReactive<Array<DesignCommand>> = shallowReactive<Array<DesignCommand>>([]);\n /** 最近一次命令执行(或合并)的时间戳(命令合并时间窗的依据) */\n protected lastExecuteTime = 0;\n\n constructor(designerState: DesignerState) {\n this.designerState = designerState;\n }\n\n /** 是否可撤销 */\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n /** 是否可重做 */\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n /** 历史记录总数 */\n get size(): number {\n return this.undoStack.length;\n }\n\n /**\n * 执行命令并入栈\n * @param command 命令对象(执行失败不会入栈)\n */\n execute(command: DesignCommand): boolean {\n if (!command.execute()) return false;\n // 时间窗内的同类连续修改尝试合并到栈顶命令(不新增历史条目)\n const top = this.undoStack[this.undoStack.length - 1];\n if (top?.tryMerge && Date.now() - this.lastExecuteTime <= mergeTimeWindow && top.tryMerge(command)) {\n // 合并成功: 重做历史失效\n this.redoStack.length = 0;\n this.lastExecuteTime = Date.now();\n this.dispatchCommandEvent(\"execute\", command);\n this.notifyPanelUpdate();\n return true;\n }\n this.undoStack.push(command);\n // 新命令会使重做历史失效\n this.redoStack.length = 0;\n // 限制历史长度\n if (this.undoStack.length > maxHistorySize) this.undoStack.splice(0, this.undoStack.length - maxHistorySize);\n this.lastExecuteTime = Date.now();\n this.dispatchCommandEvent(\"execute\", command);\n this.notifyPanelUpdate();\n return true;\n }\n\n /** 撤销最近的一个命令(撤销失败时命令保持在栈中, 历史链不变) */\n undo(): DesignCommand | undefined {\n const command = this.undoStack[this.undoStack.length - 1];\n if (!command) return;\n if (!command.undo()) return;\n this.undoStack.pop();\n this.redoStack.push(command);\n this.dispatchCommandEvent(\"undo\", command);\n this.notifyPanelUpdate();\n return command;\n }\n\n /** 重做最近撤销的一个命令(重做失败时命令保持在栈中, 历史链不变) */\n redo(): DesignCommand | undefined {\n const command = this.redoStack[this.redoStack.length - 1];\n if (!command) return;\n if (!command.redo()) return;\n this.redoStack.pop();\n this.undoStack.push(command);\n this.dispatchCommandEvent(\"redo\", command);\n this.notifyPanelUpdate();\n return command;\n }\n\n /**\n * 通知配置面板刷新\n * 节点是非响应式对象, 面板展示的属性/指令/事件在命令(含 undo/redo)修改后\n * 不会自动更新, 递增面板版本号触发重渲染\n */\n protected notifyPanelUpdate(): void {\n this.designerState.setterShareState.notifyPanelUpdate();\n }\n\n /** 清空所有历史 */\n clear(): void {\n this.undoStack.length = 0;\n this.redoStack.length = 0;\n }\n\n /** 分发命令事件(历史面板/日志订阅) */\n protected dispatchCommandEvent(type: CommandEventData[\"type\"], command: DesignCommand): void {\n this.designerState.designerEngine.eventbus.dispatch(new CommandEvent({\n type,\n name: command.name,\n path: this.designerState.designerEngine.activeDesignerPath,\n }));\n }\n}\n\nexport {\n CommandStack,\n}\n","import { ref, type Ref } from \"vue\";\nimport type { ComponentMeta, SetterGroup } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"./DesignerState\";\n\n/**\n * 组件配置面板共享状态(分组展开状态 + 面板刷新版本)\n */\nclass SetterShareState {\n /** 所属的设计器状态 */\n readonly designerState: DesignerState;\n /** 展开的组件分组 | 面板类型 -> 展开的分组标题 */\n protected readonly _expandGroups: Ref<Record<string, Array<string>>> = ref<Record<string, Array<string>>>({});\n /** 面板刷新版本号(每次 +1, 驱动面板重渲染) */\n protected readonly _panelVersion: Ref<number> = ref<number>(0);\n\n constructor(designerState: DesignerState) {\n this.designerState = designerState;\n }\n\n /** 获取所有展开的 group title */\n protected getAllExpandTitles(meta?: ComponentMeta): Record<string, Array<string>> {\n if (!meta) return {};\n const expandGroups: Record<string, Array<string>> = {\n props: [],\n style: [\"布局\", \"间距\", \"尺寸\", \"文本\", \"背景与效果\"],\n advanced: [],\n };\n const getExpands = (groups: Array<SetterGroup>) => {\n const expands: Array<string> = [];\n for (const group of groups) {\n if (group.expand !== false) {\n expands.push(group.title);\n }\n }\n return expands;\n };\n if (meta.setter.props) expandGroups.props.push(...getExpands(meta.setter.props.groups));\n return expandGroups;\n }\n\n /** 展开的组件分组 */\n get expandGroups(): Record<string, Array<string>> {\n return this._expandGroups.value;\n }\n\n set expandGroups(value: Record<string, Array<string>>) {\n this._expandGroups.value = value;\n }\n\n /** 重新计算expandGroups(选中组件变化时调用) */\n recalcExpandGroups(): void {\n this._expandGroups.value = this.getAllExpandTitles(this.designerState.selectedComponentMeta);\n }\n\n /** 面板刷新版本号(面板以它作为渲染 key) */\n get panelVersion(): number {\n return this._panelVersion.value;\n }\n\n /**\n * 通知配置面板刷新\n * 画布节点是非响应式对象(markRaw), 面板直接修改 node.props/node.listeners 后\n * 依赖这些数据的显示(绑定标记、已绑定标签等)不会自动更新, 需主动递增版本号触发重渲染\n */\n notifyPanelUpdate(): void {\n this._panelVersion.value++;\n }\n}\n\nexport {\n SetterShareState,\n}\n","import { computed, type ComputedRef, markRaw, nextTick, ref, type Ref, shallowReactive, type ShallowReactive } from \"vue\";\nimport { type BlockInstance, type ComponentMeta, htmlExtAttr, type RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignerEngine } from \"../core/DesignerEngine\";\nimport { HoverDashed } from \"./HoverDashed\";\nimport { Selection } from \"./Selection\";\nimport { CommandStack } from \"../history/CommandStack\";\nimport { calcAuxToolPosition } from \"../utils/PositionCalc\";\nimport { SetterShareState } from \"./SetterShareState\";\n\n/**\n * 设计器页面状态(一个设计器页面路由对应一个 DesignerState)\n * 持有画布容器 DOM、画布 Block 实例、悬停虚线与选中集合\n */\nclass DesignerState {\n /** 设计器引擎 */\n readonly designerEngine: DesignerEngine;\n /** 设计器画布容器 DOM(DesignCanvas 组件挂载时设置) */\n readonly _designerContainer: Ref<HTMLDivElement | undefined> = ref<HTMLDivElement | undefined>();\n /** 设计器画布的 Block 组件实例(DesignCanvas 组件挂载时设置) */\n readonly _designerBlockInstance: Ref<BlockInstance | undefined> = ref<BlockInstance | undefined>();\n /** 设计器鼠标悬停时的虚线 */\n readonly hover: HoverDashed;\n /** 命令栈(undo/redo) */\n readonly commandStack: CommandStack;\n /** 组件配置面板共享状态 */\n readonly setterShareState: SetterShareState;\n /** 设计器选中节点集合 */\n readonly selections: ShallowReactive<Array<Selection>> = shallowReactive<Array<Selection>>([]);\n /** 设计器选择的第一个节点 */\n protected readonly _selection: ComputedRef<Selection | undefined> = computed<Selection | undefined>(() => this.selections[0]);\n /** 存在选中的节点 */\n protected readonly _existsSelection: ComputedRef<boolean> = computed<boolean>(() => this.selections.length > 0);\n /** selections 中只有一个选择项 */\n protected readonly _singleSelection: ComputedRef<boolean> = computed<boolean>(() => this.selections.length === 1);\n /** 设计器选中的节点集合(由 nodeId 解析成 RuntimeNode) */\n protected readonly _selectNodes: ComputedRef<Array<RuntimeNode>> = computed<Array<RuntimeNode>>(() => {\n const nodes: Array<RuntimeNode> = [];\n const blockInstance = this.blockInstance;\n if (blockInstance) {\n for (const selection of this.selections) {\n const nodeId = selection.nodeId;\n if (!nodeId) continue;\n const node = blockInstance.globalContext.allNode[nodeId];\n if (node) nodes.push(markRaw(node));\n }\n }\n return nodes;\n });\n /** 设计器选中的第一个节点 */\n protected readonly _selectNode: ComputedRef<RuntimeNode | undefined> = computed<RuntimeNode | undefined>(() => {\n const blockInstance = this.blockInstance;\n if (!blockInstance) return;\n if (this.selections.length <= 0) return;\n const nodeId = this.selections[0].nodeId;\n if (!nodeId) return;\n return blockInstance.globalContext.allNode[nodeId];\n });\n /** 当前选中的 ComponentMeta(多选且类型不同时返回空) */\n protected readonly _selectedComponentMeta: ComputedRef<ComponentMeta | undefined> = computed<ComponentMeta | undefined>(() => this.getCurrentComponentMeta());\n\n constructor(designerEngine: DesignerEngine) {\n this.designerEngine = designerEngine;\n this.hover = new HoverDashed(this);\n this.commandStack = new CommandStack(this);\n this.setterShareState = new SetterShareState(this);\n }\n\n /**\n * 获取当前选中的 ComponentMeta,如果选中多个节点且节点类型不同返回空\n */\n protected getCurrentComponentMeta(): ComponentMeta | undefined {\n if (this.selections.length <= 0) return;\n if (this.selections.length === 1) return this.selections[0].componentMeta;\n let componentMeta: ComponentMeta | undefined;\n const types = new Set<string>();\n for (const selection of this.selections) {\n if (!selection.componentMeta) continue;\n componentMeta = selection.componentMeta;\n types.add(componentMeta.type);\n if (types.size > 1) return;\n }\n return componentMeta;\n }\n\n /** 设计器画布容器 DOM */\n get designerContainer(): HTMLDivElement | undefined {\n return this._designerContainer?.value;\n }\n\n /** 设置设计器画布容器 DOM */\n set designerContainer(value: HTMLDivElement | undefined) {\n this._designerContainer.value = value;\n }\n\n /** 设计器画布的 Block 组件实例 */\n get designerBlockInstance(): BlockInstance | undefined {\n return this._designerBlockInstance?.value;\n }\n\n /** 设置设计器画布的 Block 组件实例 */\n set designerBlockInstance(value: BlockInstance | undefined) {\n this._designerBlockInstance.value = value;\n }\n\n /** 画布 Block 实例对象(globalContext/ops 等访问入口) */\n get blockInstance(): BlockInstance | undefined {\n return this._designerBlockInstance?.value;\n }\n\n /** 设计器选择的第一个节点(Selection) */\n get selection(): Selection | undefined {\n return this._selection.value;\n }\n\n /** 存在选中的节点 */\n get existsSelection(): boolean {\n return this._existsSelection.value;\n }\n\n /** selections 中只有一个选择项 */\n get singleSelection(): boolean {\n return this._singleSelection.value;\n }\n\n /** 设计器选中的节点集合(RuntimeNode) */\n get selectNodes(): Array<RuntimeNode> {\n return this._selectNodes.value;\n }\n\n /** 设计器选中的第一个节点(RuntimeNode) */\n get selectNode(): RuntimeNode | undefined {\n return this._selectNode.value;\n }\n\n /** 当前选中的 ComponentMeta */\n get selectedComponentMeta(): ComponentMeta | undefined {\n return this._selectedComponentMeta.value;\n }\n\n /** 清空选中的节点集合 */\n clearSelections(): void {\n this.selections.length = 0;\n }\n\n /**\n * 选中指定的节点集合(替换当前选中)\n * 等待画布重新渲染完成后, 依据节点 DOM 计算选中框位置\n * @param nodeIds 节点id集合(RuntimeNode.id)\n */\n selectNodeByIds(nodeIds: Array<string>): void {\n nextTick(() => {\n const blockInstance = this.blockInstance;\n if (!blockInstance) return;\n this.selections.length = 0;\n for (const nodeId of nodeIds) {\n const node = blockInstance.globalContext.allNode[nodeId];\n if (!node) continue;\n const selection = new Selection(this);\n selection.nodeId = node.id;\n const parent = blockInstance.globalContext.nodeParent[nodeId];\n selection.parentId = parent?.id;\n selection.componentMeta = this.designerEngine.componentManage.getComponentMeta(node.type);\n const container = this.designerContainer;\n const element = container?.querySelector(`[${htmlExtAttr.nodeId}=${nodeId}]`);\n if (container && element) {\n selection.position = calcAuxToolPosition(container, element);\n }\n this.selections.push(selection);\n }\n });\n }\n}\n\nexport {\n DesignerState,\n}\n","import { ref, type Ref, shallowReactive, type ShallowReactive } from \"vue\";\nimport { type ComponentManage, DefComponentManage } from \"@ease-forge/runtime\";\nimport type { EventContainer } from \"../types/Designer\";\nimport { EngineMountEvent, type EngineMountEventData } from \"../events/engine/EngineMountEvent\";\nimport { EngineUnmountEvent, type EngineUnmountEventData } from \"../events/engine/EngineUnmountEvent\";\nimport type { DesignerDriver, DesignerDriverConstructor } from \"./DesignerDriver\";\nimport type { DesignerEffect, DesignerEffectConstructor } from \"./DesignerEffect\";\nimport { EventBus } from \"./EventBus\";\nimport { Cursor } from \"../models/Cursor\";\nimport { DraggingCmpMetas } from \"../models/DraggingCmpMetas\";\nimport { Insertion } from \"../models/Insertion\";\nimport { DesignerState } from \"../models/DesignerState\";\n\n/** 引擎初始化属性 */\ninterface DesignerEngineProps {\n /** 组件管理器 */\n componentManage: ComponentManage;\n /** 设计器内部业务事件生产者集合 */\n drivers: Array<DesignerDriverConstructor>;\n /** 设计器内部业务事件消费者集合 */\n effects: Array<DesignerEffectConstructor>;\n /** 设计器画布内容区域的 CSS 选择器(MouseClickDriver 用它判断点击是否发生在画布内) */\n designerContent: string;\n}\n\nconst defaultProps: DesignerEngineProps = {\n componentManage: new DefComponentManage(),\n drivers: [],\n effects: [],\n designerContent: '.designer-content',\n};\n\n/**\n * 设计器引擎\n * 负责设计器功能模块(Driver/Effect)的装配与生命周期管理:\n * mount -> 创建 drivers + effects -> effects 订阅事件 -> drivers 监听 DOM -> 分发 EngineMountEvent\n * unmount -> 分发 EngineUnmountEvent -> drivers 取消监听 -> effects 释放 -> 清空事件总线\n *\n * 引擎上的状态模型:\n * - cursor: 光标状态与位置(由 CursorEffect 维护)\n * - draggingCmpMetas: 正在拖拽的组件元信息(由 DraggingEffect 维护)\n * - onlyPressedCtrl/onlyPressedShift: \"仅仅按下 Ctrl/Shift\"状态(由 KeyboardDriver 维护)\n */\nclass DesignerEngine {\n /** 设计器事件总线 */\n readonly eventbus: EventBus = new EventBus();\n /** 初始化属性 */\n readonly props: DesignerEngineProps;\n /** 已创建的设计器业务事件生产者实例集合 */\n protected readonly drivers: Array<DesignerDriver> = [];\n /** 已创建的设计器业务事件消费者实例集合 */\n protected readonly effects: Array<DesignerEffect> = [];\n /** 当前光标状态 */\n readonly cursor: Cursor = new Cursor();\n /** 正在拖拽的组件的元信息 */\n readonly draggingCmpMetas: DraggingCmpMetas = new DraggingCmpMetas();\n /** 设计器插入组件的位置信息 */\n readonly insertion: Insertion = new Insertion();\n /** 所有的设计器页面状态数据(多页面设计器) | 页面路由路径(fullPath) -> DesignerState */\n readonly allDesignerState: ShallowReactive<Record<string, DesignerState>> = shallowReactive<Record<string, DesignerState>>({});\n /** 当前活动的设计器页面路由路径(fullPath) */\n protected readonly _activeDesignerPath: Ref<string | undefined> = ref<string | undefined>();\n /** 当前仅仅按下 ctrl 键 */\n protected readonly _onlyPressedCtrl: Ref<boolean> = ref<boolean>(false);\n /** 当前仅仅按下 shift 键 */\n protected readonly _onlyPressedShift: Ref<boolean> = ref<boolean>(false);\n /** 当前引擎是否已挂载 */\n protected mounted: boolean = false;\n\n constructor(props: Partial<DesignerEngineProps> = {}) {\n this.props = { ...defaultProps, ...props };\n }\n\n /** 组件管理器 */\n get componentManage(): ComponentManage {\n return this.props.componentManage;\n }\n\n /** 当前引擎是否已挂载 */\n get isMounted(): boolean {\n return this.mounted;\n }\n\n /** 当前活动的设计器页面路由路径(fullPath) */\n get activeDesignerPath(): string | undefined {\n return this._activeDesignerPath.value;\n }\n\n set activeDesignerPath(value: string | undefined) {\n // 只允许设置为已存在的页面状态\n if (value && !this.allDesignerState[value]) value = undefined;\n this._activeDesignerPath.value = value;\n }\n\n /** 当前活动的设计器页面状态 */\n get activeDesignerState(): DesignerState | undefined {\n const activeDesignerPath = this.activeDesignerPath;\n if (!activeDesignerPath) return;\n return this.allDesignerState[activeDesignerPath];\n }\n\n /**\n * 新增 DesignerState 页面状态对象(如果存在直接返回已存在的)\n * @param fullPath 设计器页面路由路径\n */\n addDesignerState(fullPath: string): DesignerState {\n let designerState = this.allDesignerState[fullPath];\n if (!designerState) {\n designerState = new DesignerState(this);\n this.allDesignerState[fullPath] = designerState;\n }\n return designerState;\n }\n\n /**\n * 删除 DesignerState 页面状态对象\n * @param fullPath 设计器页面路由路径\n */\n delDesignerState(fullPath: string): DesignerState | undefined {\n const designerState = this.allDesignerState[fullPath];\n delete this.allDesignerState[fullPath];\n if (this.activeDesignerPath === fullPath) this.activeDesignerPath = undefined;\n return designerState;\n }\n\n /** 当前仅仅按下 ctrl 键 */\n get onlyPressedCtrl(): boolean {\n return this._onlyPressedCtrl.value;\n }\n\n set onlyPressedCtrl(value: boolean) {\n this._onlyPressedCtrl.value = value;\n }\n\n /** 当前仅仅按下 shift 键 */\n get onlyPressedShift(): boolean {\n return this._onlyPressedShift.value;\n }\n\n set onlyPressedShift(value: boolean) {\n this._onlyPressedShift.value = value;\n }\n\n /**\n * 挂载当前设计器(重复挂载会先卸载旧实例)\n * @param container 监听原生事件的事件容器(默认: document)\n * @param window 引擎关联的 window 对象, 考虑设计器画布运行在 iframe 中的场景(默认: 全局 window)\n */\n mount(container: EventContainer = document, window: Window = globalThis as unknown as Window): void {\n // 先卸载旧的实例\n this.unmount();\n // 创建设计器功能模块实例\n const drivers = this.props.drivers.map(driver => new driver(this, container, window));\n const effects = this.props.effects.map(effect => new effect(this, container, window));\n this.drivers.push(...drivers);\n this.effects.push(...effects);\n // 先让 effects 订阅事件(保证 EngineMountEvent 也能被消费)\n this.effects.forEach(effect => effect.effect());\n // 再启动 drivers 监听原生事件\n this.drivers.forEach(driver => driver.attach());\n this.mounted = true;\n // 分发挂载完成事件\n const data: EngineMountEventData = { container, window, timestamp: Date.now() };\n this.eventbus.dispatch(new EngineMountEvent(data));\n }\n\n /** 卸载当前设计器(未挂载时调用无任何效果) */\n unmount(): void {\n if (!this.mounted) return;\n // 先分发卸载事件(订阅者可在此释放资源)\n const data: EngineUnmountEventData = { timestamp: Date.now() };\n this.eventbus.dispatch(new EngineUnmountEvent(data));\n // 停止 drivers 监听原生事件\n this.drivers.forEach(driver => driver.detach());\n // 停止 effects 并释放资源\n this.effects.forEach(effect => effect.destroy());\n // 清除所有的订阅函数\n this.eventbus.clearAllSubscribe();\n // 清空实例集合\n this.drivers.length = 0;\n this.effects.length = 0;\n this.mounted = false;\n }\n}\n\nexport type {\n DesignerEngineProps,\n}\n\nexport {\n DesignerEngine,\n}\n","import { Typeof } from \"@ease-forge/shared\";\nimport { type ComponentMeta, emptyNodeId, htmlExtAttr, materialItem, useHtmlExtAttr } from \"@ease-forge/runtime\";\nimport { calcDistance } from \"../utils/PositionCalc\";\nimport { DesignerDriver } from \"../core/DesignerDriver\";\nimport { DragStartEvent } from \"../events/cursor/DragStartEvent\";\nimport { DragMoveEvent } from \"../events/cursor/DragMoveEvent\";\nimport { DragStopEvent } from \"../events/cursor/DragStopEvent\";\n\n/** 拖拽状态 */\ninterface DragState {\n /** 是否在拖拽中 */\n dragging: boolean;\n /** 拖拽开始的时间戳 */\n startDragTime?: number;\n /** 开始拖拽时触发的事件 */\n startEvent?: MouseEvent;\n /** 拖拽中的事件 */\n moveEvent?: MouseEvent | DragEvent;\n}\n\n/**\n * 鼠标拖拽操作的事件处理\n * 产生的业务事件: DragStartEvent、DragMoveEvent、DragStopEvent\n * 参考: https://juejin.cn/post/7188149937883283512\n */\nclass DragDropDriver extends DesignerDriver {\n private readonly dragState: DragState = this.initDragState();\n /** 正在拖拽的组件元信息集合 Map<nodeId, ComponentMeta> */\n private componentMetas: Map<string, ComponentMeta> = new Map();\n\n protected initDragState(): DragState {\n return {\n dragging: false,\n startDragTime: undefined,\n startEvent: undefined,\n moveEvent: undefined,\n };\n }\n\n attach(): void {\n // 监听鼠标按下事件(捕获阶段)\n this.addEventListener('mousedown', this.onMouseDown, true);\n }\n\n detach(): void {\n // 取消所有的事件监听\n this.removeEventListener('mousedown', this.onMouseDown, true);\n this.removeEventListener('mouseup', this.onMouseUp);\n this.removeEventListener('mousemove', this.onMouseMove);\n this.removeEventListener('mousemove', this.onDistanceChange);\n this.removeEventListener('dragstart', this.onStartDrag);\n this.removeEventListener('dragend', this.onMouseUp);\n this.removeEventListener('dragover', this.onMouseMove);\n this.removeEventListener('contextmenu', this.preventDefault, true);\n // 重置拖拽状态\n this.dragState.dragging = false;\n this.componentMetas.clear();\n }\n\n /**\n * 鼠标按下事件,拖拽开始准备\n */\n onMouseDown = (event: MouseEvent): void => {\n // 如果 未按下鼠标左键 或者 按下了Control键 或者 win键(mac中是Command键),就直接返回\n if (event.button !== 0 || event.ctrlKey || event.metaKey) return;\n const target = event.target as HTMLElement;\n if (!target?.closest) return;\n this.componentMetas.clear();\n // 拖拽物料组件\n const materialElement = target.closest(materialItem);\n const materialMeta = useHtmlExtAttr.componentMeta(materialElement, this.componentManage);\n if (materialMeta) {\n this.componentMetas.set(emptyNodeId, materialMeta);\n } else {\n // 拖拽画布中的渲染节点\n let element = target.closest(`[${htmlExtAttr.componentType}]`);\n if (element && element.parentElement && useHtmlExtAttr.placeholderName(element)) {\n // 点中的是占位组件, 向上找到真正的容器节点\n element = element.parentElement.closest(`[${htmlExtAttr.componentType}]`);\n }\n const nodeId = useHtmlExtAttr.nodeId(element);\n const componentMeta = useHtmlExtAttr.componentMeta(element, this.componentManage);\n if (nodeId && componentMeta) {\n // 按下的节点在选中集合中 -> 拖拽整个选中的节点集合(多选拖拽)\n const selections = this.designerEngine.activeDesignerState?.selections;\n if (selections && selections.some(selection => nodeId === selection.nodeId)) {\n selections.forEach(selection => {\n if (selection.nodeId && selection.componentMeta) {\n this.componentMetas.set(selection.nodeId, selection.componentMeta);\n }\n });\n } else {\n // 拖拽单个渲染节点\n this.componentMetas.set(nodeId, componentMeta);\n }\n }\n }\n if (this.componentMetas.size <= 0) return;\n // 设置拖拽状态\n this.dragState.startEvent = event;\n this.dragState.dragging = false;\n this.dragState.startDragTime = Date.now();\n // 主要依靠鼠标事件实现拖拽效果 | mouseup-鼠标弹起(停止拖拽处理) | mousemove-鼠标移动(开始拖拽处理)\n this.removeEventListener('mouseup', this.onMouseUp);\n this.addEventListener('mouseup', this.onMouseUp);\n this.removeEventListener('mousemove', this.onDistanceChange);\n this.addEventListener('mousemove', this.onDistanceChange);\n // 为了兼容html原生的拖拽事件 | dragend-拖放操作结束(停止拖拽处理) | dragstart-开始拖动(开始拖拽处理)\n this.removeEventListener('dragend', this.onMouseUp);\n this.addEventListener('dragend', this.onMouseUp);\n this.removeEventListener('dragstart', this.onStartDrag);\n this.addEventListener('dragstart', this.onStartDrag);\n }\n\n /**\n * 鼠标弹起事件,停止拖拽处理\n */\n onMouseUp = (event: MouseEvent): void => {\n // 如果还在拖拽状态就分发拖拽结束事件\n if (this.dragState.dragging) {\n this.eventbus.dispatch(new DragStopEvent(event));\n }\n // 取消事件监听\n this.removeEventListener('mouseup', this.onMouseUp);\n this.removeEventListener('mousemove', this.onMouseMove);\n this.removeEventListener('mousemove', this.onDistanceChange);\n this.removeEventListener('dragover', this.onMouseMove);\n this.removeEventListener('dragend', this.onMouseUp);\n this.removeEventListener('dragstart', this.onStartDrag);\n this.removeEventListener('contextmenu', this.preventDefault, true);\n // 设置停止拖拽\n this.dragState.dragging = false;\n }\n\n /**\n * 鼠标移动,开始拖拽处理\n * 移动超过 4px 且按住超过 10ms 才认为开始拖拽(避免误触发)\n */\n onDistanceChange = (event: MouseEvent): void => {\n const startDragTime = this.dragState.startDragTime;\n const startEvent = this.dragState.startEvent;\n // 没有对应的状态值,直接返回\n if (Typeof.noValue(startDragTime) || Typeof.noValue(startEvent)) return;\n // 计算移动的距离和时间\n const distance = calcDistance(event.pageX, event.pageY, startEvent.pageX, startEvent.pageY);\n const timeDelta = Date.now() - startDragTime;\n // 如果是:事件对象不同、两次触发事件超过10毫秒、鼠标移动超过了4个像素,才执行逻辑\n if (event !== startEvent && timeDelta > 10 && distance > 4) {\n // 先停止 onDistanceChange 的监听\n this.removeEventListener('mousemove', this.onDistanceChange);\n // 触发开始拖拽事件\n this.onStartDrag(event);\n }\n }\n\n /**\n * 鼠标移动中 或者 拖拽中,触发开始拖拽事件\n */\n onStartDrag = (event: MouseEvent | DragEvent): void => {\n // 如果已经在拖拽中了,直接返回\n if (this.dragState.dragging) return;\n // 设置开始拖拽事件\n this.dragState.startEvent = this.dragState.startEvent || (event as MouseEvent);\n // 拖拽过程中阻止用户打开右键菜单\n this.removeEventListener('contextmenu', this.preventDefault, true);\n this.addEventListener('contextmenu', this.preventDefault, true);\n // 主要依靠鼠标事件实现拖拽效果 | mousemove-鼠标移动时(分发拖拽中事件)\n this.removeEventListener('mousemove', this.onMouseMove);\n this.addEventListener('mousemove', this.onMouseMove);\n // 为了兼容html原生的拖拽事件 | dragover-被拖进一个有效的放置目标时(分发拖拽中事件)\n this.removeEventListener('dragover', this.onMouseMove);\n this.addEventListener('dragover', this.onMouseMove);\n // 分发开始拖拽事件\n this.eventbus.dispatch(new DragStartEvent(this.dragState.startEvent, this.componentMetas));\n this.dragState.dragging = true;\n }\n\n /**\n * 鼠标移动中 或者 拖拽中,分发自定义的拖拽事件\n */\n onMouseMove = (event: MouseEvent | DragEvent): void => {\n // 位置相对于上次未变化,直接返回\n if (event.clientX === this.dragState.moveEvent?.clientX && event.clientY === this.dragState.moveEvent?.clientY) {\n return;\n }\n // 分发拖拽中事件\n this.eventbus.dispatch(new DragMoveEvent(event as MouseEvent));\n // 设置拖拽中事件对象\n this.dragState.moveEvent = event;\n }\n}\n\nexport {\n DragDropDriver,\n}\n","import { DesignerDriver } from \"../core/DesignerDriver\";\nimport { ShortcutKeyEvent } from \"../events/keyboard/ShortcutKeyEvent\";\n\n/**\n * 键盘事件驱动: 直接监听 keydown/keyup, 零第三方依赖;\n * 只分发 ShortcutKeyEvent 不绑定具体快捷键动作, 订阅者根据 ctrlKey/key 等字段自行匹配并执行\n */\nclass KeyboardDriver extends DesignerDriver {\n /** 当前按下的物理按键集合(小写) */\n protected readonly pressedKeys: Set<string> = new Set();\n\n attach(): void {\n this.addEventListener('keydown', this.onKeyEvent);\n this.addEventListener('keyup', this.onKeyEvent);\n // 窗口失焦时收不到 keyup, 清空按键状态\n // (否则 ctrl 状态残留, 之后点击画布会意外变成多选)\n this.window.addEventListener(\"blur\", this.onBlur);\n }\n\n detach(): void {\n this.removeEventListener('keydown', this.onKeyEvent);\n this.removeEventListener('keyup', this.onKeyEvent);\n this.window.removeEventListener(\"blur\", this.onBlur);\n // 重置按键状态\n this.resetKeyState();\n }\n\n /** 窗口失焦: 清空按键状态 */\n onBlur = (): void => {\n this.resetKeyState();\n }\n\n /** 重置按键状态 */\n protected resetKeyState(): void {\n this.pressedKeys.clear();\n this.designerEngine.onlyPressedCtrl = false;\n this.designerEngine.onlyPressedShift = false;\n }\n\n onKeyEvent = (event: KeyboardEvent): void => {\n const key = event.key.toLowerCase();\n // 维护按下的物理按键集合\n if (event.type === \"keydown\") {\n this.pressedKeys.add(key);\n } else {\n this.pressedKeys.delete(key);\n }\n // 维护\"仅仅按下 ctrl/shift 键\"的状态(多键按下时都不是\"仅按下\")\n this.designerEngine.onlyPressedCtrl = this.pressedKeys.size === 1 && this.pressedKeys.has(\"control\");\n this.designerEngine.onlyPressedShift = this.pressedKeys.size === 1 && this.pressedKeys.has(\"shift\");\n // 分发快捷键事件\n this.eventbus.dispatch(new ShortcutKeyEvent(event, this.pressedKeys));\n }\n}\n\nexport {\n KeyboardDriver,\n}\n","import { DesignerDriver } from \"../core/DesignerDriver\";\nimport { MouseClickEvent } from \"../events/cursor/MouseClickEvent\";\nimport { MouseDoubleClickEvent } from \"../events/cursor/MouseDoubleClickEvent\";\n\n/**\n * 鼠标点击事件驱动\n * 仅分发设计器画布区域(designerContent 选择器匹配的元素)内的点击事件\n * 产生的业务事件: MouseClickEvent、MouseDoubleClickEvent\n */\nclass MouseClickDriver extends DesignerDriver {\n attach(): void {\n this.addEventListener('click', this.onMouseClick);\n this.addEventListener('dblclick', this.onMouseDoubleClick);\n }\n\n detach(): void {\n this.removeEventListener('click', this.onMouseClick);\n this.removeEventListener('dblclick', this.onMouseDoubleClick);\n }\n\n onMouseClick = (event: MouseEvent): void => {\n const target = event.target as HTMLElement;\n if (!target?.closest) return;\n // 点击必须发生在设计器画布区域内\n const element = target.closest(this.designerEngine.props.designerContent);\n if (!element) return;\n this.eventbus.dispatch(new MouseClickEvent(event));\n }\n\n onMouseDoubleClick = (event: MouseEvent): void => {\n const target = event.target as HTMLElement;\n if (!target?.closest) return;\n // 双击必须发生在设计器画布区域内\n const element = target.closest(this.designerEngine.props.designerContent);\n if (!element) return;\n this.eventbus.dispatch(new MouseDoubleClickEvent(event));\n }\n}\n\nexport {\n MouseClickDriver,\n}\n","import { DesignerDriver } from \"../core/DesignerDriver\";\nimport { MouseMoveEvent } from \"../events/cursor/MouseMoveEvent\";\n\n/**\n * 鼠标移动事件驱动(rAF 节流)\n * 产生的业务事件: MouseMoveEvent\n */\nclass MouseMoveDriver extends DesignerDriver {\n private request?: number = undefined;\n\n attach(): void {\n this.addEventListener('mousemove', this.onMouseMove);\n }\n\n detach(): void {\n this.removeEventListener('mousemove', this.onMouseMove);\n this.cancelRequest();\n }\n\n onMouseMove = (event: MouseEvent): void => {\n // 丢弃上一帧还未执行的回调, 只分发最新一次的鼠标位置\n this.cancelRequest();\n this.request = requestAnimationFrame(() => {\n this.request = undefined;\n this.eventbus.dispatch(new MouseMoveEvent(event));\n });\n }\n\n protected cancelRequest(): void {\n if (this.request !== undefined) {\n cancelAnimationFrame(this.request);\n this.request = undefined;\n }\n }\n}\n\nexport {\n MouseMoveDriver,\n}\n","import { RequestIdle } from \"@ease-forge/shared\";\nimport { DesignerEffect } from \"../core/DesignerEffect\";\nimport { type CursorPosition, CursorStatus } from \"../types/Designer\";\nimport { DragStartEvent } from \"../events/cursor/DragStartEvent\";\nimport { DragMoveEvent } from \"../events/cursor/DragMoveEvent\";\nimport { DragStopEvent } from \"../events/cursor/DragStopEvent\";\nimport { MouseMoveEvent } from \"../events/cursor/MouseMoveEvent\";\n\n/**\n * 光标状态维护效果\n * 消费拖拽/鼠标移动事件, 维护 Cursor 模型的状态与位置\n */\nclass CursorEffect extends DesignerEffect {\n /** 原始的鼠标指针样式(拖拽结束后恢复) */\n private originalCursor: string = \"\";\n /** 取消订阅函数集合 */\n private readonly unsubscribes: Array<() => void> = [];\n\n protected onEffect(): void {\n this.dragDropCursor();\n this.mouseMoveCursor();\n }\n\n protected onDestroy(): void {\n this.unsubscribes.forEach(unsubscribe => unsubscribe());\n this.unsubscribes.length = 0;\n // 恢复容器光标样式\n if (this.originalCursor) {\n this.setContainerCursorStyle(this.originalCursor);\n this.originalCursor = \"\";\n }\n }\n\n /**\n * 从事件数据中提取坐标字段\n * 事件数据还携带 componentMetas/target/view 等成员, 不应存进光标模型\n */\n protected toCursorPosition(data: any): CursorPosition {\n return {\n clientX: data?.clientX ?? 0,\n clientY: data?.clientY ?? 0,\n pageX: data?.pageX ?? 0,\n pageY: data?.pageY ?? 0,\n topClientX: data?.topClientX ?? 0,\n topClientY: data?.topClientY ?? 0,\n topPageX: data?.topPageX ?? 0,\n topPageY: data?.topPageY ?? 0,\n };\n }\n\n /**\n * 拖拽时的 cursor 状态维护\n */\n protected dragDropCursor(): void {\n // 开始拖动\n this.unsubscribes.push(\n this.eventbus.subscribe(DragStartEvent, event => {\n this.originalCursor = this.getContainerCursorStyle();\n const cursor = this.designerEngine.cursor;\n cursor.status = CursorStatus.DragStart;\n cursor.dragStartPosition = this.toCursorPosition(event.data);\n }),\n // 拖动中\n this.eventbus.subscribe(DragMoveEvent, event => {\n const cursor = this.designerEngine.cursor;\n cursor.status = CursorStatus.Dragging;\n cursor.position = this.toCursorPosition(event.data);\n RequestIdle.requestIdle(() => {\n this.setContainerCursorStyle('move');\n });\n }),\n // 拖拽结束\n this.eventbus.subscribe(DragStopEvent, event => {\n const cursor = this.designerEngine.cursor;\n cursor.status = CursorStatus.DragStop;\n cursor.dragEndPosition = this.toCursorPosition(event.data);\n cursor.dragStartPosition = undefined;\n cursor.status = CursorStatus.Normal;\n RequestIdle.requestIdle(() => this.setContainerCursorStyle(this.originalCursor));\n }),\n );\n }\n\n /**\n * 鼠标移动时的 cursor 状态维护\n */\n protected mouseMoveCursor(): void {\n // 鼠标移动\n this.unsubscribes.push(\n this.eventbus.subscribe(MouseMoveEvent, event => {\n const cursor = this.designerEngine.cursor;\n if (![CursorStatus.Dragging, CursorStatus.DragStart].includes(cursor.status)) {\n cursor.status = CursorStatus.Normal;\n }\n if (cursor.status === CursorStatus.Dragging) return;\n cursor.position = this.toCursorPosition(event.data);\n }),\n );\n }\n}\n\nexport {\n CursorEffect,\n}\n","import type { ComponentMeta } from \"@ease-forge/runtime\";\nimport { htmlExtAttr } from \"@ease-forge/runtime\";\nimport { DesignerEffect } from \"../core/DesignerEffect\";\nimport { calcAuxToolPosition } from \"../utils/PositionCalc\";\nimport type { AuxToolPosition } from \"../types/Designer\";\nimport { DragStartEvent } from \"../events/cursor/DragStartEvent\";\nimport { DragStopEvent } from \"../events/cursor/DragStopEvent\";\nimport { DragDropEvent } from \"../events/designer/DragDropEvent\";\n\n/**\n * 拖拽状态维护效果: 只维护拖拽状态(DraggingCmpMetas),\n * 放下时分发 DragDropEvent, 节点的移动/插入由操作命令层订阅 DragDropEvent 后以命令方式执行\n */\nclass DraggingEffect extends DesignerEffect {\n /** 取消订阅函数集合 */\n private readonly unsubscribes: Array<() => void> = [];\n\n protected onEffect(): void {\n this.draggingCmpMetasEffect();\n }\n\n protected onDestroy(): void {\n this.unsubscribes.forEach(unsubscribe => unsubscribe());\n this.unsubscribes.length = 0;\n this.designerEngine.draggingCmpMetas.clear();\n }\n\n /**\n * 维护正在拖拽的组件元信息\n */\n protected draggingCmpMetasEffect(): void {\n this.unsubscribes.push(\n // 开始拖动: 填充拖拽状态\n this.eventbus.subscribe(DragStartEvent, event => {\n const componentMetas = event.data?.componentMetas;\n if (!componentMetas || componentMetas.size <= 0) return;\n const draggingCmpMetas = this.designerEngine.draggingCmpMetas;\n const cmpMetas: Array<ComponentMeta> = [];\n const nodeIds: Array<string> = [];\n const positions: Array<AuxToolPosition> = [];\n const designerContainer = this.designerEngine.activeDesignerState?.designerContainer;\n componentMetas.forEach((meta, nodeId) => {\n cmpMetas.push(meta);\n nodeIds.push(nodeId);\n // 基于画布DOM计算被拖拽节点的区域位置\n if (designerContainer) {\n const element = designerContainer.querySelector(`[${htmlExtAttr.nodeId}=${nodeId}]`);\n if (element) positions.push(calcAuxToolPosition(designerContainer, element));\n }\n });\n draggingCmpMetas.cmpMetas = cmpMetas;\n draggingCmpMetas.nodeIds = nodeIds;\n draggingCmpMetas.positions = positions;\n }, 100),\n // 拖拽结束: 分发拖拽放下事件(带插入位置信息), 并清空拖拽状态\n // 注意: priority=100 保证在 AuxToolEffect(默认0)之后执行, 此时 insertion 已存入 draggingCmpMetas\n this.eventbus.subscribe(DragStopEvent, event => {\n const draggingCmpMetas = this.designerEngine.draggingCmpMetas;\n if (!draggingCmpMetas.existsCmpMeta) return;\n // 分发给操作命令层(阶段4)执行节点的移动/插入命令\n this.eventbus.dispatch(new DragDropEvent({\n componentMetas: [...draggingCmpMetas.cmpMetas],\n nodeIds: [...draggingCmpMetas.nodeIds],\n cursor: event.data!,\n // 插入位置信息(AuxToolEffect 在 DragStop 时已存入 draggingCmpMetas.insertion)\n insertion: draggingCmpMetas.insertion,\n }));\n // 清空拖拽状态\n draggingCmpMetas.clear();\n }, 100),\n );\n }\n}\n\nexport {\n DraggingEffect,\n}\n","import { Typeof } from \"@ease-forge/shared\";\nimport type { ComponentMeta } from \"@ease-forge/runtime\";\n\n/**\n * 校验组件是否允许拖拽到指定的父组件中(基于 ComponentMeta.dragDropConfig)\n * @param cmpMeta 被拖拽组件元数据\n * @param parentCmpMeta 父级组件元数据\n * @param slotName 被拖拽到父组件的插槽位置\n * @param element 父级组件 Element 对象\n */\nfunction isAllowDrag(cmpMeta: ComponentMeta, parentCmpMeta: ComponentMeta, slotName: string, element: Element): boolean {\n if (!cmpMeta.dragDropConfig) return true;\n const parentType = parentCmpMeta.type;\n const {\n whiteList,\n blacklist,\n isAllow,\n } = cmpMeta.dragDropConfig;\n if (Typeof.hasValue(whiteList)) {\n if (!whiteList.includes(parentType)) {\n return false;\n }\n }\n if (Typeof.hasValue(blacklist)) {\n if (blacklist.includes(parentType)) {\n return false;\n }\n }\n if (Typeof.isFunction(isAllow)) {\n if (!isAllow(cmpMeta, parentCmpMeta, slotName, element)) {\n return false;\n }\n }\n return true;\n}\n\nexport {\n isAllowDrag,\n}\n","import lodash from \"lodash\";\nimport { RequestIdle } from \"@ease-forge/shared\";\nimport { deepTraverseRuntimeNode, htmlExtAttr, type RuntimeNode, useHtmlExtAttr } from \"@ease-forge/runtime\";\nimport { DesignerEffect } from \"../core/DesignerEffect\";\nimport { type NodeToCursorDistance, PointDirection } from \"../types/Designer\";\nimport { calcAuxToolPosition, calcNodeToCursorDistance } from \"../utils/PositionCalc\";\nimport { existsPlaceholder } from \"../utils/ComponentMetaUtils\";\nimport { isAllowDrag } from \"../utils/DesignerUtils\";\nimport { MouseMoveEvent } from \"../events/cursor/MouseMoveEvent\";\nimport { MouseClickEvent } from \"../events/cursor/MouseClickEvent\";\nimport { DragMoveEvent } from \"../events/cursor/DragMoveEvent\";\nimport { DragStopEvent } from \"../events/cursor/DragStopEvent\";\nimport type { DesignerState } from \"../models/DesignerState\";\nimport { Selection } from \"../models/Selection\";\n\ninterface NodeAndDesigner {\n /** 渲染节点dom */\n node: HTMLElement;\n /** 设计器画布容器dom */\n designer: HTMLElement;\n}\n\n/**\n * 设计器辅助效果: 悬停虚线、节点选中、插入位置计算\n */\nclass AuxToolEffect extends DesignerEffect {\n /** hover变化一次的最小时间间隔(毫秒) */\n private readonly minHoverChangeTime = 50;\n /** 最后一次的 event.data.target 对象 */\n private lastEventTarget: EventTarget | undefined;\n /** 最后一次鼠标移动事件时间 */\n private lastMouseMoveTime = 0;\n /** 最后一次触发 DragStopEvent 的时间 */\n private lastDragStopEventTime = 0;\n /** 取消订阅函数集合 */\n private readonly unsubscribes: Array<() => void> = [];\n\n protected onEffect(): void {\n this.hoverDashedEffect();\n this.selectionEffect();\n this.insertionEffect();\n }\n\n protected onDestroy(): void {\n this.unsubscribes.forEach(unsubscribe => unsubscribe());\n this.unsubscribes.length = 0;\n this.lastEventTarget = undefined;\n }\n\n /** 依据事件 target 找出\"渲染节点 + 画布容器\" */\n protected getNodeAndDesigner(designerState: DesignerState, target?: HTMLElement): NodeAndDesigner | undefined {\n if (!target?.closest) return;\n let container: HTMLElement | undefined = designerState.designerContainer;\n if (!container) container = target.closest(this.designerEngine.props.designerContent) as HTMLElement | undefined;\n if (!container) return;\n // 悬停目标必须是渲染节点(带 nodeRef 标记), 且不是占位组件\n const element = target.closest(`[${htmlExtAttr.nodeRef}]:not([${htmlExtAttr.placeholderName}])`) as HTMLElement | null;\n if (!element) return;\n return { node: element, designer: container };\n }\n\n /** 获取垂直方向的最小距离(光标在内部时返回 -1) */\n protected getVerticalDistance(distance: NodeToCursorDistance): number {\n if (distance.vInside) return -1;\n return Math.min(distance.top, distance.bottom);\n }\n\n /** 获取水平方向的最小距离(光标在内部时返回 -1) */\n protected getHorizontalDistance(distance: NodeToCursorDistance): number {\n if (distance.hInside) return -1;\n return Math.min(distance.left, distance.right);\n }\n\n /**\n * 设置插入位置信息(包含 DragDropConfig 校验)\n */\n protected setInsertion(designerState: DesignerState, containerId: string, distance: NodeToCursorDistance, placeholder: string = \"\"): void {\n let designerContainer: Element | null = designerState.designerContainer ?? null;\n if (!designerContainer) designerContainer = distance.element.closest(this.designerEngine.props.designerContent);\n if (!designerContainer) return;\n this.designerEngine.insertion.clear();\n const isPlaceholder = lodash.trim(placeholder).length > 0;\n let nodeId: string;\n let slotName: string;\n if (isPlaceholder) {\n // 拖到占位组件上: 插入目标是占位组件所属的容器节点与其插槽\n nodeId = containerId;\n slotName = placeholder;\n } else {\n nodeId = useHtmlExtAttr.nodeId(distance.element)!;\n slotName = useHtmlExtAttr.slotName(distance.element)!;\n }\n // 拖拽目标不能是自己或自己的子节点\n if (this.nodeIsSelfOrInside(nodeId, this.designerEngine.draggingCmpMetas.nodeIds)) {\n return;\n }\n const container = distance.element.closest(`[${htmlExtAttr.nodeId}=${containerId}]`);\n if (!container) {\n return;\n }\n const parentCmpMeta = useHtmlExtAttr.componentMeta(container, this.componentManage);\n if (!parentCmpMeta) {\n return;\n }\n // DragDropConfig 白名单/黑名单/自定义校验\n const cmpMetas = this.designerEngine.draggingCmpMetas.cmpMetas;\n const notAllowDrag = cmpMetas.some(cmpMeta => !isAllowDrag(cmpMeta, parentCmpMeta, slotName, container));\n if (notAllowDrag) return;\n // 走到这里必然通过了拖拽校验\n this.designerEngine.insertion.allowDrag = true;\n this.designerEngine.insertion.distance = distance;\n this.designerEngine.insertion.position = calcAuxToolPosition(designerContainer, distance.element);\n this.designerEngine.insertion.nodeId = nodeId;\n this.designerEngine.insertion.containerId = containerId;\n this.designerEngine.insertion.slotName = slotName;\n this.designerEngine.insertion.placeholder = isPlaceholder;\n }\n\n /** 判断 nodeId 是否在 ids 集合中或集合节点的子树中 */\n protected nodeIsSelfOrInside(nodeId: string, ids: Array<string>): boolean {\n if (ids.includes(nodeId)) return true;\n const blockInstance = this.designerEngine.activeDesignerState?.blockInstance;\n if (blockInstance) {\n const allIds: Set<string> = new Set<string>();\n for (const id of ids) {\n const runtimeNode = blockInstance.globalContext.allNode[id];\n if (!runtimeNode) continue;\n deepTraverseRuntimeNode(runtimeNode, current => allIds.add(current.id));\n }\n return allIds.has(nodeId);\n }\n return false;\n }\n\n /**\n * 鼠标悬停时的虚线框\n */\n protected hoverDashedEffect(): void {\n this.unsubscribes.push(\n this.eventbus.subscribe(MouseMoveEvent, event => {\n const now = Date.now();\n // target dom 没有变\n if (event.data!.target === this.lastEventTarget) {\n this.lastMouseMoveTime = now;\n return;\n }\n const interval = now - this.lastMouseMoveTime;\n if (interval < this.minHoverChangeTime) return;\n this.lastMouseMoveTime = now;\n // 在浏览器空闲时期计算\n RequestIdle.requestIdle(() => {\n const designerState = this.designerEngine.activeDesignerState;\n if (!designerState) return;\n const hover = designerState.hover;\n const target = event.data!.target as HTMLElement;\n const nodeAndDesigner = this.getNodeAndDesigner(designerState, target);\n if (!nodeAndDesigner) return;\n const nodeId = useHtmlExtAttr.nodeId(nodeAndDesigner.node);\n // 已选中的节点不显示悬停虚线\n if (designerState.selections.some(item => item.nodeId === nodeId)) {\n hover.clear();\n return;\n }\n hover.componentMeta = useHtmlExtAttr.componentMeta(nodeAndDesigner.node, this.componentManage);\n hover.nodeId = nodeId;\n hover.position = calcAuxToolPosition(nodeAndDesigner.designer, nodeAndDesigner.node);\n this.lastEventTarget = event.data!.target;\n });\n }),\n );\n }\n\n /**\n * 鼠标单击选中节点(支持 Ctrl 多选)\n */\n protected selectionEffect(): void {\n this.unsubscribes.push(\n this.eventbus.subscribe(MouseClickEvent, event => {\n // 刚结束拖拽的 click 不触发选中\n if (Date.now() - this.lastDragStopEventTime <= 30) return;\n const designerState = this.designerEngine.activeDesignerState;\n if (!designerState) return;\n const target = event.data!.target as HTMLElement;\n const nodeAndDesigner = this.getNodeAndDesigner(designerState, target);\n if (!nodeAndDesigner) return;\n const hover = designerState.hover;\n const selections = designerState.selections;\n const selection = new Selection(designerState);\n selection.nodeId = useHtmlExtAttr.nodeId(nodeAndDesigner.node);\n selection.parentId = useHtmlExtAttr.nodeParentId(nodeAndDesigner.node);\n if (selections.some(item => item.nodeId === selection.nodeId)) return;\n selection.componentMeta = useHtmlExtAttr.componentMeta(nodeAndDesigner.node, this.componentManage);\n selection.position = calcAuxToolPosition(nodeAndDesigner.designer, nodeAndDesigner.node);\n // 没有按下 Ctrl 就替换选中集合\n if (!this.designerEngine.onlyPressedCtrl) selections.length = 0;\n selections.push(selection);\n if (hover.nodeId && selections.some(item => item.nodeId === hover.nodeId)) {\n hover.clear();\n }\n }),\n );\n }\n\n /**\n * 拖拽过程中计算插入位置(找离光标最近的容器节点与插入点)\n */\n protected insertionEffect(): void {\n this.unsubscribes.push(\n // 拖动中: 计算插入位置\n this.eventbus.subscribe(DragMoveEvent, event => {\n const draggingCmpMetas = this.designerEngine.draggingCmpMetas;\n if (!draggingCmpMetas.existsCmpMeta) return;\n let target = event.data!.target as Element | null;\n if (!target) return;\n RequestIdle.requestIdle(() => {\n // 光标不在画布区域内直接返回\n if (!target?.closest || !target.closest(this.designerEngine.props.designerContent)) {\n this.designerEngine.insertion.clear();\n return;\n }\n const designerState = this.designerEngine.activeDesignerState;\n if (!designerState?.designerContainer) return;\n const designerBlock = designerState.blockInstance;\n if (!designerBlock) return;\n // event.data.target 属于占位组件 -> 覆盖整个容器节点\n const placeholder = useHtmlExtAttr.placeholderName(target);\n if (placeholder) {\n const distance = calcNodeToCursorDistance(event.data!, event.data!.target as Element);\n const nodeParentId = useHtmlExtAttr.nodeParentId(distance.element);\n if (nodeParentId) {\n this.setInsertion(designerState, nodeParentId, distance, placeholder);\n return;\n }\n }\n // 找出离当前鼠标位置最近的容器组件(带占位插槽的节点)\n let containerNode: Element | null = null;\n let containerId: string | undefined;\n while (true) {\n if (!target) return;\n containerNode = target.closest(`[${htmlExtAttr.nodeId}]`);\n if (!containerNode) return;\n containerId = useHtmlExtAttr.nodeId(containerNode);\n if (!containerId) return;\n const runtimeNode: RuntimeNode | undefined = designerBlock.globalContext.allNode[containerId];\n if (!runtimeNode) return;\n const isContainer = existsPlaceholder(runtimeNode.designExt?.designPlaceholder);\n if (isContainer) {\n break;\n } else {\n // 继续向上找父级容器\n if (target === containerNode) {\n target = containerNode.parentElement;\n } else {\n target = containerNode;\n }\n }\n }\n if (!containerNode || !containerId) return;\n // event.data.target 就是渲染容器节点本身(容器内的空白区域)\n if (containerNode === event.data!.target) {\n const distance = calcNodeToCursorDistance(event.data!, containerNode);\n const minDistance = Math.min(distance.top, distance.bottom, distance.left, distance.right);\n if (minDistance <= 12) {\n const nodeParentId = useHtmlExtAttr.nodeParentId(distance.element);\n if (nodeParentId) {\n this.setInsertion(designerState, nodeParentId, distance);\n return;\n }\n }\n }\n // 查找当前容器组件中所有 items 和 slots 位置渲染的节点\n const nodes = containerNode.querySelectorAll(`[${htmlExtAttr.nodeParentId}=${containerId}]`);\n const distances: Array<NodeToCursorDistance> = [];\n nodes.forEach(node => distances.push(calcNodeToCursorDistance(event.data!, node)));\n if (distances.length <= 0) return;\n // 先过滤出垂直方向最近的节点, 再过滤出水平方向最近的节点\n const minVertical = lodash.min(distances.map(distance => this.getVerticalDistance(distance)))!;\n const verticalDistances = distances.filter(distance => this.getVerticalDistance(distance) <= minVertical);\n const minHorizontal = lodash.min(verticalDistances.map(distance => this.getHorizontalDistance(distance)))!;\n const horizontalDistances = verticalDistances.filter(distance => this.getHorizontalDistance(distance) <= minHorizontal);\n // 最后按离光标最近的角计算插入点\n const minDistance = lodash.minBy(horizontalDistances, distance => {\n if (distance.bothInside) return -1;\n if (distance.point === PointDirection.leftTop) return distance.leftTop;\n if (distance.point === PointDirection.leftBottom) return distance.leftBottom;\n if (distance.point === PointDirection.rightTop) return distance.rightTop;\n if (distance.point === PointDirection.rightBottom) return distance.rightBottom;\n return Number.MAX_VALUE;\n })!;\n // 计算结果赋值\n this.setInsertion(designerState, containerId, minDistance);\n });\n }),\n // 拖拽结束: 把插入位置信息存入拖拽状态(供 DragDropEvent 消费), 并清除插入状态\n this.eventbus.subscribe(DragStopEvent, () => {\n this.lastDragStopEventTime = Date.now();\n const insertion = this.designerEngine.insertion;\n const draggingCmpMetas = this.designerEngine.draggingCmpMetas;\n draggingCmpMetas.insertion = insertion.getInsertionData();\n RequestIdle.requestIdle(() => insertion.clear());\n }),\n );\n }\n}\n\nexport {\n AuxToolEffect,\n}\n","import { Typeof } from \"@ease-forge/shared\";\nimport { type BlockInstance, childSlotName, type DesignNode, type RuntimeComponentSlotsItem, type RuntimeNode } from \"@ease-forge/runtime\";\n\n/** 节点定位类型 */\ntype InsertPosition = \"before\" | \"after\" | \"first\" | \"last\";\n\n/**\n * 节点插入目标位置\n * 统一描述\"放到哪个容器的哪个位置\", 由 applyXXX 函数映射到 runtime BlockOperation 的具体方法\n */\ninterface InsertTarget {\n /** 容器节点id(RuntimeNode.id) */\n parentId: string;\n /** 插槽名称(子节点集合是特殊的插槽, 名为 default) */\n slotName: string;\n /** 定位类型 */\n position: InsertPosition;\n /** 定位节点id(position 为 before/after 时有效) */\n positionId?: string;\n}\n\n/**\n * 读取节点当前所在的插入位置(用于 undo 时恢复节点原位置)\n * 返回 undefined 表示节点不存在或没有父节点(根节点)\n */\nfunction getNodeInsertTarget(blockInstance: BlockInstance, nodeId: string): InsertTarget | undefined {\n const node = blockInstance.globalContext.allNode[nodeId];\n if (!node) return;\n const parent = blockInstance.globalContext.nodeParent[nodeId];\n if (!parent) return;\n // 在父节点的 items 与各个插槽中查找当前节点的位置\n const findIn = (arr: Array<RuntimeComponentSlotsItem>, slotName: string): InsertTarget | undefined => {\n const idx = arr.findIndex(item => Typeof.isObj(item) && !Typeof.isArray(item) && (item as RuntimeNode).id === nodeId);\n if (idx < 0) return;\n if (idx > 0) {\n // 用\"前一个兄弟节点之后\"定位(多节点按顺序恢复时, 前兄弟总是已就位)\n const prev = arr[idx - 1];\n if (Typeof.isObj(prev) && !Typeof.isArray(prev)) {\n return { parentId: parent.id, slotName, position: \"after\", positionId: (prev as RuntimeNode).id };\n }\n }\n return { parentId: parent.id, slotName, position: \"first\" };\n };\n const target = findIn(parent.items, childSlotName);\n if (target) return target;\n for (const slotName in parent.slots) {\n const target = findIn(parent.slots[slotName], slotName);\n if (target) return target;\n }\n return;\n}\n\n/**\n * 计算节点在其父容器子节点集合中的索引\n * 用于多节点 undo 恢复时按删除/移动前的文档顺序依次还原\n * (返回 -1 表示节点不存在或没有父节点)\n */\nfunction getNodeDocIndex(blockInstance: BlockInstance, nodeId: string): number {\n const node = blockInstance.globalContext.allNode[nodeId];\n if (!node) return -1;\n const parent = blockInstance.globalContext.nodeParent[nodeId];\n if (!parent) return -1;\n const findIn = (arr: Array<RuntimeComponentSlotsItem>): number => arr.findIndex(\n item => Typeof.isObj(item) && !Typeof.isArray(item) && (item as RuntimeNode).id === nodeId,\n );\n const idx = findIn(parent.items);\n if (idx >= 0) return idx;\n for (const slotName in parent.slots) {\n const idx = findIn(parent.slots[slotName]);\n if (idx >= 0) return idx;\n }\n return -1;\n}\n\n/**\n * 校验并修正插入目标\n * undo/redo 会让\"删除后恢复\"的节点产生新的id(runtime 添加时自动分配),\n * 命令中记录的定位节点id可能已失效:\n * - 定位节点(positionId)不存在 -> 降级为容器末尾(位置略有偏差但命令语义仍然成立)\n * - 容器节点(parentId)不存在 -> 返回 null 表示目标完全失效\n */\nfunction fixInsertTarget(blockInstance: BlockInstance, target: InsertTarget): InsertTarget | null {\n const { allNode } = blockInstance.globalContext;\n if (!allNode[target.parentId]) return null;\n if ((target.position === \"before\" || target.position === \"after\") && target.positionId && !allNode[target.positionId]) {\n return { parentId: target.parentId, slotName: target.slotName, position: \"last\" };\n }\n return target;\n}\n\n/**\n * 应用插入目标: 移动已有节点\n * @return 是否成功\n */\nfunction applyMoveNodes(blockInstance: BlockInstance, target: InsertTarget, moveNodeIds: Array<string>): boolean {\n const fixedTarget = fixInsertTarget(blockInstance, target);\n if (!fixedTarget) return false;\n const ops = blockInstance.opsById;\n const moveIds = moveNodeIds.filter(id => blockInstance.globalContext.allNode[id]);\n if (moveIds.length <= 0) return false;\n target = fixedTarget;\n const isChildItems = target.slotName === childSlotName;\n if (isChildItems) {\n switch (target.position) {\n case \"before\": return target.positionId ? ops.moveNodesToItemBeforeById(target.positionId, moveNodeIds) : false;\n case \"after\": return target.positionId ? ops.moveNodesToItemAfterById(target.positionId, moveNodeIds) : false;\n case \"first\": return ops.moveNodesToItemFirstById(target.parentId, moveNodeIds);\n case \"last\": return ops.moveNodesToItemLastById(target.parentId, moveNodeIds);\n }\n }\n switch (target.position) {\n case \"before\": return target.positionId ? ops.moveNodesToSlotBeforeById(target.positionId, target.slotName, moveNodeIds) : false;\n case \"after\": return target.positionId ? ops.moveNodesToSlotAfterById(target.positionId, target.slotName, moveNodeIds) : false;\n case \"first\": return ops.moveNodesToSlotFirstById(target.parentId, target.slotName, moveNodeIds);\n case \"last\": return ops.moveNodesToSlotLastById(target.parentId, target.slotName, moveNodeIds);\n }\n}\n\n/**\n * 应用插入目标: 添加新节点\n * @return 新增的节点集合(添加失败返回空数组)\n */\nfunction applyAddNodes(blockInstance: BlockInstance, target: InsertTarget, nodes: Array<DesignNode>): Array<RuntimeComponentSlotsItem> {\n const fixedTarget = fixInsertTarget(blockInstance, target);\n if (!fixedTarget) return [];\n target = fixedTarget;\n const ops = blockInstance.opsById;\n const isChildItems = target.slotName === childSlotName;\n if (isChildItems) {\n switch (target.position) {\n case \"before\": return target.positionId ? ops.beforeAddItemsById(target.positionId, nodes) : [];\n case \"after\": return target.positionId ? ops.afterAddItemsById(target.positionId, nodes) : [];\n case \"first\": return ops.firstAddItemsById(target.parentId, nodes);\n case \"last\": return ops.appendItemsById(target.parentId, nodes);\n }\n }\n switch (target.position) {\n case \"before\": return target.positionId ? ops.beforeAddSlotsById(target.positionId, target.slotName, nodes) : [];\n case \"after\": return target.positionId ? ops.afterAddSlotsById(target.positionId, target.slotName, nodes) : [];\n case \"first\": return ops.firstAddSlotsById(target.parentId, target.slotName, nodes);\n case \"last\": return ops.appendSlotsById(target.parentId, target.slotName, nodes);\n }\n}\n\n/**\n * 把 DropEvent 的 insertion 数据转换成插入目标\n */\nfunction insertionToTarget(insertion: { containerId: string; slotName: string; nodeId: string; placeholder: boolean; before: boolean }): InsertTarget {\n if (insertion.placeholder) {\n // 放在占位组件上: 整个容器插槽的第一个位置\n return { parentId: insertion.containerId, slotName: insertion.slotName, position: \"first\" };\n }\n // 放在兄弟节点的前/后\n return {\n parentId: insertion.containerId,\n slotName: insertion.slotName,\n position: insertion.before ? \"before\" : \"after\",\n positionId: insertion.nodeId,\n };\n}\n\n/**\n * 从添加结果中提取 RuntimeNode 集合(过滤掉字符串等非节点项)\n */\nfunction toRuntimeNodes(items: Array<RuntimeComponentSlotsItem>): Array<RuntimeNode> {\n return items.filter(item => Typeof.isObj(item) && !Typeof.isArray(item)) as Array<RuntimeNode>;\n}\n\nexport type {\n InsertPosition,\n InsertTarget,\n}\n\nexport {\n getNodeInsertTarget,\n getNodeDocIndex,\n applyMoveNodes,\n applyAddNodes,\n insertionToTarget,\n toRuntimeNodes,\n}\n","import type { DesignNode, RuntimeComponentSlotsItem, RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignCommand } from \"../../history/Command\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport type { InsertTarget } from \"../NodePosition\";\nimport { applyAddNodes, toRuntimeNodes } from \"../NodePosition\";\n\n/** 添加节点命令的选项 */\ninterface AddNodesCommandOptions {\n /** 添加的目标位置 */\n target: InsertTarget;\n /** 添加的节点配置集合 */\n nodes: Array<DesignNode>;\n /** 命令执行成功后的回调(参数是新增节点的id集合, 用于选中新节点) */\n onExecute?: (nodeIds: Array<string>) => void;\n}\n\n/**\n * 添加节点命令\n * 注意: undo 后 redo 会产生新的节点id(runtime 添加节点时自动生成id)\n */\nclass AddNodesCommand implements DesignCommand {\n readonly name: string;\n /** 所属的设计器页面状态(实时读取 blockInstance) */\n protected readonly designerState: DesignerState;\n protected readonly options: AddNodesCommandOptions;\n /** execute/redo 产生的新节点id集合(用于 undo 时删除) */\n protected addedNodeIds: Array<string> = [];\n\n constructor(designerState: DesignerState, name: string, options: AddNodesCommandOptions) {\n this.designerState = designerState;\n this.name = name;\n this.options = options;\n }\n\n execute(): boolean {\n return this.doAdd();\n }\n\n undo(): boolean {\n if (this.addedNodeIds.length <= 0) return false;\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n blockInstance.opsById.removeAllById(this.addedNodeIds);\n this.addedNodeIds = [];\n return true;\n }\n\n redo(): boolean {\n return this.doAdd();\n }\n\n /** 执行添加动作 */\n protected doAdd(): boolean {\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n const added: Array<RuntimeComponentSlotsItem> = applyAddNodes(blockInstance, this.options.target, this.options.nodes);\n const runtimeNodes: Array<RuntimeNode> = toRuntimeNodes(added);\n if (runtimeNodes.length <= 0) return false;\n this.addedNodeIds = runtimeNodes.map(node => node.id);\n this.options.onExecute?.(this.addedNodeIds);\n return true;\n }\n}\n\nexport type {\n AddNodesCommandOptions,\n}\n\nexport {\n AddNodesCommand,\n}\n","import type { DesignCommand } from \"../../history/Command\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport type { InsertTarget } from \"../NodePosition\";\nimport { applyMoveNodes, getNodeDocIndex, getNodeInsertTarget } from \"../NodePosition\";\n\n/** 移动节点命令的选项 */\ninterface MoveNodesCommandOptions {\n /** 移动的目标位置 */\n target: InsertTarget;\n /** 移动的节点id集合 */\n nodeIds: Array<string>;\n /** 命令执行成功后的回调 */\n onExecute?: () => void;\n}\n\n/** 节点原位置记录 */\ninterface OriginPosition {\n nodeId: string;\n /** 移动前的插入位置(用于 undo 恢复) */\n target: InsertTarget;\n /** 移动前在父容器子节点集合中的索引(undo 按此顺序恢复) */\n docIndex: number;\n}\n\n/**\n * 移动节点命令\n * undo 依据移动前记录的原位置逐个恢复:\n * 恢复顺序按移动前的文档顺序(docIndex)而非选中顺序 ——\n * 定位语义是\"插入到前一个兄弟节点之后\", 前兄弟必须先于依赖它的节点回到原位\n */\nclass MoveNodesCommand implements DesignCommand {\n readonly name: string;\n protected readonly designerState: DesignerState;\n protected readonly options: MoveNodesCommandOptions;\n /** 移动前的节点原位置记录 */\n protected originPositions: Array<OriginPosition> = [];\n\n constructor(designerState: DesignerState, name: string, options: MoveNodesCommandOptions) {\n this.designerState = designerState;\n this.name = name;\n this.options = options;\n }\n\n execute(): boolean {\n return this.doMove();\n }\n\n undo(): boolean {\n if (this.originPositions.length <= 0) return false;\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n // 按移动前的文档顺序恢复(前兄弟节点总是先就位)\n const sorted = [...this.originPositions].sort((a, b) => a.docIndex - b.docIndex);\n let success = false;\n for (const origin of sorted) {\n if (applyMoveNodes(blockInstance, origin.target, [origin.nodeId])) success = true;\n }\n return success;\n }\n\n redo(): boolean {\n return this.doMove();\n }\n\n /** 执行移动动作(首次执行时记录原位置) */\n protected doMove(): boolean {\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n const nodeIds = this.options.nodeIds.filter(id => blockInstance.globalContext.allNode[id]);\n if (nodeIds.length <= 0) return false;\n // 记录移动前的原位置(仅首次执行记录, redo 沿用)\n if (this.originPositions.length <= 0) {\n for (const nodeId of nodeIds) {\n const target = getNodeInsertTarget(blockInstance, nodeId);\n if (target) this.originPositions.push({ nodeId, target, docIndex: getNodeDocIndex(blockInstance, nodeId) });\n }\n if (this.originPositions.length <= 0) return false;\n }\n const success = applyMoveNodes(blockInstance, this.options.target, nodeIds);\n if (success) this.options.onExecute?.();\n return success;\n }\n}\n\nexport type {\n MoveNodesCommandOptions,\n}\n\nexport {\n MoveNodesCommand,\n}\n","import lodash from \"lodash\";\nimport { type DesignNode, htmlExtAttr, type RuntimeBlock, type RuntimeComponentSlotsItem, type RuntimeNode } from \"@ease-forge/runtime\";\n\n/** props 中需要剔除的 runtime 内部标记属性 */\nconst innerPropNames = new Set<string>([\n htmlExtAttr.componentType,\n htmlExtAttr.nodeId,\n htmlExtAttr.nodeRef,\n htmlExtAttr.nodeParentId,\n htmlExtAttr.placeholderName,\n htmlExtAttr.slotName,\n]);\n\n/**\n * 深拷贝但保留函数的原始引用\n * lodash.cloneDeep 会把函数克隆成空对象, 监听器 handler / Block 的 data、computed 等\n * 函数成员必须保留原引用, 否则删除命令 undo 恢复时事件与逻辑全部失效\n */\nfunction cloneKeepFunctions<T>(value: T): T {\n return lodash.cloneDeepWith(value, item => {\n if (lodash.isFunction(item)) return item;\n });\n}\n\n/**\n * 把 RuntimeNode 的 props 转换回 DesignNode 的 props\n * (剔除 runtime 写入 DOM 的标记属性)\n */\nfunction toDesignProps(props: Record<string, any>): Record<string, any> {\n const designProps: Record<string, any> = {};\n for (const name in props) {\n if (innerPropNames.has(name)) continue;\n designProps[name] = props[name];\n }\n return designProps;\n}\n\n/**\n * 把插槽/子节点集合中的项转换回 DesignNode 配置形态\n */\nfunction toDesignItems(items: Array<RuntimeComponentSlotsItem>): Array<any> {\n return items\n .filter(item => lodash.has(item, \"type\"))\n .map(item => {\n if (lodash.isString(item)) return item;\n return runtimeNodeToDesignNode(item as RuntimeNode);\n });\n}\n\n/**\n * 把运行时节点(RuntimeNode/RuntimeBlock)反推回设计时节点配置(DesignNode/DesignBlock)\n * 用于\"删除节点\"命令的撤销: 重新添加时需要原始的 DesignNode 配置\n */\nfunction runtimeNodeToDesignNode(node: RuntimeNode): DesignNode {\n const designNode: Record<string, any> = {\n type: node.type,\n ref: node.ref,\n props: toDesignProps(node.props),\n };\n // 事件监听\n if (node.listeners && Object.keys(node.listeners).length > 0) {\n designNode.listeners = cloneKeepFunctions(node.listeners);\n }\n // 指令\n if (node.directives && Object.keys(node.directives).length > 0) {\n designNode.directives = lodash.cloneDeep(node.directives);\n }\n // html模版\n if (node.tpl && node.tpl.length > 0) {\n designNode.tpl = [...node.tpl];\n }\n // 子节点集合\n if (node.items && node.items.length > 0) {\n designNode.items = toDesignItems(node.items);\n }\n // 插槽\n if (node.slots && Object.keys(node.slots).length > 0) {\n const slots: Record<string, any> = {};\n for (const slotName in node.slots) {\n const items = node.slots[slotName];\n if (items && items.length > 0) {\n slots[slotName] = toDesignItems(items);\n }\n }\n if (Object.keys(slots).length > 0) designNode.slots = slots;\n }\n // 嵌套 Block 的区块属性\n const block = node as RuntimeBlock;\n if (block.block) {\n designNode.block = true;\n for (const key of [\"data\", \"computed\", \"watch\", \"methods\", \"lifeCycles\", \"meta\", \"i18n\"] as const) {\n const value = (block as any)[key];\n if (TypeofHasKeys(value)) designNode[key] = cloneKeepFunctions(value);\n }\n }\n return designNode as DesignNode;\n}\n\n/** 判断对象存在且有键 */\nfunction TypeofHasKeys(value: any): boolean {\n return value !== null && value !== undefined && typeof value === \"object\" && Object.keys(value).length > 0;\n}\n\nexport {\n runtimeNodeToDesignNode,\n}\n","import type { DesignNode, RuntimeComponentSlotsItem, RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignCommand } from \"../../history/Command\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport type { InsertTarget } from \"../NodePosition\";\nimport { applyAddNodes, getNodeDocIndex, getNodeInsertTarget, toRuntimeNodes } from \"../NodePosition\";\nimport { runtimeNodeToDesignNode } from \"../NodeSerialize\";\n\n/** 删除节点命令的选项 */\ninterface RemoveNodesCommandOptions {\n /** 删除的节点id集合 */\n nodeIds: Array<string>;\n /** 命令执行成功后的回调(参数是被删除的节点名称集合) */\n onExecute?: (names: Array<string>) => void;\n}\n\n/** 被删除节点的记录 */\ninterface RemovedNode {\n /** 被删除节点的原始 DesignNode 配置(用于 undo 恢复) */\n designNode: DesignNode;\n /** 被删除前的插入位置 */\n target: InsertTarget;\n /** 被删除前在父容器子节点集合中的索引(undo 时按此顺序恢复) */\n docIndex: number;\n /** 被删除前的节点id(undo 重新添加后 id 会变化) */\n oldNodeId: string;\n}\n\n/**\n * 删除节点命令\n * undo 通过记录的原始 DesignNode 配置重新添加回原位置:\n * - runtime 重新添加节点时会生成新的 id, 因此 undo 需记录\"旧id -> 新id\"映射,\n * 后续恢复节点的定位(positionId)才能正确指向已恢复的兄弟节点;\n * - 恢复按删除前的文档顺序(docIndex)进行, 保证\"前兄弟定位\"依次生效;\n * - redo 直接删除 undo 恢复出的新节点(currentNodeIds), 不会因旧 id 失效而丢失命令\n */\nclass RemoveNodesCommand implements DesignCommand {\n readonly name: string;\n protected readonly designerState: DesignerState;\n protected readonly options: RemoveNodesCommandOptions;\n /** 被删除节点的记录(execute/redo 时重建) */\n protected removedNodes: Array<RemovedNode> = [];\n /** 最近一次删除/恢复动作对应的节点id集合(redo 删除时使用) */\n protected currentNodeIds: Array<string> = [];\n\n constructor(designerState: DesignerState, name: string, options: RemoveNodesCommandOptions) {\n this.designerState = designerState;\n this.name = name;\n this.options = options;\n }\n\n execute(): boolean {\n return this.doRemove();\n }\n\n undo(): boolean {\n if (this.removedNodes.length <= 0) return false;\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n // 按删除前的文档顺序恢复, 保证前兄弟定位节点总是先于依赖它的节点就位\n const sorted = [...this.removedNodes].sort((a, b) => a.docIndex - b.docIndex);\n const idMap = new Map<string, string>();\n const newNodeIds: Array<string> = [];\n let success = false;\n for (const removed of sorted) {\n const target = this.mapInsertTarget(removed.target, idMap);\n const added: Array<RuntimeComponentSlotsItem> = applyAddNodes(blockInstance, target, [removed.designNode]);\n const runtimeNodes = toRuntimeNodes(added);\n if (runtimeNodes.length > 0) {\n success = true;\n idMap.set(removed.oldNodeId, runtimeNodes[0].id);\n newNodeIds.push(runtimeNodes[0].id);\n }\n }\n if (success) this.currentNodeIds = newNodeIds;\n return success;\n }\n\n redo(): boolean {\n return this.doRemove();\n }\n\n /** 把插入目标中指向\"已恢复节点(新id)\"的定位 id 替换成新 id, 未失效的定位保持不变 */\n protected mapInsertTarget(target: InsertTarget, idMap: Map<string, string>): InsertTarget {\n const mapped = idMap.get(target.positionId!);\n if (target.positionId && mapped) return { ...target, positionId: mapped };\n return target;\n }\n\n /** 执行删除动作 */\n protected doRemove(): boolean {\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n // 优先使用 undo 恢复后的新节点id(重新添加的节点 id 已变化, 原始 options.nodeIds 会失效)\n const nodeIds = this.currentNodeIds.length > 0 ? this.currentNodeIds : this.options.nodeIds;\n // 收集存在的节点(排除根节点等无父节点的节点)\n const nodes: Array<RuntimeNode> = [];\n for (const nodeId of nodeIds) {\n const node = blockInstance.globalContext.allNode[nodeId];\n if (!node) continue;\n if (!blockInstance.globalContext.nodeParent[nodeId]) continue;\n nodes.push(node);\n }\n if (nodes.length <= 0) return false;\n // 记录原始配置与位置(执行删除前; runtimeNodeToDesignNode 返回全新对象, 无需再次克隆)\n this.removedNodes = nodes.map(node => ({\n designNode: runtimeNodeToDesignNode(node),\n target: getNodeInsertTarget(blockInstance, node.id)!,\n docIndex: getNodeDocIndex(blockInstance, node.id),\n oldNodeId: node.id,\n }));\n this.currentNodeIds = nodes.map(node => node.id);\n const names = nodes.map(node => this.designerState.designerEngine.componentManage.getComponentMeta(node.type)?.name ?? node.type);\n // 执行删除\n blockInstance.opsById.removeAllById(this.currentNodeIds);\n this.options.onExecute?.(names);\n return true;\n }\n}\n\nexport type {\n RemoveNodesCommandOptions,\n}\n\nexport {\n RemoveNodesCommand,\n}\n","import lodash from \"lodash\";\nimport { emptyNodeId } from \"@ease-forge/runtime\";\nimport { DesignerEffect } from \"../core/DesignerEffect\";\nimport type { DesignerState } from \"../models/DesignerState\";\nimport { DragDropEvent } from \"../events/designer/DragDropEvent\";\nimport { ShortcutKeyEvent } from \"../events/keyboard/ShortcutKeyEvent\";\nimport { insertionToTarget } from \"./NodePosition\";\nimport { AddNodesCommand } from \"./commands/AddNodesCommand\";\nimport { MoveNodesCommand } from \"./commands/MoveNodesCommand\";\nimport { RemoveNodesCommand } from \"./commands/RemoveNodesCommand\";\n\n/**\n * 节点操作效果(操作命令层的入口)\n * 消费 DragDropEvent 执行节点的添加/移动命令,\n * 消费快捷键事件执行 删除选中 / undo / redo 命令\n */\nclass NodeOperationEffect extends DesignerEffect {\n /** 取消订阅函数集合 */\n private readonly unsubscribes: Array<() => void> = [];\n\n protected onEffect(): void {\n this.dragDropEffect();\n this.shortcutKeyEffect();\n }\n\n protected onDestroy(): void {\n this.unsubscribes.forEach(unsubscribe => unsubscribe());\n this.unsubscribes.length = 0;\n }\n\n /** 当前操作的页面状态 */\n protected getActiveState(): DesignerState | undefined {\n return this.designerEngine.activeDesignerState;\n }\n\n /**\n * 拖拽放下 -> 添加/移动节点命令\n */\n protected dragDropEffect(): void {\n this.unsubscribes.push(\n this.eventbus.subscribe(DragDropEvent, event => {\n const designerState = this.getActiveState();\n const data = event.data!;\n const insertion = data.insertion;\n // 没有有效的插入位置(拖出画布)或未通过 DragDropConfig 校验\n if (!insertion || !insertion.allowDrag || !designerState?.blockInstance) return;\n const target = insertionToTarget(insertion);\n const moveNodeIds = data.nodeIds.filter(id => id !== emptyNodeId);\n if (moveNodeIds.length > 0) {\n // 移动已有节点\n const command = new MoveNodesCommand(designerState, `移动 ${moveNodeIds.length} 个组件`, {\n target,\n nodeIds: moveNodeIds,\n // 移动后重算选中框位置并刷新选中状态\n onExecute: () => designerState.selectNodeByIds(moveNodeIds),\n });\n designerState.commandStack.execute(command);\n } else {\n // 从物料面板添加新节点\n const nodes = data.componentMetas.map(cmpMeta => ({\n ...(lodash.cloneDeep(cmpMeta.defDesignNode ?? {})),\n type: cmpMeta.type,\n }));\n const command = new AddNodesCommand(designerState, `添加 ${nodes.length} 个组件`, {\n target,\n nodes,\n onExecute: nodeIds => designerState.selectNodeByIds(nodeIds),\n });\n designerState.commandStack.execute(command);\n }\n }, 200),\n );\n }\n\n /**\n * 快捷键 -> 删除选中 / undo / redo\n */\n protected shortcutKeyEffect(): void {\n this.unsubscribes.push(\n this.eventbus.subscribe(ShortcutKeyEvent, event => {\n const data = event.data!;\n if (data.type !== \"keydown\") return;\n const designerState = this.getActiveState();\n if (!designerState) return;\n const ctrl = data.ctrlKey || data.metaKey;\n // 输入场景(输入框/文本域/可编辑区域)中不触发设计器快捷键, 交还原生行为(如输入框内的文本撤销)\n const target = data.rawEvent.target as HTMLElement | null;\n const inEditable = !!target && (target.tagName === \"INPUT\" || target.tagName === \"TEXTAREA\" || target.isContentEditable);\n // undo: ctrl+z\n if (ctrl && !data.shiftKey && data.key === \"z\") {\n if (inEditable) return;\n data.rawEvent.preventDefault();\n designerState.commandStack.undo();\n designerState.clearSelections();\n return;\n }\n // redo: ctrl+y 或 ctrl+shift+z\n if (ctrl && (data.key === \"y\" || (data.shiftKey && data.key === \"z\"))) {\n if (inEditable) return;\n data.rawEvent.preventDefault();\n designerState.commandStack.redo();\n designerState.clearSelections();\n return;\n }\n // 删除选中节点: Delete / Backspace\n if ((data.key === \"delete\" || data.key === \"backspace\") && designerState.existsSelection) {\n if (inEditable) return;\n data.rawEvent.preventDefault();\n const nodeIds = designerState.selections.map(selection => selection.nodeId!).filter(Boolean);\n if (nodeIds.length <= 0) return;\n const command = new RemoveNodesCommand(designerState, `删除 ${nodeIds.length} 个组件`, {\n nodeIds,\n onExecute: () => designerState.clearSelections(),\n });\n designerState.commandStack.execute(command);\n }\n }),\n );\n }\n}\n\nexport {\n NodeOperationEffect,\n}\n","import type { RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignCommand } from \"../../history/Command\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\n/** 单个节点的属性写入描述 */\ninterface UpdatePropsChange {\n /** 目标节点id */\n nodeId: string;\n /**\n * 写入位置标识(命令合并依据), 如 \"props:width\" / \"style\" / \"class\" / \"directives:for\"\n * 同一标识在合并时间窗内的连续修改会合并成一条历史\n */\n changeKey: string;\n /** 修改前的值(undo 恢复) */\n oldValue: any;\n /** 修改后的值 */\n newValue: any;\n /** 把值写入节点(空值语义由构造方决定: 赋值或删除属性) */\n write: (node: RuntimeNode, value: any) => void;\n}\n\n/** 属性修改命令的选项 */\ninterface UpdatePropsCommandOptions {\n /** 修改描述集合 */\n changes: Array<UpdatePropsChange>;\n /** 应用后是否跳过画布重渲染 */\n disableReRender?: boolean;\n}\n\n/**\n * 修改节点属性命令(属性/样式/class/指令的统一撤销载体)\n * 属性面板、样式面板、高级面板的取值修改都经由本命令写入节点,\n * 使这些修改与结构操作(增删移)一样具备 undo/redo 能力\n */\nclass UpdatePropsCommand implements DesignCommand {\n readonly name: string;\n protected readonly designerState: DesignerState;\n protected readonly options: UpdatePropsCommandOptions;\n\n constructor(designerState: DesignerState, name: string, options: UpdatePropsCommandOptions) {\n this.designerState = designerState;\n this.name = name;\n this.options = options;\n }\n\n get changes(): Array<UpdatePropsChange> {\n return this.options.changes;\n }\n\n execute(): boolean {\n return this.applyChanges(false);\n }\n\n undo(): boolean {\n return this.applyChanges(true);\n }\n\n redo(): boolean {\n return this.applyChanges(false);\n }\n\n /** 应用修改(toOld = true 时恢复修改前的值) */\n protected applyChanges(toOld: boolean): boolean {\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n const nodes: Array<RuntimeNode> = [];\n for (const change of this.options.changes) {\n const node = blockInstance.globalContext.allNode[change.nodeId];\n if (!node) continue;\n change.write(node, toOld ? change.oldValue : change.newValue);\n nodes.push(node);\n }\n if (nodes.length <= 0) return false;\n this.rerender(nodes);\n return true;\n }\n\n /** 重渲染画布并重算受影响节点的选中框位置 */\n protected rerender(nodes: Array<RuntimeNode>): void {\n if (this.options.disableReRender) return;\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return;\n blockInstance.$forceUpdate();\n blockInstance.$nextTick(() => {\n const nodeIds = new Set(nodes.map(node => node.id));\n for (const selection of this.designerState.selections) {\n if (selection.nodeId && nodeIds.has(selection.nodeId)) selection.recalcPosition();\n }\n });\n }\n\n /**\n * 命令合并: 同一节点同一写入位置的连续修改合并成一条历史\n * (相同位置更新 newValue, 新位置追加; 无任何交集时不合并)\n */\n tryMerge(next: DesignCommand): boolean {\n if (!(next instanceof UpdatePropsCommand)) return false;\n const keys = new Set(this.options.changes.map(change => `${change.nodeId}@${change.changeKey}`));\n const hasIntersection = next.options.changes.some(change => keys.has(`${change.nodeId}@${change.changeKey}`));\n if (!hasIntersection) return false;\n for (const change of next.options.changes) {\n const exists = this.options.changes.find(item => item.nodeId === change.nodeId && item.changeKey === change.changeKey);\n if (exists) {\n exists.newValue = change.newValue;\n } else {\n this.options.changes.push(change);\n }\n }\n return true;\n }\n}\n\nexport type {\n UpdatePropsChange,\n UpdatePropsCommandOptions,\n}\n\nexport {\n UpdatePropsCommand,\n}\n","import type { RuntimeListener } from \"@ease-forge/runtime\";\nimport type { DesignCommand } from \"../../history/Command\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\n/** 单个节点的事件监听修改描述 */\ninterface UpdateListenersChange {\n /** 目标节点id */\n nodeId: string;\n /** 事件名(原始事件名, 如 click; runtime 内部会转换成 onXxx 属性名) */\n event: string;\n /** 修改前的监听器(undefined 表示原本未绑定) */\n oldListener?: RuntimeListener;\n /** 修改后的监听器(undefined 表示解绑) */\n newListener?: RuntimeListener;\n}\n\n/** 事件监听修改命令的选项 */\ninterface UpdateListenersCommandOptions {\n /** 修改描述集合 */\n changes: Array<UpdateListenersChange>;\n}\n\n/**\n * 修改事件监听命令(绑定/修改/解绑)\n * 经由 runtime 的 bindListenerById / removeListenerById 执行:\n * 除写入 node.listeners 外, 还会同步维护 ext.bindListeners(渲染时真正传给组件的\n * 事件处理器)、runtimeBlock.methods 函数池并触发重渲染 —— 直接改 node.listeners\n * 不会同步这些状态, 事件修改将无法生效\n */\nclass UpdateListenersCommand implements DesignCommand {\n readonly name: string;\n protected readonly designerState: DesignerState;\n protected readonly options: UpdateListenersCommandOptions;\n\n constructor(designerState: DesignerState, name: string, options: UpdateListenersCommandOptions) {\n this.designerState = designerState;\n this.name = name;\n this.options = options;\n }\n\n execute(): boolean {\n return this.applyChanges(false);\n }\n\n undo(): boolean {\n return this.applyChanges(true);\n }\n\n redo(): boolean {\n return this.applyChanges(false);\n }\n\n /** 应用修改(toOld = true 时恢复修改前的监听器) */\n protected applyChanges(toOld: boolean): boolean {\n const blockInstance = this.designerState.blockInstance;\n if (!blockInstance) return false;\n const ops = blockInstance.opsById;\n let success = false;\n for (const change of this.options.changes) {\n const listener = toOld ? change.oldListener : change.newListener;\n if (listener) {\n success = ops.bindListenerById(change.nodeId, change.event, listener) || success;\n } else {\n success = ops.removeListenerById(change.nodeId, change.event) || success;\n }\n }\n return success;\n }\n\n /** 命令合并: 同一节点同一事件的连续修改合并成一条历史 */\n tryMerge(next: DesignCommand): boolean {\n if (!(next instanceof UpdateListenersCommand)) return false;\n const keys = new Set(this.options.changes.map(change => `${change.nodeId}@${change.event}`));\n const hasIntersection = next.options.changes.some(change => keys.has(`${change.nodeId}@${change.event}`));\n if (!hasIntersection) return false;\n for (const change of next.options.changes) {\n const exists = this.options.changes.find(item => item.nodeId === change.nodeId && item.event === change.event);\n if (exists) {\n exists.newListener = change.newListener;\n } else {\n this.options.changes.push(change);\n }\n }\n return true;\n }\n}\n\nexport type {\n UpdateListenersChange,\n UpdateListenersCommandOptions,\n}\n\nexport {\n UpdateListenersCommand,\n}\n","<script setup lang=\"ts\">\nimport { computed, type CSSProperties, onBeforeUnmount, onMounted, ref, watch } from \"vue\";\nimport { BlockComponent, type BlockInstance, type ComponentManage, type DesignBlock } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../models/DesignerState\";\n\ndefineOptions({\n name: 'DesignCanvas',\n});\n\n// 定义 Props 类型\ninterface DesignCanvasProps {\n /** 设计器页面状态 */\n designerState: DesignerState;\n /** block配置 */\n block?: DesignBlock;\n /** 是否自动加载依赖的组件 */\n autoLoadComponent?: boolean;\n}\n\n// 读取组件 props 属性\nconst props = withDefaults(defineProps<DesignCanvasProps>(), {\n autoLoadComponent: true,\n});\n\n/** 画布容器(悬停/选中/插入指示的定位参照物) */\nconst containerRef = ref<HTMLDivElement | undefined>();\n/** 画布的 Block 组件实例 */\nconst blockComponentRef = ref<InstanceType<typeof BlockComponent> | undefined>();\n/** 画布容器尺寸观察器(容器尺寸变化时重算悬停/选中框位置) */\nlet resizeObserver: ResizeObserver | undefined;\n\n// 组件管理器(从引擎获取)\nconst componentManage: ComponentManage = props.designerState.designerEngine.componentManage;\n\n// 画布容器与 Block 实例上报到页面状态\nonMounted(() => {\n props.designerState.designerContainer = containerRef.value;\n // 窗口缩放/面板开合导致画布尺寸变化后, 悬停虚线与选中框仍需贴合节点位置\n if (containerRef.value && typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver(() => {\n props.designerState.hover.recalcPosition();\n for (const selection of props.designerState.selections) {\n selection.recalcPosition();\n }\n });\n resizeObserver.observe(containerRef.value);\n }\n});\n\nonBeforeUnmount(() => {\n resizeObserver?.disconnect();\n resizeObserver = undefined;\n // 注意: 不清除 designerBlockInstance —— 预览模式(DesignCanvas 被 v-if 卸载)需要\n // 依据它的节点树反序列化生成预览 Block; 回到编辑模式重新挂载时 watch 会重新设置新实例\n if (props.designerState.designerContainer === containerRef.value) {\n props.designerState.designerContainer = undefined;\n }\n});\n\n// BlockComponent 挂载完成后, 把 Block 实例上报到页面状态\nwatch(() => blockComponentRef.value?.blockInstance, (blockInstance: BlockInstance | undefined) => {\n props.designerState.designerBlockInstance = blockInstance;\n}, { immediate: true });\n\n// ---------------- 视觉反馈层: 悬停虚线框 / 选中框 / 插入指示线 ----------------\n\nconst hover = props.designerState.hover;\nconst selections = props.designerState.selections;\nconst insertion = props.designerState.designerEngine.insertion;\n\n/** 悬停虚线框样式 */\nconst hoverStyle = computed<CSSProperties>(() => {\n const position = hover.position;\n if (!position) return { display: \"none\" };\n return {\n position: \"absolute\",\n top: `${position.top}px`,\n left: `${position.left}px`,\n width: `${position.width}px`,\n height: `${position.height}px`,\n };\n});\n\n/** 选中框集合(带节点名称) */\nconst selectionStyles = computed<Array<{ key: string; style: CSSProperties; name: string }>>(() => {\n return selections.map((selection, idx) => {\n const position = selection.position;\n const style: CSSProperties = position ? {\n position: \"absolute\",\n top: `${position.top}px`,\n left: `${position.left}px`,\n width: `${position.width}px`,\n height: `${position.height}px`,\n } : { display: \"none\" };\n return { key: selection.nodeId ?? String(idx), style, name: selection.componentMeta?.name ?? \"\" };\n });\n});\n\n/** 插入位置指示线(水平线或垂直线) */\nconst insertionStyle = computed<CSSProperties>(() => {\n const position = insertion.position;\n if (!position || insertion.isEmpty()) return { display: \"none\" };\n if (insertion.isHorizontal()) {\n // 垂直方向插入 -> 显示水平指示线\n return {\n position: \"absolute\",\n top: `${insertion.isBefore() ? position.top : position.top + position.height}px`,\n left: `${position.left}px`,\n width: `${position.width}px`,\n height: \"2px\",\n };\n }\n // 水平方向插入 -> 显示垂直指示线\n return {\n position: \"absolute\",\n top: `${position.top}px`,\n left: `${insertion.isBefore() ? position.left : position.left + position.width}px`,\n width: \"2px\",\n height: `${position.height}px`,\n };\n});\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"design-canvas designer-content\">\n <BlockComponent\n ref=\"blockComponentRef\"\n :componentManage=\"componentManage\"\n :block=\"props.block\"\n :autoLoadComponent=\"props.autoLoadComponent\"\n :isDesigning=\"true\"\n />\n <!-- 悬停虚线框 -->\n <div v-if=\"hover.nodeId\" class=\"design-canvas-hover\" :style=\"hoverStyle\"></div>\n <!-- 选中框 -->\n <div\n v-for=\"item in selectionStyles\"\n :key=\"item.key\"\n class=\"design-canvas-selection\"\n :style=\"item.style\"\n >\n <span v-if=\"item.name\" class=\"design-canvas-selection-name\">{{ item.name }}</span>\n </div>\n <!-- 插入位置指示线 -->\n <div class=\"design-canvas-insertion\" :style=\"insertionStyle\"></div>\n </div>\n</template>\n\n<style scoped>\n.design-canvas {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: auto;\n background: repeating-conic-gradient(#fafafa 0% 25%, #fff 0% 50%) 50% / 16px 16px;\n}\n\n.design-canvas-hover {\n pointer-events: none;\n border: 1px dashed #1677ff;\n z-index: 10;\n}\n\n.design-canvas-selection {\n pointer-events: none;\n border: 1px solid #1677ff;\n background-color: rgba(22, 119, 255, 0.06);\n z-index: 11;\n}\n\n.design-canvas-selection-name {\n position: absolute;\n top: -18px;\n left: -1px;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n white-space: nowrap;\n color: #fff;\n background-color: #1677ff;\n}\n\n.design-canvas-insertion {\n pointer-events: none;\n background-color: #1677ff;\n z-index: 12;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, type CSSProperties, onBeforeUnmount, onMounted, ref, watch } from \"vue\";\nimport { BlockComponent, type BlockInstance, type ComponentManage, type DesignBlock } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../models/DesignerState\";\n\ndefineOptions({\n name: 'DesignCanvas',\n});\n\n// 定义 Props 类型\ninterface DesignCanvasProps {\n /** 设计器页面状态 */\n designerState: DesignerState;\n /** block配置 */\n block?: DesignBlock;\n /** 是否自动加载依赖的组件 */\n autoLoadComponent?: boolean;\n}\n\n// 读取组件 props 属性\nconst props = withDefaults(defineProps<DesignCanvasProps>(), {\n autoLoadComponent: true,\n});\n\n/** 画布容器(悬停/选中/插入指示的定位参照物) */\nconst containerRef = ref<HTMLDivElement | undefined>();\n/** 画布的 Block 组件实例 */\nconst blockComponentRef = ref<InstanceType<typeof BlockComponent> | undefined>();\n/** 画布容器尺寸观察器(容器尺寸变化时重算悬停/选中框位置) */\nlet resizeObserver: ResizeObserver | undefined;\n\n// 组件管理器(从引擎获取)\nconst componentManage: ComponentManage = props.designerState.designerEngine.componentManage;\n\n// 画布容器与 Block 实例上报到页面状态\nonMounted(() => {\n props.designerState.designerContainer = containerRef.value;\n // 窗口缩放/面板开合导致画布尺寸变化后, 悬停虚线与选中框仍需贴合节点位置\n if (containerRef.value && typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver(() => {\n props.designerState.hover.recalcPosition();\n for (const selection of props.designerState.selections) {\n selection.recalcPosition();\n }\n });\n resizeObserver.observe(containerRef.value);\n }\n});\n\nonBeforeUnmount(() => {\n resizeObserver?.disconnect();\n resizeObserver = undefined;\n // 注意: 不清除 designerBlockInstance —— 预览模式(DesignCanvas 被 v-if 卸载)需要\n // 依据它的节点树反序列化生成预览 Block; 回到编辑模式重新挂载时 watch 会重新设置新实例\n if (props.designerState.designerContainer === containerRef.value) {\n props.designerState.designerContainer = undefined;\n }\n});\n\n// BlockComponent 挂载完成后, 把 Block 实例上报到页面状态\nwatch(() => blockComponentRef.value?.blockInstance, (blockInstance: BlockInstance | undefined) => {\n props.designerState.designerBlockInstance = blockInstance;\n}, { immediate: true });\n\n// ---------------- 视觉反馈层: 悬停虚线框 / 选中框 / 插入指示线 ----------------\n\nconst hover = props.designerState.hover;\nconst selections = props.designerState.selections;\nconst insertion = props.designerState.designerEngine.insertion;\n\n/** 悬停虚线框样式 */\nconst hoverStyle = computed<CSSProperties>(() => {\n const position = hover.position;\n if (!position) return { display: \"none\" };\n return {\n position: \"absolute\",\n top: `${position.top}px`,\n left: `${position.left}px`,\n width: `${position.width}px`,\n height: `${position.height}px`,\n };\n});\n\n/** 选中框集合(带节点名称) */\nconst selectionStyles = computed<Array<{ key: string; style: CSSProperties; name: string }>>(() => {\n return selections.map((selection, idx) => {\n const position = selection.position;\n const style: CSSProperties = position ? {\n position: \"absolute\",\n top: `${position.top}px`,\n left: `${position.left}px`,\n width: `${position.width}px`,\n height: `${position.height}px`,\n } : { display: \"none\" };\n return { key: selection.nodeId ?? String(idx), style, name: selection.componentMeta?.name ?? \"\" };\n });\n});\n\n/** 插入位置指示线(水平线或垂直线) */\nconst insertionStyle = computed<CSSProperties>(() => {\n const position = insertion.position;\n if (!position || insertion.isEmpty()) return { display: \"none\" };\n if (insertion.isHorizontal()) {\n // 垂直方向插入 -> 显示水平指示线\n return {\n position: \"absolute\",\n top: `${insertion.isBefore() ? position.top : position.top + position.height}px`,\n left: `${position.left}px`,\n width: `${position.width}px`,\n height: \"2px\",\n };\n }\n // 水平方向插入 -> 显示垂直指示线\n return {\n position: \"absolute\",\n top: `${position.top}px`,\n left: `${insertion.isBefore() ? position.left : position.left + position.width}px`,\n width: \"2px\",\n height: `${position.height}px`,\n };\n});\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"design-canvas designer-content\">\n <BlockComponent\n ref=\"blockComponentRef\"\n :componentManage=\"componentManage\"\n :block=\"props.block\"\n :autoLoadComponent=\"props.autoLoadComponent\"\n :isDesigning=\"true\"\n />\n <!-- 悬停虚线框 -->\n <div v-if=\"hover.nodeId\" class=\"design-canvas-hover\" :style=\"hoverStyle\"></div>\n <!-- 选中框 -->\n <div\n v-for=\"item in selectionStyles\"\n :key=\"item.key\"\n class=\"design-canvas-selection\"\n :style=\"item.style\"\n >\n <span v-if=\"item.name\" class=\"design-canvas-selection-name\">{{ item.name }}</span>\n </div>\n <!-- 插入位置指示线 -->\n <div class=\"design-canvas-insertion\" :style=\"insertionStyle\"></div>\n </div>\n</template>\n\n<style scoped>\n.design-canvas {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: auto;\n background: repeating-conic-gradient(#fafafa 0% 25%, #fff 0% 50%) 50% / 16px 16px;\n}\n\n.design-canvas-hover {\n pointer-events: none;\n border: 1px dashed #1677ff;\n z-index: 10;\n}\n\n.design-canvas-selection {\n pointer-events: none;\n border: 1px solid #1677ff;\n background-color: rgba(22, 119, 255, 0.06);\n z-index: 11;\n}\n\n.design-canvas-selection-name {\n position: absolute;\n top: -18px;\n left: -1px;\n padding: 0 4px;\n font-size: 12px;\n line-height: 18px;\n white-space: nowrap;\n color: #fff;\n background-color: #1677ff;\n}\n\n.design-canvas-insertion {\n pointer-events: none;\n background-color: #1677ff;\n z-index: 12;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, type CSSProperties, ref } from \"vue\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { CursorStatus } from \"../types/Designer\";\nimport type { DesignerEngine } from \"../core/DesignerEngine\";\n\ndefineOptions({\n name: 'DragGhost',\n});\n\n// 定义 Props 类型\ninterface DragGhostProps {\n /** 设计器引擎 */\n designerEngine: DesignerEngine;\n}\n\n// 读取组件 props 属性\nconst props = withDefaults(defineProps<DragGhostProps>(), {});\n\n// ghost div实例\nconst ghost = ref<HTMLDivElement | undefined>();\n// 设计器引擎光标信息\nconst cursor = props.designerEngine.cursor;\nconst draggingCmpMetas = props.designerEngine.draggingCmpMetas;\n\n// ghost样式(跟随光标, 考虑iframe场景使用顶层坐标)\nconst ghostStyle = computed<CSSProperties>(() => {\n if (!ghost.value) return {};\n const position = cursor.position;\n if (!Typeof.isNum(position.topClientX) || !Typeof.isNum(position.topClientY)) {\n return {};\n }\n return {\n transform: `perspective(1px) translate3d(${position.topClientX - 6}px, ${position.topClientY - 20}px, 0) scale(0.8)`,\n };\n});\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div\n v-if=\"cursor.status === CursorStatus.Dragging && draggingCmpMetas.existsCmpMeta\"\n ref=\"ghost\"\n class=\"designer-ghost\"\n :style=\"ghostStyle\"\n >\n <span class=\"designer-ghost-name\">\n {{ draggingCmpMetas.cmpMetas.map(meta => meta.name).join(',') }}\n </span>\n </div>\n </Teleport>\n</template>\n\n<style scoped>\n.designer-ghost {\n z-index: 999;\n pointer-events: none;\n position: fixed;\n top: 0;\n left: 0;\n color: #fff;\n background-color: #1677ff;\n height: 40px;\n min-width: 60px;\n max-width: 150px;\n padding: 4px 16px;\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: 16px;\n opacity: 0.6;\n}\n\n.designer-ghost-name {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, type CSSProperties, ref } from \"vue\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { CursorStatus } from \"../types/Designer\";\nimport type { DesignerEngine } from \"../core/DesignerEngine\";\n\ndefineOptions({\n name: 'DragGhost',\n});\n\n// 定义 Props 类型\ninterface DragGhostProps {\n /** 设计器引擎 */\n designerEngine: DesignerEngine;\n}\n\n// 读取组件 props 属性\nconst props = withDefaults(defineProps<DragGhostProps>(), {});\n\n// ghost div实例\nconst ghost = ref<HTMLDivElement | undefined>();\n// 设计器引擎光标信息\nconst cursor = props.designerEngine.cursor;\nconst draggingCmpMetas = props.designerEngine.draggingCmpMetas;\n\n// ghost样式(跟随光标, 考虑iframe场景使用顶层坐标)\nconst ghostStyle = computed<CSSProperties>(() => {\n if (!ghost.value) return {};\n const position = cursor.position;\n if (!Typeof.isNum(position.topClientX) || !Typeof.isNum(position.topClientY)) {\n return {};\n }\n return {\n transform: `perspective(1px) translate3d(${position.topClientX - 6}px, ${position.topClientY - 20}px, 0) scale(0.8)`,\n };\n});\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div\n v-if=\"cursor.status === CursorStatus.Dragging && draggingCmpMetas.existsCmpMeta\"\n ref=\"ghost\"\n class=\"designer-ghost\"\n :style=\"ghostStyle\"\n >\n <span class=\"designer-ghost-name\">\n {{ draggingCmpMetas.cmpMetas.map(meta => meta.name).join(',') }}\n </span>\n </div>\n </Teleport>\n</template>\n\n<style scoped>\n.designer-ghost {\n z-index: 999;\n pointer-events: none;\n position: fixed;\n top: 0;\n left: 0;\n color: #fff;\n background-color: #1677ff;\n height: 40px;\n min-width: 60px;\n max-width: 150px;\n padding: 4px 16px;\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: 16px;\n opacity: 0.6;\n}\n\n.designer-ghost-name {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n</style>\n","<script setup lang=\"ts\">\nimport lodash from \"lodash\";\nimport { computed } from \"vue\";\nimport { Tooltip } from \"antdv-next\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { isHtmlTag, type Setter, type SetterGroup, type SetterProps } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\ndefineOptions({ name: 'SetterPropsGroup' });\n\n// 定义 Props 类型\ninterface SetterPropsGroupProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 属性分组(已经过隐藏过滤) */\n group: SetterGroup;\n}\n\nconst props = defineProps<SetterPropsGroupProps>();\n\n// 选中的节点(多选时共用同一份配置)\nconst selectNodes = computed(() => props.designerState.selectNodes);\n\n/** 解析 setter 组件(字符串名从组件管理器解析) */\nfunction getComponent(cmp: string | any): any {\n if (Typeof.isStr(cmp) && !isHtmlTag(cmp)) {\n return props.designerState.designerEngine.componentManage.getComponent(cmp);\n }\n return cmp;\n}\n\n/** 生成传递给 setter 组件的 props */\nfunction getSetterProps(setter: Setter): SetterProps {\n const {\n cmp,\n cmpProps,\n label,\n labelTips,\n enableBind,\n isHideSetter,\n watchValue,\n ...other\n } = setter;\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: selectNodes.value,\n ...cmpProps,\n ...other,\n } as SetterProps;\n}\n\n/** 当前 setter 是否处于数据绑定状态(值是 {{ }} 表达式) */\nfunction isBound(setter: Setter): boolean {\n const { propsName, enableBind } = setter;\n if (enableBind === false || Typeof.noValue(propsName)) return false;\n const nodes = selectNodes.value;\n const values = new Set<any>();\n for (const node of nodes) {\n values.add(node.props[propsName!]);\n }\n if (values.size !== 1) return false;\n const propsValue = values.values().next().value;\n if (!Typeof.isStr(propsValue)) return false;\n const bindStr = lodash.trim(propsValue);\n return bindStr.startsWith(\"{{\") && bindStr.endsWith(\"}}\");\n}\n\n/**\n * 切换数据绑定状态(bind <-> unbind)\n */\nfunction toggleBind(setter: Setter): void {\n const { propsName } = setter;\n if (Typeof.noValue(propsName)) return;\n const nodes = selectNodes.value;\n const toBind = !isBound(setter);\n for (const node of nodes) {\n const designExt = node.designExt;\n if (!designExt.tmpBindProps) designExt.tmpBindProps = {};\n if (!designExt.tmpUnbindProps) designExt.tmpUnbindProps = {};\n if (toBind) {\n // 切换成绑定: 暂存当前值, 写入绑定表达式\n if (lodash.hasIn(node.props, propsName)) {\n designExt.tmpUnbindProps[propsName] = node.props[propsName];\n } else {\n delete designExt.tmpUnbindProps[propsName];\n }\n node.props[propsName] = designExt.tmpBindProps[propsName] ?? \"{{ }}\";\n } else {\n // 切换成非绑定: 暂存绑定表达式, 恢复之前的值\n const propsValue = node.props[propsName];\n if (Typeof.isStr(propsValue)) {\n const bindStr = lodash.trim(propsValue);\n if (bindStr.startsWith(\"{{\") && bindStr.endsWith(\"}}\")) {\n designExt.tmpBindProps[propsName] = bindStr;\n }\n }\n if (lodash.hasIn(designExt.tmpUnbindProps, propsName)) {\n designExt.tmpUnbindProps[propsName] = node.props[propsName];\n } else {\n delete node.props[propsName];\n }\n }\n }\n // 强制重新渲染画布 + 刷新面板(节点是非响应式对象, 绑定状态的显示需靠版本号触发更新)\n props.designerState.blockInstance?.$forceUpdate();\n props.designerState.setterShareState.notifyPanelUpdate();\n}\n</script>\n\n<template>\n <div v-for=\"(setter, idx) in props.group.items\" :key=\"idx\" class=\"designer-props-item\">\n <div class=\"designer-props-label\">\n <Tooltip v-if=\"setter.labelTips\" :title=\"setter.labelTips\">\n <span>{{ setter.label }}</span>\n </Tooltip>\n <span v-else>{{ setter.label }}</span>\n </div>\n <div class=\"designer-props-control\">\n <component\n :is=\"getComponent(setter.cmp)\"\n v-if=\"getComponent(setter.cmp)\"\n v-bind=\"getSetterProps(setter)\"\n />\n </div>\n <div\n v-if=\"setter.enableBind !== false && setter.propsName\"\n class=\"designer-props-bind\"\n :class=\"{ 'designer-props-bind-active': isBound(setter) }\"\n title=\"切换数据绑定(值使用 {{ 表达式 }})\"\n @click=\"toggleBind(setter)\"\n >{{ '{ }' }}</div>\n </div>\n</template>\n\n<style scoped>\n.designer-props-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 0;\n}\n\n.designer-props-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.designer-props-control {\n flex: 1;\n min-width: 0;\n}\n\n.designer-props-bind {\n flex: none;\n width: 22px;\n height: 22px;\n line-height: 20px;\n text-align: center;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n color: #9ca3af;\n font-family: Consolas, Monaco, monospace;\n font-size: 11px;\n cursor: pointer;\n user-select: none;\n}\n\n.designer-props-bind:hover {\n border-color: #1677ff;\n color: #1677ff;\n}\n\n.designer-props-bind-active {\n border-color: #1677ff;\n background: #e6f4ff;\n color: #1677ff;\n}\n</style>\n","<script setup lang=\"ts\">\nimport lodash from \"lodash\";\nimport { computed } from \"vue\";\nimport { Tooltip } from \"antdv-next\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { isHtmlTag, type Setter, type SetterGroup, type SetterProps } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\ndefineOptions({ name: 'SetterPropsGroup' });\n\n// 定义 Props 类型\ninterface SetterPropsGroupProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 属性分组(已经过隐藏过滤) */\n group: SetterGroup;\n}\n\nconst props = defineProps<SetterPropsGroupProps>();\n\n// 选中的节点(多选时共用同一份配置)\nconst selectNodes = computed(() => props.designerState.selectNodes);\n\n/** 解析 setter 组件(字符串名从组件管理器解析) */\nfunction getComponent(cmp: string | any): any {\n if (Typeof.isStr(cmp) && !isHtmlTag(cmp)) {\n return props.designerState.designerEngine.componentManage.getComponent(cmp);\n }\n return cmp;\n}\n\n/** 生成传递给 setter 组件的 props */\nfunction getSetterProps(setter: Setter): SetterProps {\n const {\n cmp,\n cmpProps,\n label,\n labelTips,\n enableBind,\n isHideSetter,\n watchValue,\n ...other\n } = setter;\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: selectNodes.value,\n ...cmpProps,\n ...other,\n } as SetterProps;\n}\n\n/** 当前 setter 是否处于数据绑定状态(值是 {{ }} 表达式) */\nfunction isBound(setter: Setter): boolean {\n const { propsName, enableBind } = setter;\n if (enableBind === false || Typeof.noValue(propsName)) return false;\n const nodes = selectNodes.value;\n const values = new Set<any>();\n for (const node of nodes) {\n values.add(node.props[propsName!]);\n }\n if (values.size !== 1) return false;\n const propsValue = values.values().next().value;\n if (!Typeof.isStr(propsValue)) return false;\n const bindStr = lodash.trim(propsValue);\n return bindStr.startsWith(\"{{\") && bindStr.endsWith(\"}}\");\n}\n\n/**\n * 切换数据绑定状态(bind <-> unbind)\n */\nfunction toggleBind(setter: Setter): void {\n const { propsName } = setter;\n if (Typeof.noValue(propsName)) return;\n const nodes = selectNodes.value;\n const toBind = !isBound(setter);\n for (const node of nodes) {\n const designExt = node.designExt;\n if (!designExt.tmpBindProps) designExt.tmpBindProps = {};\n if (!designExt.tmpUnbindProps) designExt.tmpUnbindProps = {};\n if (toBind) {\n // 切换成绑定: 暂存当前值, 写入绑定表达式\n if (lodash.hasIn(node.props, propsName)) {\n designExt.tmpUnbindProps[propsName] = node.props[propsName];\n } else {\n delete designExt.tmpUnbindProps[propsName];\n }\n node.props[propsName] = designExt.tmpBindProps[propsName] ?? \"{{ }}\";\n } else {\n // 切换成非绑定: 暂存绑定表达式, 恢复之前的值\n const propsValue = node.props[propsName];\n if (Typeof.isStr(propsValue)) {\n const bindStr = lodash.trim(propsValue);\n if (bindStr.startsWith(\"{{\") && bindStr.endsWith(\"}}\")) {\n designExt.tmpBindProps[propsName] = bindStr;\n }\n }\n if (lodash.hasIn(designExt.tmpUnbindProps, propsName)) {\n designExt.tmpUnbindProps[propsName] = node.props[propsName];\n } else {\n delete node.props[propsName];\n }\n }\n }\n // 强制重新渲染画布 + 刷新面板(节点是非响应式对象, 绑定状态的显示需靠版本号触发更新)\n props.designerState.blockInstance?.$forceUpdate();\n props.designerState.setterShareState.notifyPanelUpdate();\n}\n</script>\n\n<template>\n <div v-for=\"(setter, idx) in props.group.items\" :key=\"idx\" class=\"designer-props-item\">\n <div class=\"designer-props-label\">\n <Tooltip v-if=\"setter.labelTips\" :title=\"setter.labelTips\">\n <span>{{ setter.label }}</span>\n </Tooltip>\n <span v-else>{{ setter.label }}</span>\n </div>\n <div class=\"designer-props-control\">\n <component\n :is=\"getComponent(setter.cmp)\"\n v-if=\"getComponent(setter.cmp)\"\n v-bind=\"getSetterProps(setter)\"\n />\n </div>\n <div\n v-if=\"setter.enableBind !== false && setter.propsName\"\n class=\"designer-props-bind\"\n :class=\"{ 'designer-props-bind-active': isBound(setter) }\"\n title=\"切换数据绑定(值使用 {{ 表达式 }})\"\n @click=\"toggleBind(setter)\"\n >{{ '{ }' }}</div>\n </div>\n</template>\n\n<style scoped>\n.designer-props-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 0;\n}\n\n.designer-props-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.designer-props-control {\n flex: 1;\n min-width: 0;\n}\n\n.designer-props-bind {\n flex: none;\n width: 22px;\n height: 22px;\n line-height: 20px;\n text-align: center;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n color: #9ca3af;\n font-family: Consolas, Monaco, monospace;\n font-size: 11px;\n cursor: pointer;\n user-select: none;\n}\n\n.designer-props-bind:hover {\n border-color: #1677ff;\n color: #1677ff;\n}\n\n.designer-props-bind-active {\n border-color: #1677ff;\n background: #e6f4ff;\n color: #1677ff;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, h, watch } from \"vue\";\nimport { Collapse, type CollapseProps, Empty } from \"antdv-next\";\nimport { type PropsPanel, type Setter, type SetterGroup } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport SetterPropsGroup from \"./SetterPropsGroup.vue\";\n\ndefineOptions({ name: 'SetterPropsPanel' });\n\n// 定义 Props 类型\ninterface SetterPropsPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 设置器面板配置(来自 ComponentMeta.setter.props) */\n propsPanel?: PropsPanel;\n}\n\nconst props = defineProps<SetterPropsPanelProps>();\n\n// 分组展开状态\nconst expandGroups = computed(() => props.designerState.setterShareState.expandGroups);\n\n/** 过滤隐藏的设置器后的分组 */\nconst visibleGroups = computed<Array<SetterGroup>>(() => {\n const node = props.designerState.selectNode;\n if (!node) return [];\n return (props.propsPanel?.groups ?? [])\n .map(group => {\n const items = group.items.filter(item => !isHideSetter(item));\n return { ...group, items };\n })\n .filter(group => group.items.length > 0);\n});\n\n/** 是否隐藏当前Setter组件 */\nfunction isHideSetter(setter: Setter): boolean {\n if (!setter.isHideSetter) return false;\n const node = props.designerState.selectNode;\n if (!node) return false;\n return setter.isHideSetter(node, props.designerState.selectNodes, undefined as any) === true;\n}\n\nconst collapseItems = computed<NonNullable<CollapseProps[\"items\"]>>(() =>\n visibleGroups.value.map(group => ({\n key: group.title,\n label: group.title,\n content: h(SetterPropsGroup, { designerState: props.designerState, group }),\n })),\n);\n\n// 选中组件变化时重新计算分组展开状态\nwatch(() => props.designerState.selectedComponentMeta, () => {\n props.designerState.setterShareState.recalcExpandGroups();\n}, { immediate: true });\n</script>\n\n<template>\n <!-- key 绑定面板刷新版本: 切换数据绑定/命令修改后 setter 输入框需重读节点值 -->\n <div :key=\"props.designerState.setterShareState.panelVersion\" class=\"designer-props-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <div class=\"designer-props-node\">\n <span class=\"designer-props-node-name\">{{ props.designerState.selectedComponentMeta?.name ?? \"-\" }}</span>\n <span class=\"designer-props-node-type\">{{ props.designerState.selectNode?.type }}</span>\n </div>\n <Collapse v-model:activeKey=\"(expandGroups as any).props\" ghost size=\"small\" :items=\"collapseItems\" />\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-props-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n font-size: 12px;\n}\n\n.designer-props-node {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n border-bottom: 1px solid #f3f4f6;\n}\n\n.designer-props-node-name {\n font-weight: 600;\n color: #111827;\n}\n\n.designer-props-node-type {\n font-family: Consolas, Monaco, monospace;\n font-size: 11px;\n color: #9ca3af;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, h, watch } from \"vue\";\nimport { Collapse, type CollapseProps, Empty } from \"antdv-next\";\nimport { type PropsPanel, type Setter, type SetterGroup } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport SetterPropsGroup from \"./SetterPropsGroup.vue\";\n\ndefineOptions({ name: 'SetterPropsPanel' });\n\n// 定义 Props 类型\ninterface SetterPropsPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 设置器面板配置(来自 ComponentMeta.setter.props) */\n propsPanel?: PropsPanel;\n}\n\nconst props = defineProps<SetterPropsPanelProps>();\n\n// 分组展开状态\nconst expandGroups = computed(() => props.designerState.setterShareState.expandGroups);\n\n/** 过滤隐藏的设置器后的分组 */\nconst visibleGroups = computed<Array<SetterGroup>>(() => {\n const node = props.designerState.selectNode;\n if (!node) return [];\n return (props.propsPanel?.groups ?? [])\n .map(group => {\n const items = group.items.filter(item => !isHideSetter(item));\n return { ...group, items };\n })\n .filter(group => group.items.length > 0);\n});\n\n/** 是否隐藏当前Setter组件 */\nfunction isHideSetter(setter: Setter): boolean {\n if (!setter.isHideSetter) return false;\n const node = props.designerState.selectNode;\n if (!node) return false;\n return setter.isHideSetter(node, props.designerState.selectNodes, undefined as any) === true;\n}\n\nconst collapseItems = computed<NonNullable<CollapseProps[\"items\"]>>(() =>\n visibleGroups.value.map(group => ({\n key: group.title,\n label: group.title,\n content: h(SetterPropsGroup, { designerState: props.designerState, group }),\n })),\n);\n\n// 选中组件变化时重新计算分组展开状态\nwatch(() => props.designerState.selectedComponentMeta, () => {\n props.designerState.setterShareState.recalcExpandGroups();\n}, { immediate: true });\n</script>\n\n<template>\n <!-- key 绑定面板刷新版本: 切换数据绑定/命令修改后 setter 输入框需重读节点值 -->\n <div :key=\"props.designerState.setterShareState.panelVersion\" class=\"designer-props-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <div class=\"designer-props-node\">\n <span class=\"designer-props-node-name\">{{ props.designerState.selectedComponentMeta?.name ?? \"-\" }}</span>\n <span class=\"designer-props-node-type\">{{ props.designerState.selectNode?.type }}</span>\n </div>\n <Collapse v-model:activeKey=\"(expandGroups as any).props\" ghost size=\"small\" :items=\"collapseItems\" />\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-props-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n font-size: 12px;\n}\n\n.designer-props-node {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n border-bottom: 1px solid #f3f4f6;\n}\n\n.designer-props-node-name {\n font-weight: 600;\n color: #111827;\n}\n\n.designer-props-node-type {\n font-family: Consolas, Monaco, monospace;\n font-size: 11px;\n color: #9ca3af;\n}\n</style>\n","/** 样式分组声明: 纯数据声明 + SetterStylePanel 通用渲染, 读写同一 node.props.style */\n\n/** 样式设置项使用的原子 setter 控件类型 */\ntype StyleSetterCmp = \"StringSetter\" | \"NumberSetter\" | \"SelectSetter\" | \"ColorSetter\";\n\n/** 单个样式设置项声明 */\ninterface StyleItemDefine {\n /** CSS 属性名(支持 kebab-case, 存入 style 对象) */\n property: string;\n /** 显示名称 */\n label: string;\n /** 控件类型 */\n cmp: StyleSetterCmp;\n /** SelectSetter 的选项 */\n options?: Array<{ value: string; label: string }>;\n /** NumberSetter 的单位后缀(显示用) */\n suffix?: string;\n}\n\n/** 一组样式设置声明 */\ninterface StyleGroupDefine {\n /** 分组标题 */\n title: string;\n /** 对应 StylePanel 配置的禁用开关字段名 */\n disableKey?: \"disableLayout\" | \"disableSpacing\" | \"disableSize\" | \"disablePosition\" | \"disableFont\" | \"disableBorder\" | \"disableEffect\";\n /** 显示条件(当前 style 值判断, 如 display=flex 时才显示 flex 项) */\n visible?: (style: Record<string, any>) => boolean;\n /** 样式设置项 */\n items: Array<StyleItemDefine>;\n}\n\n/** display 属性的选项 */\nconst displayOptions = [\n { value: \"block\", label: \"块级(block)\" },\n { value: \"inline-block\", label: \"行内块(inline-block)\" },\n { value: \"inline\", label: \"行内(inline)\" },\n { value: \"flex\", label: \"弹性(flex)\" },\n { value: \"inline-flex\", label: \"行内弹性(inline-flex)\" },\n { value: \"grid\", label: \"网格(grid)\" },\n { value: \"inline-grid\", label: \"行内网格(inline-grid)\" },\n { value: \"none\", label: \"隐藏(none)\" },\n];\n\nconst isFlexDisplay = (style: Record<string, any>) => String(style[\"display\"] ?? \"\").includes(\"flex\");\nconst isGridDisplay = (style: Record<string, any>) => String(style[\"display\"] ?? \"\").includes(\"grid\");\n\n/** 全部样式分组声明(顺序即面板显示顺序) */\nconst styleGroupDefines: Array<StyleGroupDefine> = [\n {\n title: \"布局\",\n disableKey: \"disableLayout\",\n items: [\n { property: \"display\", label: \"显示类型\", cmp: \"SelectSetter\", options: displayOptions },\n { property: \"flexDirection\", label: \"主轴方向\", cmp: \"SelectSetter\", options: [\n { value: \"row\", label: \"水平(row)\" },\n { value: \"column\", label: \"垂直(column)\" },\n { value: \"row-reverse\", label: \"水平反转\" },\n { value: \"column-reverse\", label: \"垂直反转\" },\n ], },\n { property: \"justifyContent\", label: \"主轴对齐\", cmp: \"SelectSetter\", options: [\n { value: \"flex-start\", label: \"起始\" },\n { value: \"center\", label: \"居中\" },\n { value: \"flex-end\", label: \"末尾\" },\n { value: \"space-between\", label: \"两端\" },\n { value: \"space-around\", label: \"环绕\" },\n { value: \"space-evenly\", label: \"均分\" },\n ] },\n { property: \"alignItems\", label: \"交叉对齐\", cmp: \"SelectSetter\", options: [\n { value: \"flex-start\", label: \"起始\" },\n { value: \"center\", label: \"居中\" },\n { value: \"flex-end\", label: \"末尾\" },\n { value: \"stretch\", label: \"拉伸\" },\n { value: \"baseline\", label: \"基线\" },\n ] },\n { property: \"flexWrap\", label: \"换行\", cmp: \"SelectSetter\", options: [\n { value: \"nowrap\", label: \"不换行\" },\n { value: \"wrap\", label: \"换行\" },\n { value: \"wrap-reverse\", label: \"反转换行\" },\n ] },\n { property: \"gap\", label: \"间距\", cmp: \"StringSetter\" },\n ],\n },\n {\n title: \"网格\",\n visible: isGridDisplay,\n items: [\n { property: \"gridTemplateColumns\", label: \"列模板\", cmp: \"StringSetter\" },\n { property: \"gridTemplateRows\", label: \"行模板\", cmp: \"StringSetter\" },\n { property: \"gridAutoFlow\", label: \"排列方向\", cmp: \"SelectSetter\", options: [\n { value: \"row\", label: \"按行\" },\n { value: \"column\", label: \"按列\" },\n { value: \"dense\", label: \"密集\" },\n ] },\n { property: \"gridGap\", label: \"网格间距\", cmp: \"StringSetter\" },\n ],\n },\n {\n title: \"间距\",\n disableKey: \"disableSpacing\",\n items: [\n { property: \"margin\", label: \"外边距\", cmp: \"StringSetter\" },\n { property: \"marginTop\", label: \"外边距(上)\", cmp: \"StringSetter\" },\n { property: \"marginRight\", label: \"外边距(右)\", cmp: \"StringSetter\" },\n { property: \"marginBottom\", label: \"外边距(下)\", cmp: \"StringSetter\" },\n { property: \"marginLeft\", label: \"外边距(左)\", cmp: \"StringSetter\" },\n { property: \"padding\", label: \"内边距\", cmp: \"StringSetter\" },\n { property: \"paddingTop\", label: \"内边距(上)\", cmp: \"StringSetter\" },\n { property: \"paddingRight\", label: \"内边距(右)\", cmp: \"StringSetter\" },\n { property: \"paddingBottom\", label: \"内边距(下)\", cmp: \"StringSetter\" },\n { property: \"paddingLeft\", label: \"内边距(左)\", cmp: \"StringSetter\" },\n ],\n },\n {\n title: \"尺寸\",\n disableKey: \"disableSize\",\n items: [\n { property: \"width\", label: \"宽度\", cmp: \"StringSetter\" },\n { property: \"height\", label: \"高度\", cmp: \"StringSetter\" },\n { property: \"minWidth\", label: \"最小宽度\", cmp: \"StringSetter\" },\n { property: \"minHeight\", label: \"最小高度\", cmp: \"StringSetter\" },\n { property: \"maxWidth\", label: \"最大宽度\", cmp: \"StringSetter\" },\n { property: \"maxHeight\", label: \"最大高度\", cmp: \"StringSetter\" },\n ],\n },\n {\n title: \"定位\",\n disableKey: \"disablePosition\",\n items: [\n { property: \"position\", label: \"定位方式\", cmp: \"SelectSetter\", options: [\n { value: \"static\", label: \"静态\" },\n { value: \"relative\", label: \"相对\" },\n { value: \"absolute\", label: \"绝对\" },\n { value: \"fixed\", label: \"固定\" },\n { value: \"sticky\", label: \"粘性\" },\n ] },\n { property: \"top\", label: \"上偏移\", cmp: \"StringSetter\" },\n { property: \"right\", label: \"右偏移\", cmp: \"StringSetter\" },\n { property: \"bottom\", label: \"下偏移\", cmp: \"StringSetter\" },\n { property: \"left\", label: \"左偏移\", cmp: \"StringSetter\" },\n { property: \"zIndex\", label: \"层级\", cmp: \"StringSetter\" },\n ],\n },\n {\n title: \"文本\",\n disableKey: \"disableFont\",\n items: [\n { property: \"fontSize\", label: \"字号\", cmp: \"StringSetter\" },\n { property: \"fontWeight\", label: \"字重\", cmp: \"SelectSetter\", options: [\n { value: \"normal\", label: \"常规\" },\n { value: \"bold\", label: \"加粗\" },\n { value: \"300\", label: \"细\" },\n { value: \"500\", label: \"中\" },\n { value: \"600\", label: \"半粗\" },\n { value: \"800\", label: \"特粗\" },\n ] },\n { property: \"color\", label: \"颜色\", cmp: \"ColorSetter\" },\n { property: \"textAlign\", label: \"对齐\", cmp: \"SelectSetter\", options: [\n { value: \"left\", label: \"左\" },\n { value: \"center\", label: \"中\" },\n { value: \"right\", label: \"右\" },\n { value: \"justify\", label: \"两端\" },\n ] },\n { property: \"lineHeight\", label: \"行高\", cmp: \"StringSetter\" },\n { property: \"fontFamily\", label: \"字体\", cmp: \"StringSetter\" },\n { property: \"textDecoration\", label: \"修饰\", cmp: \"SelectSetter\", options: [\n { value: \"none\", label: \"无\" },\n { value: \"underline\", label: \"下划线\" },\n { value: \"line-through\", label: \"删除线\" },\n { value: \"overline\", label: \"上划线\" },\n ] },\n ],\n },\n {\n title: \"边框\",\n disableKey: \"disableBorder\",\n items: [\n { property: \"borderWidth\", label: \"边框宽度\", cmp: \"StringSetter\" },\n { property: \"borderStyle\", label: \"边框样式\", cmp: \"SelectSetter\", options: [\n { value: \"none\", label: \"无\" },\n { value: \"solid\", label: \"实线\" },\n { value: \"dashed\", label: \"虚线\" },\n { value: \"dotted\", label: \"点线\" },\n { value: \"double\", label: \"双线\" },\n ] },\n { property: \"borderColor\", label: \"边框颜色\", cmp: \"ColorSetter\" },\n { property: \"borderRadius\", label: \"圆角\", cmp: \"StringSetter\" },\n ],\n },\n {\n title: \"背景与效果\",\n disableKey: \"disableEffect\",\n items: [\n { property: \"backgroundColor\", label: \"背景颜色\", cmp: \"ColorSetter\" },\n { property: \"backgroundImage\", label: \"背景图片\", cmp: \"StringSetter\" },\n { property: \"opacity\", label: \"不透明度\", cmp: \"StringSetter\" },\n { property: \"boxShadow\", label: \"阴影\", cmp: \"StringSetter\" },\n { property: \"cursor\", label: \"光标\", cmp: \"SelectSetter\", options: [\n { value: \"auto\", label: \"自动\" },\n { value: \"pointer\", label: \"手型\" },\n { value: \"not-allowed\", label: \"禁止\" },\n { value: \"move\", label: \"移动\" },\n { value: \"text\", label: \"文本\" },\n ] },\n { property: \"overflow\", label: \"溢出\", cmp: \"SelectSetter\", options: [\n { value: \"visible\", label: \"可见\" },\n { value: \"hidden\", label: \"隐藏\" },\n { value: \"auto\", label: \"自动\" },\n { value: \"scroll\", label: \"滚动\" },\n ] },\n ],\n },\n];\n\nexport type {\n StyleSetterCmp,\n StyleItemDefine,\n StyleGroupDefine,\n}\n\nexport {\n styleGroupDefines,\n}\n","import lodash from \"lodash\";\nimport { parseStringStyle } from \"@vue/shared\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport type { StyleSetterProps, StyleSetterState } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../models/DesignerState\";\nimport type { UpdatePropsChange } from \"../operations/commands/UpdatePropsCommand\";\nimport { UpdatePropsCommand } from \"../operations/commands/UpdatePropsCommand\";\n\n/** 调用 applyStyle 的防抖时间(毫秒) */\nconst applyStyleDebounceTime = 350;\n\n/** 获取 state 默认值 */\nfunction getDefState(): StyleSetterState {\n return {\n style: {},\n };\n}\n\n/** 把 style 属性值转换成对象形式(字符串样式表转对象) */\nfunction toObjectStyle(style: any): Record<string, any> | undefined {\n if (Typeof.noValue(style)) return;\n if (Typeof.isStr(style)) {\n try {\n return parseStringStyle(style);\n } catch {\n return;\n }\n }\n if (Typeof.isObj(style)) return style;\n return;\n}\n\n/**\n * 获取 style property 值(多节点取值不一致时返回 undefined 且 multipleValuesUpdate(true))\n * @param props 样式设置器 props\n * @param styleProperty 样式属性名(支持 \"font.size\" 形式的key path)\n * @param transform 值转换函数\n */\nfunction getStyle<R = any>(props: StyleSetterProps, styleProperty: string, transform?: (value: any) => R, multipleValuesUpdate?: (multipleValues: boolean) => void): R | undefined {\n const { nodes } = props;\n if (!nodes) return;\n const values = new Set<any>();\n for (const node of nodes) {\n let value: any = undefined;\n const style = toObjectStyle(node.props?.style);\n if (style) value = lodash.get(style, styleProperty);\n if (Typeof.isFunction(transform)) value = transform(value);\n if (Typeof.noValue(value)) value = undefined;\n values.add(value);\n if (values.size > 1) break;\n }\n if (values.size <= 0) return;\n if (values.size === 1) return values.values().next().value;\n multipleValuesUpdate?.(true);\n return;\n}\n\n/** applyStyle 的待应用缓冲(同一防抖窗口内的多次修改合并成一条命令, 避免防抖丢弃靠前的修改) */\nlet applyStylePending: { props: StyleSetterProps; styleValues: Record<string, any> } | undefined;\n\n/**\n * 防抖冲刷 applyStyle 缓冲: 构造样式修改命令并执行\n * 防抖期间未写入节点, 冲刷时读到的仍是修改前的旧值, 恰好作为命令的 oldValue 快照\n */\nconst applyStyleDebounced = lodash.debounce(function (): void {\n const pending = applyStylePending;\n applyStylePending = undefined;\n if (!pending) return;\n const { props, styleValues } = pending;\n const designerState: DesignerState = props.designerState;\n const { nodes } = props;\n if (!nodes || nodes.length <= 0) return;\n const changes: Array<UpdatePropsChange> = [];\n for (const node of nodes) {\n const style = toObjectStyle(node.props?.style) ?? {};\n const oldValue: Record<string, any> = {};\n for (const property in styleValues) {\n oldValue[property] = lodash.get(style, property);\n }\n changes.push({\n nodeId: node.id,\n // 样式域整体作为合并标识: 一次调整会话中的多个样式属性合并成一条历史\n changeKey: \"style\",\n oldValue,\n newValue: { ...styleValues },\n write: (target, values) => {\n const targetStyle = toObjectStyle(target.props?.style) ?? {};\n for (const property in values) {\n const value = values[property];\n if (Typeof.noValue(value) || (Typeof.isStr(value) && lodash.trim(value).length <= 0)) {\n lodash.unset(targetStyle, property);\n } else {\n lodash.set(targetStyle, property, value);\n }\n }\n target.props.style = targetStyle;\n },\n });\n }\n if (changes.length <= 0) return;\n designerState.commandStack.execute(new UpdatePropsCommand(designerState, \"修改样式\", { changes }));\n}, applyStyleDebounceTime);\n\n/**\n * 应用 style property 值到组件节点(值为空时删除属性)\n * 同一防抖窗口内的多次调用按属性合并缓冲, 到期一次性经命令写入:\n * 整体防抖会把窗口内靠前的修改参数丢掉, 缓冲合并后每个属性的修改都会保留\n */\nfunction applyStyle(props: StyleSetterProps, styleValues: Record<string, any>): void {\n if (!applyStylePending || applyStylePending.props !== props) {\n // 切换了修改上下文(不同面板/不同节点集合): 先冲刷旧缓冲\n if (applyStylePending) applyStyleDebounced.flush();\n applyStylePending = { props, styleValues: {} };\n }\n Object.assign(applyStylePending.styleValues, styleValues);\n applyStyleDebounced();\n}\n\n/**\n * 应用 class 值到组件节点(切换主题 class, 额外 class 由本函数全权管理)\n * 最终 class = 组件自身配置的 rawClass + 主题 class, 经由命令写入(可撤销)\n */\nfunction applyClass(props: StyleSetterProps, cls: string | undefined): void {\n const { designerState, nodes } = props;\n if (!nodes || nodes.length <= 0) return;\n const trimCls = lodash.trim(cls ?? \"\");\n const changes: Array<UpdatePropsChange> = [];\n for (const node of nodes) {\n // rawClass 是组件自身配置的 class(首次应用时记录)\n if (Typeof.noValue(node.designExt.rawPropsClass)) {\n node.designExt.rawPropsClass = node.props.class ?? \"\";\n }\n const rawClass = lodash.trim(node.designExt.rawPropsClass);\n const newClass = [rawClass, trimCls].filter(item => item.length > 0).join(\" \");\n const oldValue = node.props.class;\n if (lodash.trim(oldValue ?? \"\") === newClass) continue;\n changes.push({\n nodeId: node.id,\n changeKey: \"class\",\n oldValue,\n newValue: newClass.length > 0 ? newClass : undefined,\n write: (target, value) => {\n target.props.class = value;\n },\n });\n }\n if (changes.length <= 0) return;\n designerState.commandStack.execute(new UpdatePropsCommand(designerState, \"切换主题样式\", { changes }));\n}\n\n/**\n * 获取当前主题 class(meta.componentStyles 中匹配的 class, 不匹配返回空)\n */\nfunction getActiveClass(props: StyleSetterProps, componentClasses: Array<{ name: string; class: string }>): string | undefined {\n const { nodes } = props;\n if (!nodes || nodes.length !== 1) return;\n const node = nodes[0];\n if (Typeof.noValue(node.designExt.rawPropsClass)) {\n node.designExt.rawPropsClass = node.props.class ?? \"\";\n }\n const rawClass = lodash.trim(node.designExt.rawPropsClass);\n const extraClass = lodash.trim(node.props.class?.substring(rawClass.length) ?? \"\");\n const found = componentClasses.find(item => item.class === extraClass);\n return found?.class;\n}\n\nexport {\n applyStyleDebounceTime,\n getDefState,\n toObjectStyle,\n getStyle,\n applyStyle,\n applyClass,\n getActiveClass,\n}\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport type { StyleSetterProps } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport { type StyleGroupDefine, type StyleItemDefine } from \"./style/StyleGroups\";\nimport { applyStyle, getStyle } from \"../../utils/StyleUtils\";\n\ndefineOptions({ name: 'SetterStyleGroup' });\n\n// 定义 Props 类型\ninterface SetterStyleGroupProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 生效的样式分组 */\n group: StyleGroupDefine;\n}\n\nconst props = defineProps<SetterStyleGroupProps>();\n\n// 样式设置器上下文 props\nconst styleSetterProps = computed<StyleSetterProps>(() => {\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: props.designerState.selectNodes,\n };\n});\n\n/** 读取某个样式项的当前值 */\nfunction getItemValue(item: StyleItemDefine): any {\n return getStyle(styleSetterProps.value, item.property);\n}\n\n/** 应用某个样式项的值 */\nfunction applyItemValue(item: StyleItemDefine, value: any): void {\n applyStyle(styleSetterProps.value, { [item.property]: value });\n}\n\n/** 通用渲染项的 props(传给原子 setter 组件) */\nfunction getSetterItemProps(item: StyleItemDefine): any {\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: props.designerState.selectNodes,\n // 直接读写 style 属性: 借用 Setter 协议的 getPropsValue/applyPropsValue 钩子\n getPropsValue: (_props: any) => getItemValue(item),\n applyPropsValue: (_props: any, value: any) => {\n applyItemValue(item, value);\n return false; // 已自行处理重渲染\n },\n ...(item.cmp === \"SelectSetter\" ? { options: item.options } : {}),\n };\n}\n\n/** setter 组件名解析 */\nfunction getSetterCmp(cmp: string): any {\n return props.designerState.designerEngine.componentManage.getComponent(cmp);\n}\n</script>\n\n<template>\n <div v-for=\"(item, idx) in props.group.items\" :key=\"item.property + idx\" class=\"designer-style-item\">\n <div class=\"designer-style-label\">\n <span :title=\"item.property\">{{ item.label }}</span>\n </div>\n <div class=\"designer-style-control\">\n <component\n :is=\"getSetterCmp(item.cmp)\"\n v-if=\"getSetterCmp(item.cmp)\"\n v-bind=\"getSetterItemProps(item)\"\n />\n </div>\n </div>\n</template>\n\n<style scoped>\n.designer-style-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 0;\n}\n\n.designer-style-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.designer-style-control {\n flex: 1;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport type { StyleSetterProps } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport { type StyleGroupDefine, type StyleItemDefine } from \"./style/StyleGroups\";\nimport { applyStyle, getStyle } from \"../../utils/StyleUtils\";\n\ndefineOptions({ name: 'SetterStyleGroup' });\n\n// 定义 Props 类型\ninterface SetterStyleGroupProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 生效的样式分组 */\n group: StyleGroupDefine;\n}\n\nconst props = defineProps<SetterStyleGroupProps>();\n\n// 样式设置器上下文 props\nconst styleSetterProps = computed<StyleSetterProps>(() => {\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: props.designerState.selectNodes,\n };\n});\n\n/** 读取某个样式项的当前值 */\nfunction getItemValue(item: StyleItemDefine): any {\n return getStyle(styleSetterProps.value, item.property);\n}\n\n/** 应用某个样式项的值 */\nfunction applyItemValue(item: StyleItemDefine, value: any): void {\n applyStyle(styleSetterProps.value, { [item.property]: value });\n}\n\n/** 通用渲染项的 props(传给原子 setter 组件) */\nfunction getSetterItemProps(item: StyleItemDefine): any {\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: props.designerState.selectNodes,\n // 直接读写 style 属性: 借用 Setter 协议的 getPropsValue/applyPropsValue 钩子\n getPropsValue: (_props: any) => getItemValue(item),\n applyPropsValue: (_props: any, value: any) => {\n applyItemValue(item, value);\n return false; // 已自行处理重渲染\n },\n ...(item.cmp === \"SelectSetter\" ? { options: item.options } : {}),\n };\n}\n\n/** setter 组件名解析 */\nfunction getSetterCmp(cmp: string): any {\n return props.designerState.designerEngine.componentManage.getComponent(cmp);\n}\n</script>\n\n<template>\n <div v-for=\"(item, idx) in props.group.items\" :key=\"item.property + idx\" class=\"designer-style-item\">\n <div class=\"designer-style-label\">\n <span :title=\"item.property\">{{ item.label }}</span>\n </div>\n <div class=\"designer-style-control\">\n <component\n :is=\"getSetterCmp(item.cmp)\"\n v-if=\"getSetterCmp(item.cmp)\"\n v-bind=\"getSetterItemProps(item)\"\n />\n </div>\n </div>\n</template>\n\n<style scoped>\n.designer-style-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 0;\n}\n\n.designer-style-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.designer-style-control {\n flex: 1;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, h, watch } from \"vue\";\nimport { Collapse, type CollapseProps, Empty, Select } from \"antdv-next\";\nimport type { StylePanel, StyleSetterProps } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport { type StyleGroupDefine, styleGroupDefines } from \"./style/StyleGroups\";\nimport { applyClass, getActiveClass, toObjectStyle } from \"../../utils/StyleUtils\";\nimport SetterStyleGroup from \"./SetterStyleGroup.vue\";\n\ndefineOptions({ name: 'SetterStylePanel' });\n\n// 定义 Props 类型\ninterface SetterStylePanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 样式设置器面板配置(来自 ComponentMeta.setter.style) */\n stylePanel?: StylePanel;\n}\n\nconst props = defineProps<SetterStylePanelProps>();\n\n// 样式设置器上下文 props\nconst styleSetterProps = computed<StyleSetterProps>(() => {\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: props.designerState.selectNodes,\n };\n});\n\n/** 当前选中节点的 style 对象 */\nconst currentStyle = computed<Record<string, any>>(() => {\n const node = props.designerState.selectNode;\n if (!node) return {};\n return toObjectStyle(node.props?.style) ?? {};\n});\n\n/** 生效的分组(过滤禁用项与不满足显示条件的分组) */\nconst visibleGroups = computed<Array<StyleGroupDefine>>(() => {\n const disable = props.stylePanel ?? {};\n const style = currentStyle.value;\n return styleGroupDefines.filter(group => {\n if (group.disableKey && (disable as any)[group.disableKey]) return false;\n if (group.visible && !group.visible(style)) return false;\n return true;\n });\n});\n\n/** 组件主题 class 选项(meta.componentStyles) */\nconst componentStyleOptions = computed(() => {\n return props.designerState.selectedComponentMeta?.setter.style?.componentStyles?.map(item => ({\n value: item.class,\n label: item.name,\n })) ?? [];\n});\n\n/** 组件主题 class 当前值 */\nconst activeClass = computed(() => getActiveClass(\n styleSetterProps.value,\n props.designerState.selectedComponentMeta?.setter.style?.componentStyles ?? [],\n));\n\n/** 切换主题 class */\nfunction onClassChange(cls: string | undefined): void {\n applyClass(styleSetterProps.value, cls);\n}\n\nconst collapseItems = computed<NonNullable<CollapseProps[\"items\"]>>(() =>\n visibleGroups.value.map(group => ({\n key: group.title,\n label: group.title,\n content: h(SetterStyleGroup, { designerState: props.designerState, group }),\n })),\n);\n\n// 分组展开状态\nconst expandKeys = computed({\n get: () => (props.designerState.setterShareState.expandGroups.style ?? []).slice(),\n set: (value: Array<string>) => {\n props.designerState.setterShareState.expandGroups = {\n ...props.designerState.setterShareState.expandGroups,\n style: value,\n };\n },\n});\n\nwatch(() => props.designerState.selectedComponentMeta, () => {\n props.designerState.setterShareState.recalcExpandGroups();\n});\n</script>\n\n<template>\n <div class=\"designer-style-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <!-- 组件内置主题 -->\n <div v-if=\"componentStyleOptions.length > 0\" class=\"designer-style-theme-item\">\n <div class=\"designer-style-theme-label\">主题样式</div>\n <div class=\"designer-style-theme-control\">\n <Select\n allowClear\n placeholder=\"选择主题\"\n :options=\"componentStyleOptions\"\n :value=\"activeClass || undefined\"\n @change=\"onClassChange\"\n />\n </div>\n </div>\n <Collapse v-model:activeKey=\"expandKeys\" ghost size=\"small\" :items=\"collapseItems\" />\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-style-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n font-size: 12px;\n}\n\n.designer-style-theme-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 0;\n}\n\n.designer-style-theme-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.designer-style-theme-control {\n flex: 1;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, h, watch } from \"vue\";\nimport { Collapse, type CollapseProps, Empty, Select } from \"antdv-next\";\nimport type { StylePanel, StyleSetterProps } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport { type StyleGroupDefine, styleGroupDefines } from \"./style/StyleGroups\";\nimport { applyClass, getActiveClass, toObjectStyle } from \"../../utils/StyleUtils\";\nimport SetterStyleGroup from \"./SetterStyleGroup.vue\";\n\ndefineOptions({ name: 'SetterStylePanel' });\n\n// 定义 Props 类型\ninterface SetterStylePanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 样式设置器面板配置(来自 ComponentMeta.setter.style) */\n stylePanel?: StylePanel;\n}\n\nconst props = defineProps<SetterStylePanelProps>();\n\n// 样式设置器上下文 props\nconst styleSetterProps = computed<StyleSetterProps>(() => {\n return {\n designerState: props.designerState,\n blockInstance: props.designerState.blockInstance!,\n nodes: props.designerState.selectNodes,\n };\n});\n\n/** 当前选中节点的 style 对象 */\nconst currentStyle = computed<Record<string, any>>(() => {\n const node = props.designerState.selectNode;\n if (!node) return {};\n return toObjectStyle(node.props?.style) ?? {};\n});\n\n/** 生效的分组(过滤禁用项与不满足显示条件的分组) */\nconst visibleGroups = computed<Array<StyleGroupDefine>>(() => {\n const disable = props.stylePanel ?? {};\n const style = currentStyle.value;\n return styleGroupDefines.filter(group => {\n if (group.disableKey && (disable as any)[group.disableKey]) return false;\n if (group.visible && !group.visible(style)) return false;\n return true;\n });\n});\n\n/** 组件主题 class 选项(meta.componentStyles) */\nconst componentStyleOptions = computed(() => {\n return props.designerState.selectedComponentMeta?.setter.style?.componentStyles?.map(item => ({\n value: item.class,\n label: item.name,\n })) ?? [];\n});\n\n/** 组件主题 class 当前值 */\nconst activeClass = computed(() => getActiveClass(\n styleSetterProps.value,\n props.designerState.selectedComponentMeta?.setter.style?.componentStyles ?? [],\n));\n\n/** 切换主题 class */\nfunction onClassChange(cls: string | undefined): void {\n applyClass(styleSetterProps.value, cls);\n}\n\nconst collapseItems = computed<NonNullable<CollapseProps[\"items\"]>>(() =>\n visibleGroups.value.map(group => ({\n key: group.title,\n label: group.title,\n content: h(SetterStyleGroup, { designerState: props.designerState, group }),\n })),\n);\n\n// 分组展开状态\nconst expandKeys = computed({\n get: () => (props.designerState.setterShareState.expandGroups.style ?? []).slice(),\n set: (value: Array<string>) => {\n props.designerState.setterShareState.expandGroups = {\n ...props.designerState.setterShareState.expandGroups,\n style: value,\n };\n },\n});\n\nwatch(() => props.designerState.selectedComponentMeta, () => {\n props.designerState.setterShareState.recalcExpandGroups();\n});\n</script>\n\n<template>\n <div class=\"designer-style-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <!-- 组件内置主题 -->\n <div v-if=\"componentStyleOptions.length > 0\" class=\"designer-style-theme-item\">\n <div class=\"designer-style-theme-label\">主题样式</div>\n <div class=\"designer-style-theme-control\">\n <Select\n allowClear\n placeholder=\"选择主题\"\n :options=\"componentStyleOptions\"\n :value=\"activeClass || undefined\"\n @change=\"onClassChange\"\n />\n </div>\n </div>\n <Collapse v-model:activeKey=\"expandKeys\" ghost size=\"small\" :items=\"collapseItems\" />\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-style-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n font-size: 12px;\n}\n\n.designer-style-theme-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 0;\n}\n\n.designer-style-theme-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.designer-style-theme-control {\n flex: 1;\n min-width: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, reactive } from \"vue\";\nimport { Button, Empty, Tag } from \"antdv-next\";\nimport lodash from \"lodash\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { createFun, type RuntimeNode, toPropsEventName } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport { type UpdateListenersChange, UpdateListenersCommand } from \"../../operations/commands/UpdateListenersCommand\";\n\ndefineOptions({ name: 'SetterEventPanel' });\n\n// 定义 Props 类型\ninterface SetterEventPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 事件面板配置(来自 ComponentMeta.setter.events) */\n eventPanel?: { includeInnerEvents?: any; excludeInnerEvents?: Array<string>; groups?: Array<any> };\n}\n\nconst props = defineProps<SetterEventPanelProps>();\n\n// 内置事件项(展示用, 仅需名称与描述)\ninterface InnerEventInfo {\n name: string;\n description?: string;\n}\n\n/** 内置的 html 原生事件分组 */\nconst innerEventGroups: Array<{ title: string; items: Array<InnerEventInfo> }> = [\n {\n title: \"鼠标事件\",\n items: [\n { name: \"click\", description: \"单击\" },\n { name: \"dblclick\", description: \"双击\" },\n { name: \"mouseenter\", description: \"移入\" },\n { name: \"mouseleave\", description: \"移出\" },\n { name: \"mousedown\", description: \"按下\" },\n { name: \"mouseup\", description: \"弹起\" },\n ],\n },\n {\n title: \"键盘事件\",\n items: [\n { name: \"keydown\", description: \"按下\" },\n { name: \"keyup\", description: \"弹起\" },\n ],\n },\n];\n\nconst nodes = computed<Array<RuntimeNode>>(() => props.designerState.selectNodes);\n\n/** 显示的事件分组(meta 配置的分组 + 内置事件分组) */\nconst eventGroups = computed<Array<{ title: string; items: Array<any> }>>(() => {\n const groups: Array<{ title: string; items: Array<any> }> = [];\n const metaGroups = props.eventPanel?.groups;\n if (metaGroups && metaGroups.length > 0) groups.push(...metaGroups as any);\n const exclude = props.eventPanel?.excludeInnerEvents;\n if (props.eventPanel?.includeInnerEvents !== false) {\n for (const group of innerEventGroups) {\n if (exclude?.includes(group.title)) continue;\n groups.push(group);\n }\n }\n return groups;\n});\n\n/** 展开编辑的事件名 */\nconst editingEvent = reactive<{ event: string; code: string; new: boolean }>({\n event: \"\",\n code: \"\",\n new: false,\n});\n\n/** 事件名转 listeners 的 key(onXxx) */\nfunction toListenerKey(eventName: string): string {\n return toPropsEventName(eventName);\n}\n\n/** 读取事件监听器(多节点不一致返回 undefined) */\nfunction getListener(eventName: string): any {\n const key = toListenerKey(eventName);\n const values = new Set<any>();\n for (const node of nodes.value) {\n values.add(node.listeners[key]);\n }\n if (values.size !== 1) return;\n return values.values().next().value;\n}\n\n/** 是否已绑定 */\nfunction isBound(eventName: string): boolean {\n const listener = getListener(eventName);\n return !!listener?.handler;\n}\n\n/** 读取绑定的函数体字符串(从 handler 函数的 toString 提取) */\nfunction getBoundCode(eventName: string): string {\n const listener = getListener(eventName);\n const handler = listener?.handler;\n if (!Typeof.isFun(handler)) return \"\";\n try {\n const source = handler.toString();\n const matched = source.match(/\\{([\\s\\S]*)\\}$/);\n return matched ? matched[1].trim() : source;\n } catch {\n return \"\";\n }\n}\n\n/** 开始编辑(绑定/修改) */\nfunction startEdit(eventName: string): void {\n editingEvent.event = eventName;\n editingEvent.code = getBoundCode(eventName) || \"console.log('事件触发', event)\";\n editingEvent.new = !isBound(eventName);\n}\n\n/**\n * 保存事件绑定(函数体字符串经 runtime 的 createFun 转成真函数)\n * 经由 UpdateListenersCommand 执行: runtime ops 会同步维护 ext.bindListeners 与\n * methods 函数池, 直接写 node.listeners 不会同步这些状态, 事件将无法生效\n */\nfunction saveEdit(): void {\n const eventName = editingEvent.event;\n if (!eventName) return;\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const code = lodash.trim(editingEvent.code);\n let handler: any;\n try {\n if (code.length > 0) handler = createFun({ code });\n } catch (err) {\n console.warn(\"[EventPanel] 事件函数解析失败\", err);\n return;\n }\n const key = toListenerKey(eventName);\n const changes: Array<UpdateListenersChange> = [];\n for (const node of nodes.value) {\n const oldListener = node.listeners[key];\n // 函数体未变化不产生历史\n if (handler && oldListener?.handler\n && Function.prototype.toString.call(oldListener.handler) === Function.prototype.toString.call(handler)) continue;\n changes.push({\n nodeId: node.id,\n event: eventName,\n oldListener,\n newListener: handler ? { handler } : undefined,\n });\n }\n editingEvent.event = \"\";\n if (changes.length > 0) {\n designerState.commandStack.execute(new UpdateListenersCommand(designerState, `绑定事件 ${eventName}`, { changes }));\n }\n}\n\n/** 解绑事件 */\nfunction removeBind(eventName: string): void {\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const key = toListenerKey(eventName);\n const changes: Array<UpdateListenersChange> = [];\n for (const node of nodes.value) {\n const oldListener = node.listeners[key];\n if (!oldListener) continue;\n changes.push({\n nodeId: node.id,\n event: eventName,\n oldListener,\n newListener: undefined,\n });\n }\n if (changes.length > 0) {\n designerState.commandStack.execute(new UpdateListenersCommand(designerState, `解绑事件 ${eventName}`, { changes }));\n }\n}\n</script>\n\n<template>\n <!-- key 绑定面板刷新版本: 节点 listeners 是非响应式对象, 修改后靠版本号触发重新渲染 -->\n <div :key=\"props.designerState.setterShareState.panelVersion\" class=\"designer-event-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <div v-for=\"group in eventGroups\" :key=\"group.title\" class=\"designer-event-group\">\n <div class=\"designer-event-group-title\">{{ group.title }}</div>\n <div v-for=\"info in group.items\" :key=\"info.name\" class=\"designer-event-item\">\n <div class=\"designer-event-name\">\n {{ info.description ?? info.name }}\n <span class=\"designer-event-key\">{{ info.name }}</span>\n </div>\n <div class=\"designer-event-actions\">\n <Tag v-if=\"isBound(info.name)\" color=\"blue\" class=\"designer-event-tag\">已绑定</Tag>\n <Button size=\"small\" type=\"link\" @click=\"startEdit(info.name)\">{{ isBound(info.name) ? '编辑' : '绑定' }}</Button>\n <Button v-if=\"isBound(info.name)\" size=\"small\" type=\"link\" danger @click=\"removeBind(info.name)\">解绑</Button>\n </div>\n </div>\n </div>\n <!-- 函数体编辑区 -->\n <div v-if=\"editingEvent.event\" class=\"designer-event-editor\">\n <div class=\"designer-event-editor-title\">\n 编辑事件函数: <b>{{ editingEvent.event }}</b>\n </div>\n <textarea\n class=\"designer-event-textarea\"\n v-model=\"editingEvent.code\"\n placeholder=\"函数体字符串(如: console.log('click', event)), 留空清除绑定\"\n ></textarea>\n <div class=\"designer-event-editor-actions\">\n <Button size=\"small\" type=\"primary\" @click=\"saveEdit\">保存</Button>\n <Button size=\"small\" @click=\"editingEvent.event = ''\">取消</Button>\n </div>\n </div>\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-event-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n padding: 4px 0;\n font-size: 12px;\n}\n\n.designer-event-group-title {\n padding: 6px 12px 2px;\n font-weight: 600;\n color: #374151;\n}\n\n.designer-event-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 3px 12px;\n}\n\n.designer-event-name {\n color: #374151;\n}\n\n.designer-event-key {\n margin-left: 4px;\n font-family: Consolas, Monaco, monospace;\n font-size: 11px;\n color: #9ca3af;\n}\n\n.designer-event-tag {\n margin-right: 0;\n line-height: 16px;\n font-size: 11px;\n}\n\n.designer-event-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.designer-event-editor {\n margin: 8px 12px;\n padding: 8px;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n background: #fafafa;\n}\n\n.designer-event-editor-title {\n margin-bottom: 6px;\n color: #374151;\n}\n\n.designer-event-textarea {\n width: 100%;\n min-height: 72px;\n padding: 4px 8px;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n font-size: 12px;\n font-family: Consolas, Monaco, monospace;\n box-sizing: border-box;\n resize: vertical;\n}\n\n.designer-event-textarea:focus {\n outline: none;\n border-color: #1677ff;\n}\n\n.designer-event-editor-actions {\n display: flex;\n gap: 8px;\n margin-top: 6px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, reactive } from \"vue\";\nimport { Button, Empty, Tag } from \"antdv-next\";\nimport lodash from \"lodash\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { createFun, type RuntimeNode, toPropsEventName } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport { type UpdateListenersChange, UpdateListenersCommand } from \"../../operations/commands/UpdateListenersCommand\";\n\ndefineOptions({ name: 'SetterEventPanel' });\n\n// 定义 Props 类型\ninterface SetterEventPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 事件面板配置(来自 ComponentMeta.setter.events) */\n eventPanel?: { includeInnerEvents?: any; excludeInnerEvents?: Array<string>; groups?: Array<any> };\n}\n\nconst props = defineProps<SetterEventPanelProps>();\n\n// 内置事件项(展示用, 仅需名称与描述)\ninterface InnerEventInfo {\n name: string;\n description?: string;\n}\n\n/** 内置的 html 原生事件分组 */\nconst innerEventGroups: Array<{ title: string; items: Array<InnerEventInfo> }> = [\n {\n title: \"鼠标事件\",\n items: [\n { name: \"click\", description: \"单击\" },\n { name: \"dblclick\", description: \"双击\" },\n { name: \"mouseenter\", description: \"移入\" },\n { name: \"mouseleave\", description: \"移出\" },\n { name: \"mousedown\", description: \"按下\" },\n { name: \"mouseup\", description: \"弹起\" },\n ],\n },\n {\n title: \"键盘事件\",\n items: [\n { name: \"keydown\", description: \"按下\" },\n { name: \"keyup\", description: \"弹起\" },\n ],\n },\n];\n\nconst nodes = computed<Array<RuntimeNode>>(() => props.designerState.selectNodes);\n\n/** 显示的事件分组(meta 配置的分组 + 内置事件分组) */\nconst eventGroups = computed<Array<{ title: string; items: Array<any> }>>(() => {\n const groups: Array<{ title: string; items: Array<any> }> = [];\n const metaGroups = props.eventPanel?.groups;\n if (metaGroups && metaGroups.length > 0) groups.push(...metaGroups as any);\n const exclude = props.eventPanel?.excludeInnerEvents;\n if (props.eventPanel?.includeInnerEvents !== false) {\n for (const group of innerEventGroups) {\n if (exclude?.includes(group.title)) continue;\n groups.push(group);\n }\n }\n return groups;\n});\n\n/** 展开编辑的事件名 */\nconst editingEvent = reactive<{ event: string; code: string; new: boolean }>({\n event: \"\",\n code: \"\",\n new: false,\n});\n\n/** 事件名转 listeners 的 key(onXxx) */\nfunction toListenerKey(eventName: string): string {\n return toPropsEventName(eventName);\n}\n\n/** 读取事件监听器(多节点不一致返回 undefined) */\nfunction getListener(eventName: string): any {\n const key = toListenerKey(eventName);\n const values = new Set<any>();\n for (const node of nodes.value) {\n values.add(node.listeners[key]);\n }\n if (values.size !== 1) return;\n return values.values().next().value;\n}\n\n/** 是否已绑定 */\nfunction isBound(eventName: string): boolean {\n const listener = getListener(eventName);\n return !!listener?.handler;\n}\n\n/** 读取绑定的函数体字符串(从 handler 函数的 toString 提取) */\nfunction getBoundCode(eventName: string): string {\n const listener = getListener(eventName);\n const handler = listener?.handler;\n if (!Typeof.isFun(handler)) return \"\";\n try {\n const source = handler.toString();\n const matched = source.match(/\\{([\\s\\S]*)\\}$/);\n return matched ? matched[1].trim() : source;\n } catch {\n return \"\";\n }\n}\n\n/** 开始编辑(绑定/修改) */\nfunction startEdit(eventName: string): void {\n editingEvent.event = eventName;\n editingEvent.code = getBoundCode(eventName) || \"console.log('事件触发', event)\";\n editingEvent.new = !isBound(eventName);\n}\n\n/**\n * 保存事件绑定(函数体字符串经 runtime 的 createFun 转成真函数)\n * 经由 UpdateListenersCommand 执行: runtime ops 会同步维护 ext.bindListeners 与\n * methods 函数池, 直接写 node.listeners 不会同步这些状态, 事件将无法生效\n */\nfunction saveEdit(): void {\n const eventName = editingEvent.event;\n if (!eventName) return;\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const code = lodash.trim(editingEvent.code);\n let handler: any;\n try {\n if (code.length > 0) handler = createFun({ code });\n } catch (err) {\n console.warn(\"[EventPanel] 事件函数解析失败\", err);\n return;\n }\n const key = toListenerKey(eventName);\n const changes: Array<UpdateListenersChange> = [];\n for (const node of nodes.value) {\n const oldListener = node.listeners[key];\n // 函数体未变化不产生历史\n if (handler && oldListener?.handler\n && Function.prototype.toString.call(oldListener.handler) === Function.prototype.toString.call(handler)) continue;\n changes.push({\n nodeId: node.id,\n event: eventName,\n oldListener,\n newListener: handler ? { handler } : undefined,\n });\n }\n editingEvent.event = \"\";\n if (changes.length > 0) {\n designerState.commandStack.execute(new UpdateListenersCommand(designerState, `绑定事件 ${eventName}`, { changes }));\n }\n}\n\n/** 解绑事件 */\nfunction removeBind(eventName: string): void {\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const key = toListenerKey(eventName);\n const changes: Array<UpdateListenersChange> = [];\n for (const node of nodes.value) {\n const oldListener = node.listeners[key];\n if (!oldListener) continue;\n changes.push({\n nodeId: node.id,\n event: eventName,\n oldListener,\n newListener: undefined,\n });\n }\n if (changes.length > 0) {\n designerState.commandStack.execute(new UpdateListenersCommand(designerState, `解绑事件 ${eventName}`, { changes }));\n }\n}\n</script>\n\n<template>\n <!-- key 绑定面板刷新版本: 节点 listeners 是非响应式对象, 修改后靠版本号触发重新渲染 -->\n <div :key=\"props.designerState.setterShareState.panelVersion\" class=\"designer-event-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <div v-for=\"group in eventGroups\" :key=\"group.title\" class=\"designer-event-group\">\n <div class=\"designer-event-group-title\">{{ group.title }}</div>\n <div v-for=\"info in group.items\" :key=\"info.name\" class=\"designer-event-item\">\n <div class=\"designer-event-name\">\n {{ info.description ?? info.name }}\n <span class=\"designer-event-key\">{{ info.name }}</span>\n </div>\n <div class=\"designer-event-actions\">\n <Tag v-if=\"isBound(info.name)\" color=\"blue\" class=\"designer-event-tag\">已绑定</Tag>\n <Button size=\"small\" type=\"link\" @click=\"startEdit(info.name)\">{{ isBound(info.name) ? '编辑' : '绑定' }}</Button>\n <Button v-if=\"isBound(info.name)\" size=\"small\" type=\"link\" danger @click=\"removeBind(info.name)\">解绑</Button>\n </div>\n </div>\n </div>\n <!-- 函数体编辑区 -->\n <div v-if=\"editingEvent.event\" class=\"designer-event-editor\">\n <div class=\"designer-event-editor-title\">\n 编辑事件函数: <b>{{ editingEvent.event }}</b>\n </div>\n <textarea\n class=\"designer-event-textarea\"\n v-model=\"editingEvent.code\"\n placeholder=\"函数体字符串(如: console.log('click', event)), 留空清除绑定\"\n ></textarea>\n <div class=\"designer-event-editor-actions\">\n <Button size=\"small\" type=\"primary\" @click=\"saveEdit\">保存</Button>\n <Button size=\"small\" @click=\"editingEvent.event = ''\">取消</Button>\n </div>\n </div>\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-event-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n padding: 4px 0;\n font-size: 12px;\n}\n\n.designer-event-group-title {\n padding: 6px 12px 2px;\n font-weight: 600;\n color: #374151;\n}\n\n.designer-event-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 3px 12px;\n}\n\n.designer-event-name {\n color: #374151;\n}\n\n.designer-event-key {\n margin-left: 4px;\n font-family: Consolas, Monaco, monospace;\n font-size: 11px;\n color: #9ca3af;\n}\n\n.designer-event-tag {\n margin-right: 0;\n line-height: 16px;\n font-size: 11px;\n}\n\n.designer-event-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.designer-event-editor {\n margin: 8px 12px;\n padding: 8px;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n background: #fafafa;\n}\n\n.designer-event-editor-title {\n margin-bottom: 6px;\n color: #374151;\n}\n\n.designer-event-textarea {\n width: 100%;\n min-height: 72px;\n padding: 4px 8px;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n font-size: 12px;\n font-family: Consolas, Monaco, monospace;\n box-sizing: border-box;\n resize: vertical;\n}\n\n.designer-event-textarea:focus {\n outline: none;\n border-color: #1677ff;\n}\n\n.designer-event-editor-actions {\n display: flex;\n gap: 8px;\n margin-top: 6px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { Empty } from \"antdv-next\";\nimport lodash from \"lodash\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport type { RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport type { UpdatePropsChange } from \"../../operations/commands/UpdatePropsCommand\";\nimport { UpdatePropsCommand } from \"../../operations/commands/UpdatePropsCommand\";\n\ndefineOptions({ name: 'SetterAdvancedPanel' });\n\n// 定义 Props 类型\ninterface SetterAdvancedPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 高级设置面板配置(来自 ComponentMeta.setter.advanced) */\n advancedPanel?: { disableVShow?: boolean; disableVIf?: boolean; disableVFor?: boolean };\n}\n\nconst props = defineProps<SetterAdvancedPanelProps>();\n\nconst nodes = computed<Array<RuntimeNode>>(() => props.designerState.selectNodes);\n\n/**\n * 解析 v-for 表达式 \"item in list\" / \"(item, key, index) in list\"\n * runtime 的 v-for 指令协议是 { data, item, key, index } 对象, 直接存表达式字符串无法渲染\n */\nfunction parseVForExp(exp: string): { data: string; item: string; key?: string; index?: string } | undefined {\n const matched = lodash.trim(exp).match(/^(.+?)\\s+in\\s+(.+)$/);\n if (!matched) return;\n const varsStr = lodash.trim(matched[1]).replace(/^\\((.+)\\)$/, \"$1\");\n const data = lodash.trim(matched[2]);\n const vars = varsStr.split(\",\").map(itemVar => lodash.trim(itemVar)).filter(itemVar => itemVar.length > 0);\n if (vars.length <= 0 || data.length <= 0) return;\n return { data, item: vars[0], key: vars[1], index: vars[2] };\n}\n\n/** 把 v-for 指令配置序列化回 \"item in list\" 表达式形式(编辑显示用) */\nfunction toVForExp(forDirective: any): string {\n if (Typeof.isStr(forDirective)) return forDirective;\n if (!Typeof.isObj(forDirective)) return \"\";\n const vars = [forDirective.item, forDirective.key, forDirective.index]\n .filter((itemVar: any) => Typeof.isStr(itemVar) && lodash.trim(itemVar).length > 0)\n .map((itemVar: string) => lodash.trim(itemVar));\n const data = Typeof.isStr(forDirective.data) ? lodash.trim(forDirective.data) : \"\";\n if (vars.length <= 0 || data.length <= 0) return \"\";\n return vars.length > 1 ? `(${vars.join(\", \")}) in ${data}` : `${vars[0]} in ${data}`;\n}\n\n/** 读取指令原始值(兼容 {value} 包装形态) */\nfunction getDirectiveValue(name: \"show\" | \"if\" | \"for\"): any {\n const first = nodes.value[0];\n if (!first) return;\n const values = new Set<any>();\n for (const node of nodes.value) {\n const value = (node.directives as any)[name];\n values.add(Typeof.isObj(value) && !Typeof.isStr(value) ? (value as any).value : value);\n }\n if (values.size !== 1) return;\n return values.values().next().value;\n}\n\nconst showValue = computed(() => {\n // 读取 style.display 判断显示状态(显示/隐藏通过 style.display 实现, 渲染效果与 v-show 等价)\n // 注: runtime 动态渲染链对运行时修改 directives.show 后的 withDirectives(vShow) 重新应用存在问题(遗留),\n // 因此设计器的显示/隐藏切换写 style.display, v-if/v-for 仍按表达式协议写入指令\n const node = nodes.value[0];\n if (!node) return true;\n const style = Typeof.isObj(node.props?.style) ? node.props.style : {};\n return style.display !== \"none\";\n});\nconst ifValue = computed(() => Typeof.isStr(getDirectiveValue(\"if\")) ? getDirectiveValue(\"if\") : String(getDirectiveValue(\"if\") ?? \"\"));\nconst forValue = computed(() => toVForExp(getDirectiveValue(\"for\")));\n\n/** 构造并执行属性修改命令 */\nfunction executeUpdateCommand(designerState: DesignerState, name: string, changes: Array<UpdatePropsChange>): void {\n if (changes.length <= 0) return;\n designerState.commandStack.execute(new UpdatePropsCommand(designerState, name, { changes }));\n}\n\n/** 切换显示/隐藏(写 style.display, 渲染效果与 v-show 等价) */\nfunction applyShow(checked: boolean): void {\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const changes: Array<UpdatePropsChange> = [];\n for (const node of nodes.value) {\n const style = Typeof.isObj(node.props?.style) ? { ...node.props.style } : {};\n const oldValue = node.props.style;\n if (checked) {\n if (style.display === \"none\") delete style.display;\n } else {\n style.display = \"none\";\n }\n if (lodash.isEqual(oldValue, style)) continue;\n changes.push({\n nodeId: node.id,\n changeKey: \"style:display\",\n oldValue,\n newValue: style,\n write: (target, value) => {\n target.props.style = Typeof.isObj(value) ? value : undefined;\n },\n });\n }\n executeUpdateCommand(designerState, checked ? \"显示节点\" : \"隐藏节点\", changes);\n}\n\n/**\n * 应用指令值(空值删除指令)\n * - v-if: 表达式字符串\n * - v-for: 表达式解析成 { data, item, key?, index? } 对象(runtime 指令协议)\n */\nfunction applyDirective(name: \"show\" | \"if\" | \"for\", value: any): void {\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const exp = lodash.trim(String(value ?? \"\"));\n let directiveValue: any = undefined;\n if (name === \"for\") {\n if (exp.length > 0) {\n directiveValue = parseVForExp(exp);\n // 表达式无法解析时不写入(避免存入 runtime 无法渲染的字符串)\n if (!directiveValue) return;\n }\n } else {\n directiveValue = exp.length > 0 ? exp : undefined;\n }\n const changes: Array<UpdatePropsChange> = [];\n for (const node of nodes.value) {\n const oldValue = (node.directives as any)[name];\n if (lodash.isEqual(oldValue, directiveValue)) continue;\n changes.push({\n nodeId: node.id,\n changeKey: `directives:${name}`,\n oldValue,\n newValue: directiveValue,\n write: (target, val) => {\n if (Typeof.noValue(val)) {\n delete (target.directives as any)[name];\n } else {\n (target.directives as any)[name] = val;\n }\n },\n });\n }\n executeUpdateCommand(designerState, `修改 v-${name} 指令`, changes);\n}\n</script>\n\n<template>\n <!-- key 绑定面板刷新版本: 指令/样式是非响应式数据, undo/redo 后靠版本号触发重新渲染 -->\n <div :key=\"props.designerState.setterShareState.panelVersion\" class=\"designer-advanced-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <!-- v-show -->\n <div v-if=\"!props.advancedPanel?.disableVShow\" class=\"designer-advanced-item\">\n <div class=\"designer-advanced-label\">显示(v-show)</div>\n <div class=\"designer-advanced-control\">\n <label class=\"designer-advanced-switch\">\n <input type=\"checkbox\" :checked=\"showValue\" @change=\"event => applyShow((event.target as HTMLInputElement).checked)\" />\n <span>{{ showValue ? '显示' : '隐藏' }}</span>\n </label>\n </div>\n </div>\n <!-- v-if -->\n <div v-if=\"!props.advancedPanel?.disableVIf\" class=\"designer-advanced-item designer-advanced-column\">\n <div class=\"designer-advanced-label\">条件渲染(v-if)</div>\n <div class=\"designer-advanced-control\">\n <textarea\n class=\"designer-advanced-textarea\"\n placeholder=\"条件表达式, 如: {{ flag }} 或 flag === 1; 留空删除指令\"\n :value=\"ifValue\"\n @change=\"event => applyDirective('if', (event.target as HTMLTextAreaElement).value)\"\n ></textarea>\n </div>\n </div>\n <!-- v-for -->\n <div v-if=\"!props.advancedPanel?.disableVFor\" class=\"designer-advanced-item designer-advanced-column\">\n <div class=\"designer-advanced-label\">循环渲染(v-for)</div>\n <div class=\"designer-advanced-control\">\n <textarea\n class=\"designer-advanced-textarea\"\n placeholder=\"循环表达式, 如: item in items; 留空删除指令\"\n :value=\"forValue\"\n @change=\"event => applyDirective('for', (event.target as HTMLTextAreaElement).value)\"\n ></textarea>\n </div>\n </div>\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-advanced-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n padding: 8px 12px;\n font-size: 12px;\n box-sizing: border-box;\n}\n\n.designer-advanced-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 0;\n}\n\n.designer-advanced-column {\n flex-direction: column;\n align-items: stretch;\n}\n\n.designer-advanced-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n}\n\n.designer-advanced-column .designer-advanced-label {\n width: auto;\n}\n\n.designer-advanced-control {\n flex: 1;\n min-width: 0;\n}\n\n.designer-advanced-switch {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n user-select: none;\n}\n\n.designer-advanced-textarea {\n width: 100%;\n min-height: 48px;\n padding: 4px 8px;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n font-size: 12px;\n font-family: Consolas, Monaco, monospace;\n box-sizing: border-box;\n resize: vertical;\n}\n\n.designer-advanced-textarea:focus {\n outline: none;\n border-color: #1677ff;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { Empty } from \"antdv-next\";\nimport lodash from \"lodash\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport type { RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\nimport type { UpdatePropsChange } from \"../../operations/commands/UpdatePropsCommand\";\nimport { UpdatePropsCommand } from \"../../operations/commands/UpdatePropsCommand\";\n\ndefineOptions({ name: 'SetterAdvancedPanel' });\n\n// 定义 Props 类型\ninterface SetterAdvancedPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 高级设置面板配置(来自 ComponentMeta.setter.advanced) */\n advancedPanel?: { disableVShow?: boolean; disableVIf?: boolean; disableVFor?: boolean };\n}\n\nconst props = defineProps<SetterAdvancedPanelProps>();\n\nconst nodes = computed<Array<RuntimeNode>>(() => props.designerState.selectNodes);\n\n/**\n * 解析 v-for 表达式 \"item in list\" / \"(item, key, index) in list\"\n * runtime 的 v-for 指令协议是 { data, item, key, index } 对象, 直接存表达式字符串无法渲染\n */\nfunction parseVForExp(exp: string): { data: string; item: string; key?: string; index?: string } | undefined {\n const matched = lodash.trim(exp).match(/^(.+?)\\s+in\\s+(.+)$/);\n if (!matched) return;\n const varsStr = lodash.trim(matched[1]).replace(/^\\((.+)\\)$/, \"$1\");\n const data = lodash.trim(matched[2]);\n const vars = varsStr.split(\",\").map(itemVar => lodash.trim(itemVar)).filter(itemVar => itemVar.length > 0);\n if (vars.length <= 0 || data.length <= 0) return;\n return { data, item: vars[0], key: vars[1], index: vars[2] };\n}\n\n/** 把 v-for 指令配置序列化回 \"item in list\" 表达式形式(编辑显示用) */\nfunction toVForExp(forDirective: any): string {\n if (Typeof.isStr(forDirective)) return forDirective;\n if (!Typeof.isObj(forDirective)) return \"\";\n const vars = [forDirective.item, forDirective.key, forDirective.index]\n .filter((itemVar: any) => Typeof.isStr(itemVar) && lodash.trim(itemVar).length > 0)\n .map((itemVar: string) => lodash.trim(itemVar));\n const data = Typeof.isStr(forDirective.data) ? lodash.trim(forDirective.data) : \"\";\n if (vars.length <= 0 || data.length <= 0) return \"\";\n return vars.length > 1 ? `(${vars.join(\", \")}) in ${data}` : `${vars[0]} in ${data}`;\n}\n\n/** 读取指令原始值(兼容 {value} 包装形态) */\nfunction getDirectiveValue(name: \"show\" | \"if\" | \"for\"): any {\n const first = nodes.value[0];\n if (!first) return;\n const values = new Set<any>();\n for (const node of nodes.value) {\n const value = (node.directives as any)[name];\n values.add(Typeof.isObj(value) && !Typeof.isStr(value) ? (value as any).value : value);\n }\n if (values.size !== 1) return;\n return values.values().next().value;\n}\n\nconst showValue = computed(() => {\n // 读取 style.display 判断显示状态(显示/隐藏通过 style.display 实现, 渲染效果与 v-show 等价)\n // 注: runtime 动态渲染链对运行时修改 directives.show 后的 withDirectives(vShow) 重新应用存在问题(遗留),\n // 因此设计器的显示/隐藏切换写 style.display, v-if/v-for 仍按表达式协议写入指令\n const node = nodes.value[0];\n if (!node) return true;\n const style = Typeof.isObj(node.props?.style) ? node.props.style : {};\n return style.display !== \"none\";\n});\nconst ifValue = computed(() => Typeof.isStr(getDirectiveValue(\"if\")) ? getDirectiveValue(\"if\") : String(getDirectiveValue(\"if\") ?? \"\"));\nconst forValue = computed(() => toVForExp(getDirectiveValue(\"for\")));\n\n/** 构造并执行属性修改命令 */\nfunction executeUpdateCommand(designerState: DesignerState, name: string, changes: Array<UpdatePropsChange>): void {\n if (changes.length <= 0) return;\n designerState.commandStack.execute(new UpdatePropsCommand(designerState, name, { changes }));\n}\n\n/** 切换显示/隐藏(写 style.display, 渲染效果与 v-show 等价) */\nfunction applyShow(checked: boolean): void {\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const changes: Array<UpdatePropsChange> = [];\n for (const node of nodes.value) {\n const style = Typeof.isObj(node.props?.style) ? { ...node.props.style } : {};\n const oldValue = node.props.style;\n if (checked) {\n if (style.display === \"none\") delete style.display;\n } else {\n style.display = \"none\";\n }\n if (lodash.isEqual(oldValue, style)) continue;\n changes.push({\n nodeId: node.id,\n changeKey: \"style:display\",\n oldValue,\n newValue: style,\n write: (target, value) => {\n target.props.style = Typeof.isObj(value) ? value : undefined;\n },\n });\n }\n executeUpdateCommand(designerState, checked ? \"显示节点\" : \"隐藏节点\", changes);\n}\n\n/**\n * 应用指令值(空值删除指令)\n * - v-if: 表达式字符串\n * - v-for: 表达式解析成 { data, item, key?, index? } 对象(runtime 指令协议)\n */\nfunction applyDirective(name: \"show\" | \"if\" | \"for\", value: any): void {\n const designerState: DesignerState = props.designerState;\n if (!designerState.blockInstance) return;\n const exp = lodash.trim(String(value ?? \"\"));\n let directiveValue: any = undefined;\n if (name === \"for\") {\n if (exp.length > 0) {\n directiveValue = parseVForExp(exp);\n // 表达式无法解析时不写入(避免存入 runtime 无法渲染的字符串)\n if (!directiveValue) return;\n }\n } else {\n directiveValue = exp.length > 0 ? exp : undefined;\n }\n const changes: Array<UpdatePropsChange> = [];\n for (const node of nodes.value) {\n const oldValue = (node.directives as any)[name];\n if (lodash.isEqual(oldValue, directiveValue)) continue;\n changes.push({\n nodeId: node.id,\n changeKey: `directives:${name}`,\n oldValue,\n newValue: directiveValue,\n write: (target, val) => {\n if (Typeof.noValue(val)) {\n delete (target.directives as any)[name];\n } else {\n (target.directives as any)[name] = val;\n }\n },\n });\n }\n executeUpdateCommand(designerState, `修改 v-${name} 指令`, changes);\n}\n</script>\n\n<template>\n <!-- key 绑定面板刷新版本: 指令/样式是非响应式数据, undo/redo 后靠版本号触发重新渲染 -->\n <div :key=\"props.designerState.setterShareState.panelVersion\" class=\"designer-advanced-panel\">\n <Empty v-if=\"!props.designerState.existsSelection\" description=\"请选择画布中的组件\" />\n <template v-else>\n <!-- v-show -->\n <div v-if=\"!props.advancedPanel?.disableVShow\" class=\"designer-advanced-item\">\n <div class=\"designer-advanced-label\">显示(v-show)</div>\n <div class=\"designer-advanced-control\">\n <label class=\"designer-advanced-switch\">\n <input type=\"checkbox\" :checked=\"showValue\" @change=\"event => applyShow((event.target as HTMLInputElement).checked)\" />\n <span>{{ showValue ? '显示' : '隐藏' }}</span>\n </label>\n </div>\n </div>\n <!-- v-if -->\n <div v-if=\"!props.advancedPanel?.disableVIf\" class=\"designer-advanced-item designer-advanced-column\">\n <div class=\"designer-advanced-label\">条件渲染(v-if)</div>\n <div class=\"designer-advanced-control\">\n <textarea\n class=\"designer-advanced-textarea\"\n placeholder=\"条件表达式, 如: {{ flag }} 或 flag === 1; 留空删除指令\"\n :value=\"ifValue\"\n @change=\"event => applyDirective('if', (event.target as HTMLTextAreaElement).value)\"\n ></textarea>\n </div>\n </div>\n <!-- v-for -->\n <div v-if=\"!props.advancedPanel?.disableVFor\" class=\"designer-advanced-item designer-advanced-column\">\n <div class=\"designer-advanced-label\">循环渲染(v-for)</div>\n <div class=\"designer-advanced-control\">\n <textarea\n class=\"designer-advanced-textarea\"\n placeholder=\"循环表达式, 如: item in items; 留空删除指令\"\n :value=\"forValue\"\n @change=\"event => applyDirective('for', (event.target as HTMLTextAreaElement).value)\"\n ></textarea>\n </div>\n </div>\n </template>\n </div>\n</template>\n\n<style scoped>\n.designer-advanced-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n padding: 8px 12px;\n font-size: 12px;\n box-sizing: border-box;\n}\n\n.designer-advanced-item {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 4px 0;\n}\n\n.designer-advanced-column {\n flex-direction: column;\n align-items: stretch;\n}\n\n.designer-advanced-label {\n flex: none;\n width: 76px;\n color: #6b7280;\n}\n\n.designer-advanced-column .designer-advanced-label {\n width: auto;\n}\n\n.designer-advanced-control {\n flex: 1;\n min-width: 0;\n}\n\n.designer-advanced-switch {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n user-select: none;\n}\n\n.designer-advanced-textarea {\n width: 100%;\n min-height: 48px;\n padding: 4px 8px;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n font-size: 12px;\n font-family: Consolas, Monaco, monospace;\n box-sizing: border-box;\n resize: vertical;\n}\n\n.designer-advanced-textarea:focus {\n outline: none;\n border-color: #1677ff;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from \"vue\";\nimport { Input, Tabs } from \"antdv-next\";\nimport { type ComponentMeta, isHtmlTag, type MaterialMetaTab } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\ndefineOptions({ name: 'MaterialPanel' });\n\n// 定义 Props 类型\ninterface MaterialPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 物料分组配置 */\n materialTabs?: Array<MaterialMetaTab>;\n /** 物料依赖的组件类型映射(加载物料时一并加载依赖组件) */\n dependence?: Record<string, Array<string>>;\n}\n\nconst props = defineProps<MaterialPanelProps>();\n\n// 物料搜索关键字\nconst searchText = ref<string>(\"\");\n\n/** 已加载的组件元信息 */\nconst loadedMetas = ref<Record<string, ComponentMeta>>({});\n\n// 挂载时加载所有物料元信息与组件实现\nonMounted(async () => {\n const types = new Set<string>();\n const addType = (type: string): void => {\n if (types.has(type)) return;\n types.add(type);\n // 物料依赖的组件类型一并加载\n const dependencies = props.dependence?.[type];\n if (dependencies) dependencies.forEach(dependency => addType(dependency));\n };\n for (const tab of props.materialTabs ?? []) {\n for (const group of tab.groups) {\n for (const type of group.types) {\n addType(type);\n }\n }\n }\n if (types.size <= 0) return;\n try {\n const allTypes = Array.from(types);\n const [metas] = await Promise.all([\n props.designerState.designerEngine.componentManage.loadAsyncComponentMeta(allTypes),\n // 组件实现也要加载: 异步注册的物料拖入画布后才能渲染(排除 html 标签)\n props.designerState.designerEngine.componentManage.loadAsyncComponent(allTypes.filter(type => !isHtmlTag(type))),\n ]);\n loadedMetas.value = metas;\n } catch (err) {\n console.warn(\"加载物料元信息失败\", err);\n }\n});\n\n/** 过滤后的分组(按搜索关键字) */\nconst visibleTabs = computed(() => {\n const keyword = (searchText.value ?? \"\").trim().toLowerCase();\n return (props.materialTabs ?? []).map(tab => ({\n ...tab,\n groups: tab.groups.map(group => ({\n ...group,\n metas: group.types.map(type => loadedMetas.value[type]).filter(Boolean),\n })).filter(group => group.metas.length > 0).map(group => ({\n ...group,\n metas: keyword.length > 0\n ? group.metas.filter(meta => meta.name.toLowerCase().includes(keyword) || meta.type.toLowerCase().includes(keyword))\n : group.metas,\n })).filter(group => group.metas.length > 0),\n })).filter(tab => tab.groups.length > 0);\n});\n/** Tabs 的 items 配置(内容经 contentRender 槽按 key 渲染) */\nconst tabItems = computed(() => visibleTabs.value.map(tab => ({ key: tab.title, label: tab.title })));\n</script>\n\n<template>\n <div class=\"designer-material-panel\">\n <div class=\"designer-material-search\">\n <Input\n v-model:value=\"searchText\"\n size=\"small\"\n allowClear\n placeholder=\"搜索组件\"\n />\n </div>\n <Tabs v-if=\"visibleTabs.length > 0\" size=\"small\" class=\"designer-material-tabs\" :items=\"tabItems\">\n <template #contentRender=\"{ item }\">\n <template v-for=\"tab in visibleTabs\" :key=\"tab.title\">\n <div v-if=\"tab.title === item.key\">\n <div v-for=\"group in tab.groups\" :key=\"group.title\" class=\"designer-material-group\">\n <div class=\"designer-material-group-title\">{{ group.title }}</div>\n <div class=\"designer-material-items\">\n <div\n v-for=\"meta in group.metas\"\n :key=\"meta.type\"\n class=\"draggable material-item\"\n :data-component-type=\"meta.type\"\n :title=\"meta.type\"\n >\n {{ meta.name }}\n </div>\n </div>\n </div>\n </div>\n </template>\n </template>\n </Tabs>\n <div v-else class=\"designer-material-empty\">未配置物料或无匹配组件</div>\n </div>\n</template>\n\n<style scoped>\n.designer-material-panel {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.designer-material-search {\n flex: none;\n padding: 8px 8px 4px;\n}\n\n.designer-material-tabs {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 0 8px;\n}\n\n.designer-material-group-title {\n font-size: 12px;\n font-weight: 600;\n color: #6b7280;\n padding: 6px 0 4px;\n}\n\n.designer-material-items {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n padding-bottom: 8px;\n}\n\n.draggable.material-item {\n padding: 6px 8px;\n border: 1px dashed #d9d9d9;\n border-radius: 4px;\n background: #fff;\n cursor: grab;\n user-select: none;\n font-size: 12px;\n text-align: center;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.draggable.material-item:hover {\n border-color: #1677ff;\n color: #1677ff;\n}\n\n.designer-material-empty {\n padding: 24px;\n text-align: center;\n color: #9ca3af;\n font-size: 12px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from \"vue\";\nimport { Input, Tabs } from \"antdv-next\";\nimport { type ComponentMeta, isHtmlTag, type MaterialMetaTab } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\ndefineOptions({ name: 'MaterialPanel' });\n\n// 定义 Props 类型\ninterface MaterialPanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 物料分组配置 */\n materialTabs?: Array<MaterialMetaTab>;\n /** 物料依赖的组件类型映射(加载物料时一并加载依赖组件) */\n dependence?: Record<string, Array<string>>;\n}\n\nconst props = defineProps<MaterialPanelProps>();\n\n// 物料搜索关键字\nconst searchText = ref<string>(\"\");\n\n/** 已加载的组件元信息 */\nconst loadedMetas = ref<Record<string, ComponentMeta>>({});\n\n// 挂载时加载所有物料元信息与组件实现\nonMounted(async () => {\n const types = new Set<string>();\n const addType = (type: string): void => {\n if (types.has(type)) return;\n types.add(type);\n // 物料依赖的组件类型一并加载\n const dependencies = props.dependence?.[type];\n if (dependencies) dependencies.forEach(dependency => addType(dependency));\n };\n for (const tab of props.materialTabs ?? []) {\n for (const group of tab.groups) {\n for (const type of group.types) {\n addType(type);\n }\n }\n }\n if (types.size <= 0) return;\n try {\n const allTypes = Array.from(types);\n const [metas] = await Promise.all([\n props.designerState.designerEngine.componentManage.loadAsyncComponentMeta(allTypes),\n // 组件实现也要加载: 异步注册的物料拖入画布后才能渲染(排除 html 标签)\n props.designerState.designerEngine.componentManage.loadAsyncComponent(allTypes.filter(type => !isHtmlTag(type))),\n ]);\n loadedMetas.value = metas;\n } catch (err) {\n console.warn(\"加载物料元信息失败\", err);\n }\n});\n\n/** 过滤后的分组(按搜索关键字) */\nconst visibleTabs = computed(() => {\n const keyword = (searchText.value ?? \"\").trim().toLowerCase();\n return (props.materialTabs ?? []).map(tab => ({\n ...tab,\n groups: tab.groups.map(group => ({\n ...group,\n metas: group.types.map(type => loadedMetas.value[type]).filter(Boolean),\n })).filter(group => group.metas.length > 0).map(group => ({\n ...group,\n metas: keyword.length > 0\n ? group.metas.filter(meta => meta.name.toLowerCase().includes(keyword) || meta.type.toLowerCase().includes(keyword))\n : group.metas,\n })).filter(group => group.metas.length > 0),\n })).filter(tab => tab.groups.length > 0);\n});\n/** Tabs 的 items 配置(内容经 contentRender 槽按 key 渲染) */\nconst tabItems = computed(() => visibleTabs.value.map(tab => ({ key: tab.title, label: tab.title })));\n</script>\n\n<template>\n <div class=\"designer-material-panel\">\n <div class=\"designer-material-search\">\n <Input\n v-model:value=\"searchText\"\n size=\"small\"\n allowClear\n placeholder=\"搜索组件\"\n />\n </div>\n <Tabs v-if=\"visibleTabs.length > 0\" size=\"small\" class=\"designer-material-tabs\" :items=\"tabItems\">\n <template #contentRender=\"{ item }\">\n <template v-for=\"tab in visibleTabs\" :key=\"tab.title\">\n <div v-if=\"tab.title === item.key\">\n <div v-for=\"group in tab.groups\" :key=\"group.title\" class=\"designer-material-group\">\n <div class=\"designer-material-group-title\">{{ group.title }}</div>\n <div class=\"designer-material-items\">\n <div\n v-for=\"meta in group.metas\"\n :key=\"meta.type\"\n class=\"draggable material-item\"\n :data-component-type=\"meta.type\"\n :title=\"meta.type\"\n >\n {{ meta.name }}\n </div>\n </div>\n </div>\n </div>\n </template>\n </template>\n </Tabs>\n <div v-else class=\"designer-material-empty\">未配置物料或无匹配组件</div>\n </div>\n</template>\n\n<style scoped>\n.designer-material-panel {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.designer-material-search {\n flex: none;\n padding: 8px 8px 4px;\n}\n\n.designer-material-tabs {\n flex: 1;\n min-height: 0;\n overflow: auto;\n padding: 0 8px;\n}\n\n.designer-material-group-title {\n font-size: 12px;\n font-weight: 600;\n color: #6b7280;\n padding: 6px 0 4px;\n}\n\n.designer-material-items {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n padding-bottom: 8px;\n}\n\n.draggable.material-item {\n padding: 6px 8px;\n border: 1px dashed #d9d9d9;\n border-radius: 4px;\n background: #fff;\n cursor: grab;\n user-select: none;\n font-size: 12px;\n text-align: center;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.draggable.material-item:hover {\n border-color: #1677ff;\n color: #1677ff;\n}\n\n.designer-material-empty {\n padding: 24px;\n text-align: center;\n color: #9ca3af;\n font-size: 12px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { Empty, Tree } from \"antdv-next\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { type RuntimeComponentSlotsItem, type RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\ndefineOptions({ name: 'OutlinePanel' });\n\n// 定义 Props 类型\ninterface OutlinePanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n}\n\nconst props = defineProps<OutlinePanelProps>();\n\n/** 树节点数据 */\ninterface OutlineTreeNode {\n title: string;\n key: string;\n children?: Array<OutlineTreeNode>;\n}\n\n/** RuntimeNode 转大纲树节点(递归 items 与 slots) */\nfunction toOutlineNodes(items: Array<RuntimeComponentSlotsItem>, depth: number = 0): Array<OutlineTreeNode> {\n if (depth > 30) return [];\n const result: Array<OutlineTreeNode> = [];\n for (const item of items) {\n if (!Typeof.isObj(item) || Typeof.isArray(item)) continue;\n const node = item as RuntimeNode;\n const meta = props.designerState.designerEngine.componentManage.getComponentMeta(node.type);\n const children: Array<OutlineTreeNode> = [];\n // 子节点(items) + 各插槽(slots)\n children.push(...toOutlineNodes(node.items ?? [], depth + 1));\n for (const slotName in node.slots) {\n const slotChildren = toOutlineNodes(node.slots[slotName] ?? [], depth + 1);\n if (slotChildren.length > 0) {\n children.push(...slotChildren);\n }\n }\n result.push({\n title: meta?.name ?? node.type,\n key: node.id,\n children: children.length > 0 ? children : undefined,\n });\n }\n return result;\n}\n\n/** 大纲树数据 */\nconst treeData = computed<Array<OutlineTreeNode>>(() => {\n const blockInstance = props.designerState.blockInstance;\n const runtimeBlock = blockInstance?.globalContext.runtimeBlock;\n if (!runtimeBlock) return [];\n return toOutlineNodes(runtimeBlock.items ?? []);\n});\n\n/** 当前选中的树节点key */\nconst selectedKeys = computed<Array<string>>(() => {\n return props.designerState.selections.map(selection => selection.nodeId!).filter(Boolean);\n});\n\n/** 点击树节点 -> 选中画布节点 */\nfunction onSelect(keys: Array<string>): void {\n if (keys.length === 1) {\n props.designerState.selectNodeByIds([keys[0]]);\n }\n}\n</script>\n\n<template>\n <div class=\"designer-outline-panel\">\n <Empty v-if=\"treeData.length <= 0\" description=\"画布为空\" />\n <Tree\n v-else\n block-node\n :tree-data=\"treeData\"\n :selected-keys=\"selectedKeys\"\n default-expand-all\n @select=\"onSelect\"\n />\n </div>\n</template>\n\n<style scoped>\n.designer-outline-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n padding: 4px;\n font-size: 12px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { Empty, Tree } from \"antdv-next\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport { type RuntimeComponentSlotsItem, type RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../../models/DesignerState\";\n\ndefineOptions({ name: 'OutlinePanel' });\n\n// 定义 Props 类型\ninterface OutlinePanelProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n}\n\nconst props = defineProps<OutlinePanelProps>();\n\n/** 树节点数据 */\ninterface OutlineTreeNode {\n title: string;\n key: string;\n children?: Array<OutlineTreeNode>;\n}\n\n/** RuntimeNode 转大纲树节点(递归 items 与 slots) */\nfunction toOutlineNodes(items: Array<RuntimeComponentSlotsItem>, depth: number = 0): Array<OutlineTreeNode> {\n if (depth > 30) return [];\n const result: Array<OutlineTreeNode> = [];\n for (const item of items) {\n if (!Typeof.isObj(item) || Typeof.isArray(item)) continue;\n const node = item as RuntimeNode;\n const meta = props.designerState.designerEngine.componentManage.getComponentMeta(node.type);\n const children: Array<OutlineTreeNode> = [];\n // 子节点(items) + 各插槽(slots)\n children.push(...toOutlineNodes(node.items ?? [], depth + 1));\n for (const slotName in node.slots) {\n const slotChildren = toOutlineNodes(node.slots[slotName] ?? [], depth + 1);\n if (slotChildren.length > 0) {\n children.push(...slotChildren);\n }\n }\n result.push({\n title: meta?.name ?? node.type,\n key: node.id,\n children: children.length > 0 ? children : undefined,\n });\n }\n return result;\n}\n\n/** 大纲树数据 */\nconst treeData = computed<Array<OutlineTreeNode>>(() => {\n const blockInstance = props.designerState.blockInstance;\n const runtimeBlock = blockInstance?.globalContext.runtimeBlock;\n if (!runtimeBlock) return [];\n return toOutlineNodes(runtimeBlock.items ?? []);\n});\n\n/** 当前选中的树节点key */\nconst selectedKeys = computed<Array<string>>(() => {\n return props.designerState.selections.map(selection => selection.nodeId!).filter(Boolean);\n});\n\n/** 点击树节点 -> 选中画布节点 */\nfunction onSelect(keys: Array<string>): void {\n if (keys.length === 1) {\n props.designerState.selectNodeByIds([keys[0]]);\n }\n}\n</script>\n\n<template>\n <div class=\"designer-outline-panel\">\n <Empty v-if=\"treeData.length <= 0\" description=\"画布为空\" />\n <Tree\n v-else\n block-node\n :tree-data=\"treeData\"\n :selected-keys=\"selectedKeys\"\n default-expand-all\n @select=\"onSelect\"\n />\n </div>\n</template>\n\n<style scoped>\n.designer-outline-panel {\n width: 100%;\n height: 100%;\n overflow: auto;\n padding: 4px;\n font-size: 12px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref } from \"vue\";\nimport { Button, message, Tabs, Tooltip } from \"antdv-next\";\nimport { ClearOutlined, DeleteOutlined, EditOutlined, EyeOutlined, RedoOutlined, UndoOutlined } from \"@antdv-next/icons\";\nimport { BlockComponent, type DesignBlock, type MaterialMetaTab, type RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../models/DesignerState\";\nimport DesignCanvas from \"./DesignCanvas.vue\";\nimport DragGhost from \"./DragGhost.vue\";\nimport SetterPropsPanel from \"./panels/SetterPropsPanel.vue\";\nimport SetterStylePanel from \"./panels/SetterStylePanel.vue\";\nimport SetterEventPanel from \"./panels/SetterEventPanel.vue\";\nimport SetterAdvancedPanel from \"./panels/SetterAdvancedPanel.vue\";\nimport MaterialPanel from \"./panels/MaterialPanel.vue\";\nimport OutlinePanel from \"./panels/OutlinePanel.vue\";\nimport { RemoveNodesCommand } from \"../operations/commands/RemoveNodesCommand\";\nimport { runtimeNodeToDesignNode } from \"../operations/NodeSerialize\";\n\ndefineOptions({ name: 'Workbench' });\n\n// 定义 Props 类型\ninterface WorkbenchProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 画布的 DesignBlock 配置 */\n block?: DesignBlock;\n /** 物料分组配置 */\n materialTabs?: Array<MaterialMetaTab>;\n}\n\nconst props = defineProps<WorkbenchProps>();\n\nconst engine = computed(() => props.designerState.designerEngine);\n/** 是否预览模式(预览时画布按运行时渲染, 不响应设计交互) */\nconst previewMode = ref<boolean>(false);\n/** 左侧面板活动Tab */\nconst leftTab = ref<string>(\"material\");\n/** 右侧面板活动Tab */\nconst rightTab = ref<string>(\"props\");\n\n/** 撤销 */\nfunction doUndo(): void {\n props.designerState.commandStack.undo();\n props.designerState.clearSelections();\n}\n\n/** 重做 */\nfunction doRedo(): void {\n props.designerState.commandStack.redo();\n props.designerState.clearSelections();\n}\n\n/** 删除选中节点 */\nfunction doDelete(): void {\n const nodeIds = props.designerState.selections.map(selection => selection.nodeId!).filter(Boolean);\n if (nodeIds.length <= 0) return;\n const command = new RemoveNodesCommand(props.designerState, `删除 ${nodeIds.length} 个组件`, {\n nodeIds,\n onExecute: () => props.designerState.clearSelections(),\n });\n props.designerState.commandStack.execute(command);\n}\n\n/** 清空画布(删除根容器下所有子节点) */\nfunction doClear(): void {\n const blockInstance = props.designerState.blockInstance;\n const runtimeBlock = blockInstance?.globalContext.runtimeBlock;\n if (!runtimeBlock) return;\n const nodeIds = (runtimeBlock.items ?? [])\n .filter((item): item is RuntimeNode => !!item && typeof item === \"object\" && !Array.isArray(item))\n .map(node => node.id);\n if (nodeIds.length <= 0) {\n message.info(\"画布已经是空的\");\n return;\n }\n const command = new RemoveNodesCommand(props.designerState, \"清空画布\", {\n nodeIds,\n onExecute: () => props.designerState.clearSelections(),\n });\n props.designerState.commandStack.execute(command);\n}\n\n/** 选中组件的各面板配置 */\nconst propsPanel = computed(() => props.designerState.selectedComponentMeta?.setter?.props);\nconst stylePanel = computed(() => props.designerState.selectedComponentMeta?.setter?.style);\nconst eventPanel = computed(() => props.designerState.selectedComponentMeta?.setter?.events);\nconst advancedPanel = computed(() => props.designerState.selectedComponentMeta?.setter?.advanced);\n\n/** 预览用的 DesignBlock(进入预览时从当前设计树反序列化, 保证设计修改带入预览) */\nconst previewBlock = computed<DesignBlock | undefined>(() => {\n if (!previewMode.value) return undefined;\n const runtimeBlock = props.designerState.blockInstance?.globalContext.runtimeBlock;\n return runtimeBlock ? (runtimeNodeToDesignNode(runtimeBlock) as unknown as DesignBlock) : undefined;\n});\n</script>\n\n<template>\n <div class=\"designer-workbench\">\n <!-- 顶部工具栏 -->\n <div class=\"designer-workbench-toolbar\">\n <div class=\"designer-workbench-toolbar-group\">\n <Tooltip title=\"撤销 Ctrl+Z\">\n <Button size=\"small\" type=\"text\" :disabled=\"!designerState.commandStack.canUndo || previewMode\" @click=\"doUndo\">\n <UndoOutlined />\n </Button>\n </Tooltip>\n <Tooltip title=\"重做 Ctrl+Y\">\n <Button size=\"small\" type=\"text\" :disabled=\"!designerState.commandStack.canRedo || previewMode\" @click=\"doRedo\">\n <RedoOutlined />\n </Button>\n </Tooltip>\n <Tooltip title=\"删除选中 Delete\">\n <Button size=\"small\" type=\"text\" danger :disabled=\"!designerState.existsSelection || previewMode\" @click=\"doDelete\">\n <DeleteOutlined />\n </Button>\n </Tooltip>\n <Tooltip title=\"清空画布\">\n <Button size=\"small\" type=\"text\" danger :disabled=\"previewMode\" @click=\"doClear\">\n <ClearOutlined />\n </Button>\n </Tooltip>\n </div>\n <div class=\"designer-workbench-toolbar-title\">可视化页面设计器</div>\n <div class=\"designer-workbench-toolbar-group\">\n <Button size=\"small\" :type=\"previewMode ? 'primary' : 'default'\" @click=\"previewMode = !previewMode\">\n <EyeOutlined v-if=\"!previewMode\" />\n <EditOutlined v-else />\n {{ previewMode ? '编辑' : '预览' }}\n </Button>\n </div>\n </div>\n <!-- 主体三栏 -->\n <div class=\"designer-workbench-body\">\n <!-- 左侧: 物料/大纲 -->\n <div class=\"designer-workbench-left\">\n <Tabs v-model:activeKey=\"leftTab\" size=\"small\" class=\"designer-workbench-left-tabs\"\n :items=\"[{ key: 'material', label: '物料' }, { key: 'outline', label: '大纲' }]\"/>\n <div class=\"designer-workbench-left-content\">\n <MaterialPanel v-show=\"leftTab === 'material'\" :designerState=\"designerState\" :materialTabs=\"props.materialTabs\" />\n <OutlinePanel v-show=\"leftTab === 'outline'\" :designerState=\"designerState\" />\n </div>\n </div>\n <!-- 中间: 画布 -->\n <div class=\"designer-workbench-center\">\n <DesignCanvas v-if=\"!previewMode\" :designerState=\"designerState\" :block=\"props.block\" />\n <BlockComponent\n v-else\n class=\"designer-workbench-preview\"\n :componentManage=\"engine.componentManage\"\n :block=\"previewBlock\"\n :isDesigning=\"false\"\n />\n </div>\n <!-- 右侧: 配置面板 -->\n <div class=\"designer-workbench-right\">\n <Tabs v-model:activeKey=\"rightTab\" size=\"small\" class=\"designer-workbench-right-tabs\"\n :items=\"[\n { key: 'props', label: '属性' },\n { key: 'style', label: '样式' },\n { key: 'events', label: '事件' },\n { key: 'advanced', label: '高级' },\n ]\"/>\n <div class=\"designer-workbench-right-content\">\n <SetterPropsPanel v-show=\"rightTab === 'props'\" :designerState=\"designerState\" :propsPanel=\"propsPanel\" />\n <SetterStylePanel v-show=\"rightTab === 'style'\" :designerState=\"designerState\" :stylePanel=\"stylePanel\" />\n <SetterEventPanel v-show=\"rightTab === 'events'\" :designerState=\"designerState\" :eventPanel=\"eventPanel\" />\n <SetterAdvancedPanel v-show=\"rightTab === 'advanced'\" :designerState=\"designerState\" :advancedPanel=\"advancedPanel\" />\n </div>\n </div>\n </div>\n <DragGhost :designerEngine=\"engine\" />\n </div>\n</template>\n\n<style scoped>\n.designer-workbench {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: #fff;\n}\n\n.designer-workbench-toolbar {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 12px;\n border-bottom: 1px solid #e5e7eb;\n background: #fafafa;\n}\n\n.designer-workbench-toolbar-group {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.designer-workbench-toolbar-title {\n font-size: 14px;\n font-weight: 600;\n color: #374151;\n}\n\n.designer-workbench-body {\n flex: 1;\n display: flex;\n min-height: 0;\n}\n\n.designer-workbench-left {\n flex: none;\n width: 240px;\n display: flex;\n flex-direction: column;\n border-right: 1px solid #e5e7eb;\n min-height: 0;\n}\n\n.designer-workbench-left-tabs,\n.designer-workbench-right-tabs {\n flex: none;\n padding: 0 8px;\n margin-bottom: 0;\n}\n\n.designer-workbench-left-content,\n.designer-workbench-right-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.designer-workbench-center {\n flex: 1;\n min-width: 0;\n padding: 12px;\n}\n\n.designer-workbench-preview {\n width: 100%;\n height: 100%;\n overflow: auto;\n}\n\n.designer-workbench-right {\n flex: none;\n width: 320px;\n display: flex;\n flex-direction: column;\n border-left: 1px solid #e5e7eb;\n min-height: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, ref } from \"vue\";\nimport { Button, message, Tabs, Tooltip } from \"antdv-next\";\nimport { ClearOutlined, DeleteOutlined, EditOutlined, EyeOutlined, RedoOutlined, UndoOutlined } from \"@antdv-next/icons\";\nimport { BlockComponent, type DesignBlock, type MaterialMetaTab, type RuntimeNode } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../models/DesignerState\";\nimport DesignCanvas from \"./DesignCanvas.vue\";\nimport DragGhost from \"./DragGhost.vue\";\nimport SetterPropsPanel from \"./panels/SetterPropsPanel.vue\";\nimport SetterStylePanel from \"./panels/SetterStylePanel.vue\";\nimport SetterEventPanel from \"./panels/SetterEventPanel.vue\";\nimport SetterAdvancedPanel from \"./panels/SetterAdvancedPanel.vue\";\nimport MaterialPanel from \"./panels/MaterialPanel.vue\";\nimport OutlinePanel from \"./panels/OutlinePanel.vue\";\nimport { RemoveNodesCommand } from \"../operations/commands/RemoveNodesCommand\";\nimport { runtimeNodeToDesignNode } from \"../operations/NodeSerialize\";\n\ndefineOptions({ name: 'Workbench' });\n\n// 定义 Props 类型\ninterface WorkbenchProps {\n /** 设计器状态数据 */\n designerState: DesignerState;\n /** 画布的 DesignBlock 配置 */\n block?: DesignBlock;\n /** 物料分组配置 */\n materialTabs?: Array<MaterialMetaTab>;\n}\n\nconst props = defineProps<WorkbenchProps>();\n\nconst engine = computed(() => props.designerState.designerEngine);\n/** 是否预览模式(预览时画布按运行时渲染, 不响应设计交互) */\nconst previewMode = ref<boolean>(false);\n/** 左侧面板活动Tab */\nconst leftTab = ref<string>(\"material\");\n/** 右侧面板活动Tab */\nconst rightTab = ref<string>(\"props\");\n\n/** 撤销 */\nfunction doUndo(): void {\n props.designerState.commandStack.undo();\n props.designerState.clearSelections();\n}\n\n/** 重做 */\nfunction doRedo(): void {\n props.designerState.commandStack.redo();\n props.designerState.clearSelections();\n}\n\n/** 删除选中节点 */\nfunction doDelete(): void {\n const nodeIds = props.designerState.selections.map(selection => selection.nodeId!).filter(Boolean);\n if (nodeIds.length <= 0) return;\n const command = new RemoveNodesCommand(props.designerState, `删除 ${nodeIds.length} 个组件`, {\n nodeIds,\n onExecute: () => props.designerState.clearSelections(),\n });\n props.designerState.commandStack.execute(command);\n}\n\n/** 清空画布(删除根容器下所有子节点) */\nfunction doClear(): void {\n const blockInstance = props.designerState.blockInstance;\n const runtimeBlock = blockInstance?.globalContext.runtimeBlock;\n if (!runtimeBlock) return;\n const nodeIds = (runtimeBlock.items ?? [])\n .filter((item): item is RuntimeNode => !!item && typeof item === \"object\" && !Array.isArray(item))\n .map(node => node.id);\n if (nodeIds.length <= 0) {\n message.info(\"画布已经是空的\");\n return;\n }\n const command = new RemoveNodesCommand(props.designerState, \"清空画布\", {\n nodeIds,\n onExecute: () => props.designerState.clearSelections(),\n });\n props.designerState.commandStack.execute(command);\n}\n\n/** 选中组件的各面板配置 */\nconst propsPanel = computed(() => props.designerState.selectedComponentMeta?.setter?.props);\nconst stylePanel = computed(() => props.designerState.selectedComponentMeta?.setter?.style);\nconst eventPanel = computed(() => props.designerState.selectedComponentMeta?.setter?.events);\nconst advancedPanel = computed(() => props.designerState.selectedComponentMeta?.setter?.advanced);\n\n/** 预览用的 DesignBlock(进入预览时从当前设计树反序列化, 保证设计修改带入预览) */\nconst previewBlock = computed<DesignBlock | undefined>(() => {\n if (!previewMode.value) return undefined;\n const runtimeBlock = props.designerState.blockInstance?.globalContext.runtimeBlock;\n return runtimeBlock ? (runtimeNodeToDesignNode(runtimeBlock) as unknown as DesignBlock) : undefined;\n});\n</script>\n\n<template>\n <div class=\"designer-workbench\">\n <!-- 顶部工具栏 -->\n <div class=\"designer-workbench-toolbar\">\n <div class=\"designer-workbench-toolbar-group\">\n <Tooltip title=\"撤销 Ctrl+Z\">\n <Button size=\"small\" type=\"text\" :disabled=\"!designerState.commandStack.canUndo || previewMode\" @click=\"doUndo\">\n <UndoOutlined />\n </Button>\n </Tooltip>\n <Tooltip title=\"重做 Ctrl+Y\">\n <Button size=\"small\" type=\"text\" :disabled=\"!designerState.commandStack.canRedo || previewMode\" @click=\"doRedo\">\n <RedoOutlined />\n </Button>\n </Tooltip>\n <Tooltip title=\"删除选中 Delete\">\n <Button size=\"small\" type=\"text\" danger :disabled=\"!designerState.existsSelection || previewMode\" @click=\"doDelete\">\n <DeleteOutlined />\n </Button>\n </Tooltip>\n <Tooltip title=\"清空画布\">\n <Button size=\"small\" type=\"text\" danger :disabled=\"previewMode\" @click=\"doClear\">\n <ClearOutlined />\n </Button>\n </Tooltip>\n </div>\n <div class=\"designer-workbench-toolbar-title\">可视化页面设计器</div>\n <div class=\"designer-workbench-toolbar-group\">\n <Button size=\"small\" :type=\"previewMode ? 'primary' : 'default'\" @click=\"previewMode = !previewMode\">\n <EyeOutlined v-if=\"!previewMode\" />\n <EditOutlined v-else />\n {{ previewMode ? '编辑' : '预览' }}\n </Button>\n </div>\n </div>\n <!-- 主体三栏 -->\n <div class=\"designer-workbench-body\">\n <!-- 左侧: 物料/大纲 -->\n <div class=\"designer-workbench-left\">\n <Tabs v-model:activeKey=\"leftTab\" size=\"small\" class=\"designer-workbench-left-tabs\"\n :items=\"[{ key: 'material', label: '物料' }, { key: 'outline', label: '大纲' }]\"/>\n <div class=\"designer-workbench-left-content\">\n <MaterialPanel v-show=\"leftTab === 'material'\" :designerState=\"designerState\" :materialTabs=\"props.materialTabs\" />\n <OutlinePanel v-show=\"leftTab === 'outline'\" :designerState=\"designerState\" />\n </div>\n </div>\n <!-- 中间: 画布 -->\n <div class=\"designer-workbench-center\">\n <DesignCanvas v-if=\"!previewMode\" :designerState=\"designerState\" :block=\"props.block\" />\n <BlockComponent\n v-else\n class=\"designer-workbench-preview\"\n :componentManage=\"engine.componentManage\"\n :block=\"previewBlock\"\n :isDesigning=\"false\"\n />\n </div>\n <!-- 右侧: 配置面板 -->\n <div class=\"designer-workbench-right\">\n <Tabs v-model:activeKey=\"rightTab\" size=\"small\" class=\"designer-workbench-right-tabs\"\n :items=\"[\n { key: 'props', label: '属性' },\n { key: 'style', label: '样式' },\n { key: 'events', label: '事件' },\n { key: 'advanced', label: '高级' },\n ]\"/>\n <div class=\"designer-workbench-right-content\">\n <SetterPropsPanel v-show=\"rightTab === 'props'\" :designerState=\"designerState\" :propsPanel=\"propsPanel\" />\n <SetterStylePanel v-show=\"rightTab === 'style'\" :designerState=\"designerState\" :stylePanel=\"stylePanel\" />\n <SetterEventPanel v-show=\"rightTab === 'events'\" :designerState=\"designerState\" :eventPanel=\"eventPanel\" />\n <SetterAdvancedPanel v-show=\"rightTab === 'advanced'\" :designerState=\"designerState\" :advancedPanel=\"advancedPanel\" />\n </div>\n </div>\n </div>\n <DragGhost :designerEngine=\"engine\" />\n </div>\n</template>\n\n<style scoped>\n.designer-workbench {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: #fff;\n}\n\n.designer-workbench-toolbar {\n flex: none;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 12px;\n border-bottom: 1px solid #e5e7eb;\n background: #fafafa;\n}\n\n.designer-workbench-toolbar-group {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.designer-workbench-toolbar-title {\n font-size: 14px;\n font-weight: 600;\n color: #374151;\n}\n\n.designer-workbench-body {\n flex: 1;\n display: flex;\n min-height: 0;\n}\n\n.designer-workbench-left {\n flex: none;\n width: 240px;\n display: flex;\n flex-direction: column;\n border-right: 1px solid #e5e7eb;\n min-height: 0;\n}\n\n.designer-workbench-left-tabs,\n.designer-workbench-right-tabs {\n flex: none;\n padding: 0 8px;\n margin-bottom: 0;\n}\n\n.designer-workbench-left-content,\n.designer-workbench-right-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.designer-workbench-center {\n flex: 1;\n min-width: 0;\n padding: 12px;\n}\n\n.designer-workbench-preview {\n width: 100%;\n height: 100%;\n overflow: auto;\n}\n\n.designer-workbench-right {\n flex: none;\n width: 320px;\n display: flex;\n flex-direction: column;\n border-left: 1px solid #e5e7eb;\n min-height: 0;\n}\n</style>\n","import lodash from \"lodash\";\nimport { markRaw, watch } from \"vue\";\nimport { Typeof } from \"@ease-forge/shared\";\nimport type { BlockInstance, RuntimeNode, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport type { DesignerState } from \"../models/DesignerState\";\nimport { type UpdatePropsChange, UpdatePropsCommand } from \"../operations/commands/UpdatePropsCommand\";\n\n/** 当选中多个节点且节点的同一属性有不同值时的提示文本 */\nconst multipleValuesText = \"存在多个不同值\";\n\n/** setter值转换函数 */\ntype ValueTransform<T = any> = (value: any) => T | undefined;\n\n/** setter值转换成object */\nconst toObj: ValueTransform = value => {\n if (Typeof.noValue(value)) return;\n return markRaw(value);\n};\n\n/** setter值转换成string */\nconst toStr: ValueTransform<string> = value => {\n return lodash.toString(value);\n};\n\n/** setter值转换成boolean */\nconst toBool: ValueTransform<boolean> = value => {\n return !!value;\n};\n\n/** setter值转换成number */\nconst toNumber: ValueTransform<number> = value => {\n if (Typeof.noValue(value)) return;\n value = lodash.toNumber(value);\n if (value === Infinity || isNaN(value)) {\n value = undefined;\n }\n return value;\n};\n\n/** setter值使用JSON.stringify序列化成字符串 */\nconst jsonStringify: ValueTransform<string> = value => {\n if (!value) return \"\";\n return JSON.stringify(value, null, 4);\n};\n\n/**\n * 获取 state 默认值\n */\nfunction getDefState(): SetterState {\n return {\n multipleValues: false,\n value: undefined,\n };\n}\n\n/**\n * 获取setter值(多节点取值不一致时标记 multipleValues)\n * @param props 设置器组件 props 属性\n * @param state 设置器组件 state 属性\n * @param transform setter值转换函数\n */\nfunction getValue<R = any>(props: SetterProps, state: SetterState, transform?: ValueTransform<R>): R {\n let value = _doGetValue(props, state, transform);\n if (Typeof.isFunction(transform)) {\n value = transform(value);\n }\n return value;\n}\n\nfunction _doGetValue(props: SetterProps, state: SetterState, transform?: ValueTransform): any {\n const { nodes, propsName, getPropsValue } = props;\n if (!nodes) return;\n if (!propsName && !Typeof.isFunction(getPropsValue)) return;\n const values = new Set<any>();\n for (const node of nodes) {\n let value = undefined;\n if (getPropsValue) {\n // 根据 getPropsValue 取值\n value = getPropsValue(node.props, node);\n } else if (propsName) {\n if (lodash.hasIn(node.props, propsName)) {\n // 根据 propsName 取值\n value = node.props?.[propsName];\n } else {\n // 使用默认值\n value = props.defPropsValue;\n }\n }\n if (Typeof.isFunction(transform)) value = transform(value);\n if (Typeof.noValue(value)) value = undefined;\n values.add(value);\n if (values.size > 1) {\n break;\n }\n }\n if (values.size <= 0) {\n return;\n } else if (values.size === 1) {\n return values.values().next().value;\n } else {\n state.multipleValues = true;\n state.value = undefined;\n return;\n }\n}\n\n/**\n * 应用setter值到组件节点\n * 经由 UpdatePropsCommand 写入(可撤销/重做), 时间窗内的连续修改合并成一条历史;\n * applyPropsValue 钩子自行管理写入与重渲染的场景(如样式面板的防抖缓冲)不走命令,\n * 由钩子实现方(StyleUtils.applyStyle)自行构造命令\n * @param props 设置器组件 props 属性\n * @param state 设置器组件 state 属性\n * @param setter 设置器组件实例\n * @param value 应用的setter值\n */\nfunction applyValue<T = any>(props: SetterProps, state: SetterState, setter: any, value: T): boolean {\n const {\n designerState,\n blockInstance,\n nodes,\n propsName,\n applyPropsValue,\n disableReRender,\n recalcAuxToolPosition,\n recalcAuxToolPositionDelay,\n updateVNodeKey,\n } = props;\n let res = false;\n if (!nodes) return res;\n if (!propsName && !Typeof.isFunction(applyPropsValue)) return res;\n // ---- 自定义读写钩子: 保持钩子自身的写入与重渲染行为 ----\n if (Typeof.isFunction(applyPropsValue)) {\n for (const node of nodes) {\n res = applyPropsValue(node.props, value, node, setter) !== false;\n // 属性值更新后强制更新当前组件VNode的key值(解决某些组件props属性变化后无法生效问题)\n if (updateVNodeKey && res) {\n node.designExt.designKey = `__design_key_${Date.now()}_${Math.random().toString(36).slice(2, 12)}`;\n }\n }\n if (res) {\n state.multipleValues = false;\n forceUpdateBlock(designerState, blockInstance, nodes, disableReRender, recalcAuxToolPosition, recalcAuxToolPositionDelay);\n }\n return res;\n }\n // ---- propsName 直写: 构造属性修改命令 ----\n if (!propsName) return res;\n const changes: Array<UpdatePropsChange> = [];\n for (const node of nodes) {\n if (!node.props) continue;\n const oldValue = lodash.hasIn(node.props, propsName) ? lodash.cloneDeep(node.props[propsName]) : undefined;\n // 值未变化的节点不产生历史记录\n if (lodash.isEqual(oldValue, value)) continue;\n changes.push({\n nodeId: node.id,\n changeKey: `props:${propsName}`,\n oldValue,\n newValue: value,\n write: (target, val) => {\n target.props[propsName!] = val;\n if (updateVNodeKey) {\n target.designExt.designKey = `__design_key_${Date.now()}_${Math.random().toString(36).slice(2, 12)}`;\n }\n },\n });\n }\n if (changes.length <= 0) return res;\n const command = new UpdatePropsCommand(designerState, `修改属性 ${propsName}`, {\n changes,\n disableReRender,\n });\n res = designerState.commandStack.execute(command);\n if (res) state.multipleValues = false;\n return res;\n}\n\n/**\n * 强制重新渲染 Block 组件\n */\nfunction forceUpdateBlock(designerState: DesignerState, blockInstance: BlockInstance | undefined, nodes: Array<RuntimeNode>, disableReRender?: boolean, recalcAuxToolPosition?: boolean, recalcAuxToolPositionDelay?: number): void {\n if (!disableReRender && blockInstance) {\n blockInstance.$forceUpdate();\n // 重新计算选中框的位置(更新属性有可能改变渲染节点的大小和位置)\n if (recalcAuxToolPosition) {\n const recalcFun = () => {\n const nodeIds = nodes.map(node => node.id);\n for (const selection of designerState.selections) {\n if (selection.nodeId && nodeIds.includes(selection.nodeId)) {\n selection.recalcPosition();\n }\n }\n };\n blockInstance.$nextTick(() => {\n if ((recalcAuxToolPositionDelay ?? 0) > 0) {\n setTimeout(recalcFun, recalcAuxToolPositionDelay);\n } else {\n recalcFun();\n }\n });\n }\n }\n}\n\n/**\n * 监听选中的节点变化, 重新读取setter值\n */\nfunction watchNodes(props: SetterProps, state: SetterState, transform?: ValueTransform): void {\n watch(() => props.nodes, () => {\n state.value = getValue(props, state, transform);\n });\n}\n\n/**\n * 定义设置器组件公开内容\n */\nfunction getSetterExpose<T = any>(props: SetterProps, state: SetterState, setter: any, transform?: ValueTransform<T>) {\n return {\n designerState: props.designerState,\n blockInstance: props.blockInstance,\n nodes: props.nodes,\n getValue: () => state.value,\n setValue: (value: any) => {\n if (Typeof.isFunction(transform)) value = transform(value);\n state.value = value;\n applyValue(props, state, setter, value);\n },\n };\n}\n\nexport type {\n ValueTransform,\n}\n\nexport {\n multipleValuesText,\n toObj,\n toStr,\n toBool,\n toNumber,\n jsonStringify,\n getDefState,\n getValue,\n applyValue,\n forceUpdateBlock,\n watchNodes,\n getSetterExpose,\n}\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { Input } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'StringSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <Input\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请输入'\"\n :title=\"state.multipleValues ? '存在多个不同值' : undefined\"\n v-bind=\"$attrs\"\n v-model:value=\"state.value\"\n @change=\"() => applyValue(props, state, instance?.proxy, state.value)\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { Input } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'StringSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <Input\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请输入'\"\n :title=\"state.multipleValues ? '存在多个不同值' : undefined\"\n v-bind=\"$attrs\"\n v-model:value=\"state.value\"\n @change=\"() => applyValue(props, state, instance?.proxy, state.value)\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { InputNumber } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toNumber, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'NumberSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<number>>({\n ...getDefState(),\n});\nstate.value = getValue<number>(props, state, toNumber);\nwatchNodes(props, state, toNumber);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toNumber),\n});\n</script>\n\n<template>\n <InputNumber\n class=\"designer-setter-full\"\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请输入'\"\n v-bind=\"$attrs\"\n v-model:value=\"state.value\"\n @change=\"value => applyValue(props, state, instance?.proxy, value)\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { InputNumber } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toNumber, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'NumberSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<number>>({\n ...getDefState(),\n});\nstate.value = getValue<number>(props, state, toNumber);\nwatchNodes(props, state, toNumber);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toNumber),\n});\n</script>\n\n<template>\n <InputNumber\n class=\"designer-setter-full\"\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请输入'\"\n v-bind=\"$attrs\"\n v-model:value=\"state.value\"\n @change=\"value => applyValue(props, state, instance?.proxy, value)\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { Switch } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toBool, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'BoolSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<boolean>>({\n ...getDefState(),\n});\nstate.value = getValue<boolean>(props, state, toBool);\nwatchNodes(props, state, toBool);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toBool),\n});\n</script>\n\n<template>\n <Switch\n v-bind=\"$attrs\"\n :checked=\"!!state.value\"\n @change=\"(checked: any) => { state.value = checked; applyValue(props, state, instance?.proxy, checked); }\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { Switch } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toBool, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'BoolSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<boolean>>({\n ...getDefState(),\n});\nstate.value = getValue<boolean>(props, state, toBool);\nwatchNodes(props, state, toBool);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toBool),\n});\n</script>\n\n<template>\n <Switch\n v-bind=\"$attrs\"\n :checked=\"!!state.value\"\n @change=\"(checked: any) => { state.value = checked; applyValue(props, state, instance?.proxy, checked); }\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { Select } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'SelectSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<any>>({\n ...getDefState(),\n});\n// 初始值经 toStr 转换, 与 watchNodes/getSetterExpose 的取值形态保持一致(否则回显匹配 options 时类型不一致)\nstate.value = getValue(props, state, toStr);\nwatchNodes(props, state, toStr);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <Select\n class=\"designer-setter-full\"\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请选择'\"\n v-bind=\"$attrs\"\n :value=\"state.value\"\n @change=\"value => { state.value = value; applyValue(props, state, instance?.proxy, value); }\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { Select } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'SelectSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<any>>({\n ...getDefState(),\n});\n// 初始值经 toStr 转换, 与 watchNodes/getSetterExpose 的取值形态保持一致(否则回显匹配 options 时类型不一致)\nstate.value = getValue(props, state, toStr);\nwatchNodes(props, state, toStr);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <Select\n class=\"designer-setter-full\"\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请选择'\"\n v-bind=\"$attrs\"\n :value=\"state.value\"\n @change=\"value => { state.value = value; applyValue(props, state, instance?.proxy, value); }\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'ColorSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\nfunction clearValue(): void {\n state.value = undefined;\n applyValue(props, state, instance?.proxy, undefined);\n}\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <div class=\"designer-color-setter\">\n <input\n class=\"color-input\"\n type=\"color\"\n :value=\"state.value ?? '#000000'\"\n @change=\"event => { state.value = (event.target as HTMLInputElement).value; applyValue(props, state, instance?.proxy, state.value); }\"\n />\n <span class=\"color-text\">{{ state.value }}</span>\n <span v-show=\"state.value\" class=\"color-clear\" title=\"清除颜色\" @click=\"clearValue\">×</span>\n </div>\n</template>\n\n<style scoped>\n.designer-color-setter {\n display: flex;\n align-items: center;\n min-height: 24px;\n}\n\ninput[type=color].color-input {\n width: 24px;\n height: 24px;\n border: none;\n background: transparent;\n padding: 0;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.color-text {\n margin-left: 8px;\n font-size: 12px;\n color: #6b7280;\n}\n\n.color-clear {\n margin-left: 6px;\n padding: 0 6px;\n font-size: 14px;\n line-height: 20px;\n color: #6b7280;\n cursor: pointer;\n border-radius: 4px;\n}\n\n.color-clear:hover {\n background: #f3f4f6;\n color: #1677ff;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'ColorSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\nfunction clearValue(): void {\n state.value = undefined;\n applyValue(props, state, instance?.proxy, undefined);\n}\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <div class=\"designer-color-setter\">\n <input\n class=\"color-input\"\n type=\"color\"\n :value=\"state.value ?? '#000000'\"\n @change=\"event => { state.value = (event.target as HTMLInputElement).value; applyValue(props, state, instance?.proxy, state.value); }\"\n />\n <span class=\"color-text\">{{ state.value }}</span>\n <span v-show=\"state.value\" class=\"color-clear\" title=\"清除颜色\" @click=\"clearValue\">×</span>\n </div>\n</template>\n\n<style scoped>\n.designer-color-setter {\n display: flex;\n align-items: center;\n min-height: 24px;\n}\n\ninput[type=color].color-input {\n width: 24px;\n height: 24px;\n border: none;\n background: transparent;\n padding: 0;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.color-text {\n margin-left: 8px;\n font-size: 12px;\n color: #6b7280;\n}\n\n.color-clear {\n margin-left: 6px;\n padding: 0 6px;\n font-size: 14px;\n line-height: 20px;\n color: #6b7280;\n cursor: pointer;\n border-radius: 4px;\n}\n\n.color-clear:hover {\n background: #f3f4f6;\n color: #1677ff;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { DatePicker } from \"antdv-next\";\nimport dayjs, { type Dayjs } from \"dayjs\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'DateSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\n/** 字符串值转 Dayjs(控件需要) */\nfunction toDayjs(value: string | undefined): Dayjs | undefined {\n return value ? dayjs(value) : undefined;\n}\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <DatePicker\n class=\"designer-setter-full\"\n :value=\"toDayjs(state.value)\"\n v-bind=\"$attrs\"\n valueFormat=\"YYYY-MM-DD\"\n @change=\"(_date: any, dateString: string | Array<string>) => {\n const value = Array.isArray(dateString) ? dateString[0] : dateString;\n state.value = value || undefined;\n applyValue(props, state, instance?.proxy, state.value);\n }\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { DatePicker } from \"antdv-next\";\nimport dayjs, { type Dayjs } from \"dayjs\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'DateSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\n/** 字符串值转 Dayjs(控件需要) */\nfunction toDayjs(value: string | undefined): Dayjs | undefined {\n return value ? dayjs(value) : undefined;\n}\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <DatePicker\n class=\"designer-setter-full\"\n :value=\"toDayjs(state.value)\"\n v-bind=\"$attrs\"\n valueFormat=\"YYYY-MM-DD\"\n @change=\"(_date: any, dateString: string | Array<string>) => {\n const value = Array.isArray(dateString) ? dateString[0] : dateString;\n state.value = value || undefined;\n applyValue(props, state, instance?.proxy, state.value);\n }\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { TimePicker } from \"antdv-next\";\nimport dayjs, { type Dayjs } from \"dayjs\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'TimeSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\n/** 字符串值转 Dayjs(控件需要) */\nfunction toDayjs(value: string | undefined): Dayjs | undefined {\n return value ? dayjs(value, \"HH:mm:ss\") : undefined;\n}\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <TimePicker\n class=\"designer-setter-full\"\n :value=\"toDayjs(state.value)\"\n v-bind=\"$attrs\"\n valueFormat=\"HH:mm:ss\"\n @change=\"(_time: any, timeString: string | Array<string>) => {\n const value = Array.isArray(timeString) ? timeString[0] : timeString;\n state.value = value || undefined;\n applyValue(props, state, instance?.proxy, state.value);\n }\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { TimePicker } from \"antdv-next\";\nimport dayjs, { type Dayjs } from \"dayjs\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'TimeSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\n/** 字符串值转 Dayjs(控件需要) */\nfunction toDayjs(value: string | undefined): Dayjs | undefined {\n return value ? dayjs(value, \"HH:mm:ss\") : undefined;\n}\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <TimePicker\n class=\"designer-setter-full\"\n :value=\"toDayjs(state.value)\"\n v-bind=\"$attrs\"\n valueFormat=\"HH:mm:ss\"\n @change=\"(_time: any, timeString: string | Array<string>) => {\n const value = Array.isArray(timeString) ? timeString[0] : timeString;\n state.value = value || undefined;\n applyValue(props, state, instance?.proxy, state.value);\n }\"\n />\n</template>\n\n<style scoped>\n.designer-setter-full {\n width: 100%;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { TextArea } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'EditorSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <TextArea\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请输入内容'\"\n v-bind=\"$attrs\"\n v-model:value=\"state.value\"\n :autoSize=\"{ minRows: 2, maxRows: 12 }\"\n @change=\"() => applyValue(props, state, instance?.proxy, state.value)\"\n />\n</template>\n\n<style scoped>\n\n</style>\n","<script setup lang=\"ts\">\nimport { getCurrentInstance, reactive } from \"vue\";\nimport { TextArea } from \"antdv-next\";\nimport type { SetterExpose, SetterProps, SetterState } from \"@ease-forge/runtime\";\nimport { applyValue, getDefState, getSetterExpose, getValue, toStr, watchNodes } from \"../../utils/SetterUtils\";\n\ndefineOptions({ name: 'EditorSetter' });\n\nconst instance = getCurrentInstance();\nconst props = withDefaults(defineProps<SetterProps>(), {});\n\nconst state = reactive<SetterState<string>>({\n ...getDefState(),\n});\nstate.value = getValue<string>(props, state, toStr);\nwatchNodes(props, state, toStr);\n\ndefineExpose<SetterExpose>({\n ...getSetterExpose(props, state, instance?.proxy, toStr),\n});\n</script>\n\n<template>\n <TextArea\n :placeholder=\"state.multipleValues ? '存在多个不同值' : '请输入内容'\"\n v-bind=\"$attrs\"\n v-model:value=\"state.value\"\n :autoSize=\"{ minRows: 2, maxRows: 12 }\"\n @change=\"() => applyValue(props, state, instance?.proxy, state.value)\"\n />\n</template>\n\n<style scoped>\n\n</style>\n","import type { ComponentManage } from \"@ease-forge/runtime\";\nimport StringSetter from \"../components/setter/StringSetter.vue\";\nimport NumberSetter from \"../components/setter/NumberSetter.vue\";\nimport BoolSetter from \"../components/setter/BoolSetter.vue\";\nimport SelectSetter from \"../components/setter/SelectSetter.vue\";\nimport ColorSetter from \"../components/setter/ColorSetter.vue\";\nimport DateSetter from \"../components/setter/DateSetter.vue\";\nimport TimeSetter from \"../components/setter/TimeSetter.vue\";\nimport EditorSetter from \"../components/setter/EditorSetter.vue\";\n\n/**\n * 注册组件设置器(Setter 组件按名称注册到组件管理器, 供 ComponentMeta.setter 配置中的 cmp 字符串解析)\n * TODO(designer-meta 阶段): IconSetter(FontAwesome图标选择完整版)\n */\nfunction registerSetterComponents(componentManage: ComponentManage): void {\n componentManage.registerComponent(\"StringSetter\", StringSetter);\n componentManage.registerComponent(\"NumberSetter\", NumberSetter);\n componentManage.registerComponent(\"BoolSetter\", BoolSetter);\n componentManage.registerComponent(\"SelectSetter\", SelectSetter);\n componentManage.registerComponent(\"ColorSetter\", ColorSetter);\n componentManage.registerComponent(\"DateSetter\", DateSetter);\n componentManage.registerComponent(\"TimeSetter\", TimeSetter);\n componentManage.registerComponent(\"EditorSetter\", EditorSetter);\n}\n\nexport {\n registerSetterComponents,\n}\n","/**\n * @ease-forge/designer\n * 可视化页面设计器 (架构级重构自 clever-app-studio/src/draggable)\n * 实施阶段: 6/6 (面板与组装: Workbench 工作台 + 物料/大纲/样式/事件/高级面板)\n */\n\n/** designer 包版本号(与 package.json 保持一致) */\nconst DESIGNER_VERSION = \"1.1.0\";\n\n/** 当前实施阶段标记, 全部阶段完成后移除 */\nconst DESIGNER_STAGE = 6;\n\n// ---------------- types ----------------\nexport * from \"./types/Designer\";\n\n// ---------------- events ----------------\nexport { DesignerEvent } from \"./events/DesignerEvent\";\nexport type { DesignerEventConstructor } from \"./events/DesignerEvent\";\nexport { EngineMountEvent } from \"./events/engine/EngineMountEvent\";\nexport type { EngineMountEventData } from \"./events/engine/EngineMountEvent\";\nexport { EngineUnmountEvent } from \"./events/engine/EngineUnmountEvent\";\nexport type { EngineUnmountEventData } from \"./events/engine/EngineUnmountEvent\";\n// cursor 事件\nexport { AbstractCursorEvent } from \"./events/cursor/AbstractCursorEvent\";\nexport type { CursorEventData } from \"./events/cursor/AbstractCursorEvent\";\nexport { DragStartEvent } from \"./events/cursor/DragStartEvent\";\nexport type { DragStartEventData } from \"./events/cursor/DragStartEvent\";\nexport { DragMoveEvent } from \"./events/cursor/DragMoveEvent\";\nexport { DragStopEvent } from \"./events/cursor/DragStopEvent\";\nexport { MouseClickEvent } from \"./events/cursor/MouseClickEvent\";\nexport { MouseDoubleClickEvent } from \"./events/cursor/MouseDoubleClickEvent\";\nexport { MouseMoveEvent } from \"./events/cursor/MouseMoveEvent\";\n// keyboard 事件\nexport { ShortcutKeyEvent } from \"./events/keyboard/ShortcutKeyEvent\";\nexport type { ShortcutKeyEventData } from \"./events/keyboard/ShortcutKeyEvent\";\n// designer 业务事件\nexport { DragDropEvent } from \"./events/designer/DragDropEvent\";\nexport type { DragDropEventData } from \"./events/designer/DragDropEvent\";\nexport { CommandEvent } from \"./events/designer/CommandEvent\";\nexport type { CommandEventData } from \"./events/designer/CommandEvent\";\n\n// ---------------- core ----------------\nexport { EventBus } from \"./core/EventBus\";\nexport type { Subscriber } from \"./core/EventBus\";\nexport { DesignerModule } from \"./core/DesignerModule\";\nexport { DesignerDriver } from \"./core/DesignerDriver\";\nexport type { DesignerDriverConstructor } from \"./core/DesignerDriver\";\nexport { DesignerEffect } from \"./core/DesignerEffect\";\nexport type { DesignerEffectConstructor } from \"./core/DesignerEffect\";\nexport { DesignerEngine } from \"./core/DesignerEngine\";\nexport type { DesignerEngineProps } from \"./core/DesignerEngine\";\n\n// ---------------- models ----------------\nexport { Cursor } from \"./models/Cursor\";\nexport { DraggingCmpMetas } from \"./models/DraggingCmpMetas\";\nexport { HoverDashed } from \"./models/HoverDashed\";\nexport { Selection } from \"./models/Selection\";\nexport { Insertion } from \"./models/Insertion\";\nexport { DesignerState } from \"./models/DesignerState\";\nexport { SetterShareState } from \"./models/SetterShareState\";\n\n// ---------------- drivers ----------------\nexport { DragDropDriver } from \"./drivers/DragDropDriver\";\nexport { KeyboardDriver } from \"./drivers/KeyboardDriver\";\nexport { MouseClickDriver } from \"./drivers/MouseClickDriver\";\nexport { MouseMoveDriver } from \"./drivers/MouseMoveDriver\";\n\n// ---------------- effects ----------------\nexport { CursorEffect } from \"./effects/CursorEffect\";\nexport { DraggingEffect } from \"./effects/DraggingEffect\";\nexport { AuxToolEffect } from \"./effects/AuxToolEffect\";\nexport { NodeOperationEffect } from \"./operations/NodeOperationEffect\";\n\n// ---------------- history ----------------\nexport type { DesignCommand } from \"./history/Command\";\nexport { CommandStack } from \"./history/CommandStack\";\n\n// ---------------- operations ----------------\nexport type { InsertPosition, InsertTarget } from \"./operations/NodePosition\";\nexport { getNodeInsertTarget, getNodeDocIndex, applyMoveNodes, applyAddNodes, insertionToTarget, toRuntimeNodes } from \"./operations/NodePosition\";\nexport { runtimeNodeToDesignNode } from \"./operations/NodeSerialize\";\nexport { AddNodesCommand } from \"./operations/commands/AddNodesCommand\";\nexport type { AddNodesCommandOptions } from \"./operations/commands/AddNodesCommand\";\nexport { MoveNodesCommand } from \"./operations/commands/MoveNodesCommand\";\nexport type { MoveNodesCommandOptions } from \"./operations/commands/MoveNodesCommand\";\nexport { RemoveNodesCommand } from \"./operations/commands/RemoveNodesCommand\";\nexport type { RemoveNodesCommandOptions } from \"./operations/commands/RemoveNodesCommand\";\nexport { UpdatePropsCommand } from \"./operations/commands/UpdatePropsCommand\";\nexport type { UpdatePropsChange, UpdatePropsCommandOptions } from \"./operations/commands/UpdatePropsCommand\";\nexport { UpdateListenersCommand } from \"./operations/commands/UpdateListenersCommand\";\nexport type { UpdateListenersChange, UpdateListenersCommandOptions } from \"./operations/commands/UpdateListenersCommand\";\n\n// ---------------- components ----------------\nexport { default as DesignCanvas } from \"./components/DesignCanvas.vue\";\nexport { default as DragGhost } from \"./components/DragGhost.vue\";\nexport { default as Workbench } from \"./components/Workbench.vue\";\nexport { default as SetterPropsPanel } from \"./components/panels/SetterPropsPanel.vue\";\nexport { default as SetterStylePanel } from \"./components/panels/SetterStylePanel.vue\";\nexport { default as SetterEventPanel } from \"./components/panels/SetterEventPanel.vue\";\nexport { default as SetterAdvancedPanel } from \"./components/panels/SetterAdvancedPanel.vue\";\nexport { default as MaterialPanel } from \"./components/panels/MaterialPanel.vue\";\nexport { default as OutlinePanel } from \"./components/panels/OutlinePanel.vue\";\nexport { styleGroupDefines } from \"./components/panels/style/StyleGroups\";\nexport type { StyleSetterCmp, StyleItemDefine, StyleGroupDefine } from \"./components/panels/style/StyleGroups\";\n\n// ---------------- register ----------------\nexport { registerSetterComponents } from \"./register/RegisterSetter\";\n\n// ---------------- setter utils ----------------\nexport {\n multipleValuesText,\n toObj,\n toStr,\n toBool,\n toNumber,\n jsonStringify,\n getDefState,\n getValue as getSetterValue,\n applyValue as applySetterValue,\n forceUpdateBlock,\n watchNodes,\n getSetterExpose,\n} from \"./utils/SetterUtils\";\nexport type { ValueTransform as SetterValueTransform } from \"./utils/SetterUtils\";\n\n// ---------------- style utils ----------------\nexport {\n applyStyleDebounceTime,\n toObjectStyle,\n getStyle,\n applyStyle,\n applyClass,\n getActiveClass,\n} from \"./utils/StyleUtils\";\n\n// ---------------- utils ----------------\nexport {\n defCursorPosition,\n calcAuxToolPosition,\n calcNodeToCursorDistance,\n calcDistance,\n calcPositionDelta,\n} from \"./utils/PositionCalc\";\nexport { existsPlaceholder } from \"./utils/ComponentMetaUtils\";\nexport { isAllowDrag } from \"./utils/DesignerUtils\";\n\nexport {\n DESIGNER_VERSION,\n DESIGNER_STAGE,\n}\n"],"mappings":"0xBAIA,IAAK,EAAL,SAAA,EAAA,OAEI,GAAA,OAAA,SAEA,EAAA,UAAA,aAEA,EAAA,SAAA,WAEA,EAAA,SAAA,aACJ,EATK,GAAA,CAAA,CASL,EAuBK,EAAL,SAAA,EAAA,OAEI,GAAA,SAAA,WAEA,EAAA,UAAA,aACJ,EALK,GAAA,CAAA,CAKL,EAGK,EAAL,SAAA,EAAA,OAEI,GAAA,GAAA,KAEA,EAAA,OAAA,UACJ,EALK,GAAA,CAAA,CAKL,EAGK,EAAL,SAAA,EAAA,OAEI,GAAA,SAAA,WAEA,EAAA,KAAA,OAEA,EAAA,QAAA,WACJ,EAPK,GAAA,CAAA,CAOL,EA0BK,EAAL,SAAA,EAAA,OACI,GAAA,IAAA,MACA,EAAA,OAAA,SACA,EAAA,KAAA,OACA,EAAA,MAAA,SACJ,EALK,GAAA,CAAA,CAKL,EAGK,EAAL,SAAA,EAAA,OACI,GAAA,QAAA,UACA,EAAA,WAAA,aACA,EAAA,SAAA,WACA,EAAA,YAAA,eACJ,EALK,GAAA,CAAA,CAKL,ECrFe,EAAf,KAAyC,CAErC,OAAgB,UAAoB,GAEpC,KAEA,KAEA,QAEA,YAAY,EAAa,EAAe,CACpC,KAAK,KAAQ,KAAK,YAAyC,UACtD,KAAK,MACN,QAAQ,KAAK,wBAAwB,KAAK,YAAY,KAAK,qBAAqB,EAEhF,IAAS,IAAA,KAAW,KAAK,KAAO,GAChC,IAAY,IAAA,KAAW,KAAK,QAAU,EAC9C,CACJ,ECdM,EAAN,cAA+B,CAAoC,CAC/D,OAAgB,UAAY,cAChC,ECPM,EAAN,cAAiC,CAAsC,CACnE,OAAgB,UAAY,gBAChC,ECMe,EAAf,cAA2F,CAAoB,CAC3G,YAAY,EAAmB,CAC3B,MAAM,EACN,KAAK,KAAO,GAAqB,CAAK,CAC1C,CACJ,EAKA,SAAS,GAAqB,EAAoC,CAC9D,IAAM,EAAwB,CAC1B,QAAS,EAAM,QACf,QAAS,EAAM,QACf,MAAO,EAAM,MACb,MAAO,EAAM,MACb,OAAQ,EAAM,OACd,KAAM,EAAM,KACZ,WAAY,EAAM,QAClB,WAAY,EAAM,QAClB,SAAU,EAAM,MAChB,SAAU,EAAM,KACpB,EAEM,CAAE,gBAAiB,EAAM,MAAQ,CAAC,EACxC,GAAI,GAAgB,EAAK,OAAS,EAAA,mBAAoB,CAElD,IAAM,EAAY,EAAa,sBAAsB,EAI/C,EAAQ,EAAU,MAAS,EAA6B,YAE9D,EAAK,WAAa,EAAK,QAAU,EAAQ,EAAU,EACnD,EAAK,WAAa,EAAK,QAAU,EAAQ,EAAU,EACnD,EAAK,SAAW,EAAK,MAAQ,EAAU,EAAI,EAAK,KAAK,QACrD,EAAK,SAAW,EAAK,MAAQ,EAAU,EAAI,EAAK,KAAK,QAErD,IAAM,EAAa,SAAS,iBAAiB,EAAK,SAAU,EAAK,UAAU,EACvE,IAAe,IAAc,EAAK,OAAS,EACnD,CACA,OAAO,CACX,CCjDA,IAAM,EAAN,cAA6B,CAAwC,CACjE,OAAgB,UAAY,oBAE5B,YAAY,EAAmB,EAA4C,CACvE,MAAM,CAAK,EACX,KAAK,KAAM,eAAiB,CAChC,CACJ,ECdM,EAAN,cAA4B,CAAoB,CAC5C,OAAgB,UAAY,kBAChC,ECFM,EAAN,cAA4B,CAAoB,CAC5C,OAAgB,UAAY,kBAChC,ECFM,GAAN,cAA8B,CAAoB,CAC9C,OAAgB,UAAY,oBAChC,ECFM,GAAN,cAAoC,CAAoB,CACpD,OAAgB,UAAY,2BAChC,ECFM,EAAN,cAA6B,CAAoB,CAC7C,OAAgB,UAAY,mBAChC,ECmBM,GAAN,cAA+B,CAAoC,CAC/D,OAAgB,UAAY,oBAE5B,YAAY,EAAyB,EAAkC,CACnE,MAAM,CACF,KAAM,EAAS,KACf,IAAK,EAAS,IAAI,YAAY,EAC9B,QAAS,EAAS,QAClB,SAAU,EAAS,SACnB,OAAQ,EAAS,OACjB,QAAS,EAAS,QAClB,cACA,UACJ,CAAC,CACL,CACJ,ECjBM,GAAN,cAA4B,CAAiC,CACzD,OAAgB,UAAY,oBAChC,ECXM,GAAN,cAA2B,CAAgC,CACvD,OAAgB,UAAY,kBAChC,ECJM,GAAN,KAAe,CAEX,YAAuE,IAAI,IAM3E,SAAsC,EAAoB,CACtD,IAAM,EAAM,KAAK,YAAY,IAAI,EAAM,IAAI,EAC3C,GAAI,CAAC,GAAO,EAAI,QAAU,EAAG,OAE7B,IAAM,EAAW,EAAI,MAAM,EAC3B,IAAK,IAAM,KAAc,EACrB,GAAI,CACA,EAAW,IAAI,CAAK,CACxB,OAAS,EAAK,CAEV,QAAQ,MAAM,kBAAkB,EAAM,KAAK,aAAc,CAAG,CAChE,CAER,CASA,UACI,EACA,EACA,EAAmB,EACT,CACV,IAAM,EAAY,EAAW,UAC7B,GAAI,CAAC,EAED,OADA,QAAQ,MAAM,sBAAsB,EAAW,KAAK,qBAAqB,MAC5D,IAAA,GAEjB,IAAI,EAAM,KAAK,YAAY,IAAI,CAAS,EACnC,IACD,EAAM,CAAC,EACP,KAAK,YAAY,IAAI,EAAW,CAAG,GAGvC,IAAM,EAA2B,CAAE,WAAU,IAAK,CAAyB,EACvE,EAAY,EAAI,OACpB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,OAAQ,IAC5B,GAAI,EAAI,EAAE,CAAC,SAAW,EAAU,CAC5B,EAAY,EACZ,KACJ,CAIJ,OAFA,EAAI,OAAO,EAAW,EAAG,CAAI,MAEhB,KAAK,YAAY,EAAY,CAAU,CACxD,CAOA,YAAyC,EAA6C,EAAqC,CACvH,IAAM,EAAM,KAAK,YAAY,IAAI,EAAW,SAAS,EACrD,GAAI,CAAC,EAAK,OACV,IAAM,EAAM,EAAI,UAAU,GAAQ,EAAK,MAAS,CAAyB,EACrE,GAAO,GAAG,EAAI,OAAO,EAAK,CAAC,CACnC,CAMA,eAAe,EAA4C,CACvD,KAAK,YAAY,OAAO,EAAW,SAAS,CAChD,CAGA,mBAA0B,CACtB,KAAK,YAAY,MAAM,CAC3B,CACJ,ECvFe,GAAf,KAA8B,CAE1B,eAEA,SAEA,gBAEA,UAEA,OAEA,YAAY,EAAgC,EAA2B,EAAgB,CACnF,KAAK,eAAiB,EACtB,KAAK,SAAW,EAAe,SAC/B,KAAK,gBAAkB,EAAe,gBACtC,KAAK,UAAY,EACjB,KAAK,OAAS,CAClB,CAGA,yBAA4C,CAIxC,OAHI,KAAK,qBAAqB,SACnB,KAAK,UAAU,KAAK,MAAM,OAE9B,KAAK,UAAU,MAAM,MAChC,CAGA,wBAAkC,EAA6C,CACvE,KAAK,qBAAqB,SAC1B,KAAK,UAAU,KAAK,MAAM,OAAS,EAEnC,KAAK,UAAU,MAAM,OAAS,CAEtC,CACJ,ECtCe,EAAf,cAAsC,EAAe,CASjD,iBAA2B,EAAW,EAAe,EAAqB,CACtE,KAAK,UAAU,iBAAiB,EAAM,EAAU,CAAO,CAC3D,CAUA,oBAA8B,EAAW,EAAe,EAAqB,CACzE,KAAK,UAAU,oBAAoB,EAAM,EAAU,CAAO,CAC9D,CAGA,eAA4B,GAAuB,CAC/C,EAAM,eAAe,CACzB,CAOJ,ECnCe,EAAf,cAAsC,EAAe,CAEjD,QAA6B,GAM7B,QAAe,CACP,KAAK,UACT,KAAK,QAAU,GACf,KAAK,SAAS,EAClB,CAMA,SAAgB,CACP,KAAK,UACV,KAAK,QAAU,GACf,KAAK,UAAU,EACnB,CAOJ,EChCM,GAAiB,IAAI,IAAI,kSAM/B,CAAC,EAGK,EAAoC,CACtC,QAAS,EACT,QAAS,EACT,MAAO,EACP,MAAO,EACP,WAAY,EACZ,WAAY,EACZ,SAAU,EACV,SAAU,CACd,EAKA,SAAS,GAAsB,EAAoB,EAAoC,CACnF,OACI,EACA,WAAW,EAAM,UAAU,EAC3B,WAAW,EAAM,WAAW,EAC5B,WAAW,EAAM,WAAW,EAC5B,WAAW,EAAM,YAAY,EAC7B,WAAW,EAAM,eAAe,EAChC,WAAW,EAAM,gBAAgB,CAEzC,CAKA,SAAS,GAAyB,EAA2B,CACzD,GAAI,CAAC,EAAS,MAAO,GACrB,IAAM,EAAS,EAAQ,cACvB,GAAI,CAAC,EAAQ,MAAO,GACpB,IAAM,EAAU,EAAQ,QAAQ,YAAY,EACtC,EAAgB,EAAO,QACvB,EAAQ,iBAAiB,CAAO,EAChC,EAAc,iBAAiB,CAAM,EACrC,MAAuB,CACzB,IAAM,EAAa,EAAQ,sBAAsB,CAAC,CAAC,MAC7C,EAAa,GAAsB,EAAY,CAAK,EACpD,EAAmB,EAAO,sBAAsB,CAAC,CAAC,MACxD,OAAO,EAAW,QAAQ,CAAC,EAAI,EAAiB,QAAQ,CAAC,CAC7D,EAiBA,OAhBI,IAAY,MAAQ,IAAY,OAC5B,IAAkB,MAEtB,EAAY,UAAY,QAAU,EAAY,gBAAkB,OAChE,EAAY,UAAY,QACpB,EAAe,EAAU,GAE7B,GAAe,IAAI,CAAO,EACtB,EAAM,UAAY,SAClB,EAAI,EAAM,QAAU,QAAU,EAAM,QAAU,SACtC,GAAe,GAMxB,EAAM,QAAQ,WAAW,QAAQ,CAC5C,CAOA,SAAS,EAAoB,EAAoB,EAAmC,CAChF,IAAM,EAAgB,EAAU,sBAAsB,EAChD,EAAc,EAAQ,sBAAsB,EAClD,MAAO,CACH,OAAQ,EAAY,OAAS,EAC7B,MAAO,EAAY,MAAQ,EAC3B,IAAK,EAAY,IAAM,EAAc,IAAM,EAAU,UAAY,EACjE,KAAM,EAAY,KAAO,EAAc,KAAO,EAAU,WAAa,EACrE,MAAO,EAAY,IAAM,EAAc,IAAM,GAC7C,SAAW,EAAc,IAAM,EAAc,OAAS,EAAY,IAAM,EAAY,OAAU,EAClG,CACJ,CAOA,SAAS,EAAyB,EAA0B,EAAwC,CAChG,IAAM,EAAc,EAAQ,sBAAsB,EAE5C,EAAM,EAAS,QAAU,EAAY,IACrC,EAAS,EAAS,QAAU,EAAY,IAAM,EAAY,OAC1D,EAAO,EAAS,QAAU,EAAY,KACtC,EAAQ,EAAS,QAAU,EAAY,KAAO,EAAY,MAC1D,EAAS,KAAK,IAAI,CAAG,EACrB,EAAY,KAAK,IAAI,CAAM,EAC3B,EAAU,KAAK,IAAI,CAAI,EACvB,EAAW,KAAK,IAAI,CAAK,EAEzB,EAAU,GAAO,GAAK,GAAU,EAChC,EAAU,GAAQ,GAAK,GAAS,EAChC,EAAa,GAAW,GAAW,EAAY,MAAQ,GAAK,EAAY,OAAS,EACnF,EACC,IACG,GAAO,EACP,EAAY,EAAU,IACf,GAAU,EACjB,EAAY,EAAU,OACf,GAAQ,EACf,EAAY,EAAU,KACf,GAAS,IAChB,EAAY,EAAU,QAG9B,IAAM,EAAqB,CACvB,CAAE,UAAW,EAAU,IAAK,MAAO,CAAO,EAC1C,CAAE,UAAW,EAAU,OAAQ,MAAO,CAAU,EAChD,CAAE,UAAW,EAAU,KAAM,MAAO,CAAQ,EAC5C,CAAE,UAAW,EAAU,MAAO,MAAO,CAAS,CAClD,EACA,AACI,IAAY,EAAA,QAAO,MAAM,EAAoB,GAAQ,EAAK,KAAK,CAAC,CAAE,UAGtE,IAAM,EAAc,GAAyB,CAAO,EAC9C,EAAW,CAAC,EAQlB,GAPI,GAAe,CAAC,EAAU,IAAK,EAAU,MAAM,CAAC,CAAC,SAAS,CAAS,IACnE,EAAY,GAAW,EAAW,EAAU,MAAQ,EAAU,MAE9D,GAAY,CAAC,EAAU,KAAM,EAAU,KAAK,CAAC,CAAC,SAAS,CAAS,IAChE,EAAY,GAAU,EAAY,EAAU,OAAS,EAAU,KAG/D,EAAY,CACZ,IAAM,EAAc,EAAA,QAAO,MAAM,EAAoB,GAAQ,EAAK,KAAK,EACnE,EAAY,OAAS,KACrB,EAAY,EAAY,UAEhC,CAEA,IAAM,EAAU,KAAK,IAAI,EAAa,EAAS,QAAS,EAAS,QAAS,EAAY,KAAM,EAAY,GAAG,CAAC,EACtG,EAAa,KAAK,IAAI,EAAa,EAAS,QAAS,EAAS,QAAS,EAAY,KAAM,EAAY,IAAM,EAAY,MAAM,CAAC,EAC9H,EAAW,KAAK,IAAI,EAAa,EAAS,QAAS,EAAS,QAAS,EAAY,KAAO,EAAY,MAAO,EAAY,GAAG,CAAC,EAC3H,EAAc,KAAK,IAAI,EAAa,EAAS,QAAS,EAAS,QAAS,EAAY,KAAO,EAAY,MAAO,EAAY,IAAM,EAAY,MAAM,CAAC,EACnJ,CAAE,SAAU,EAAA,QAAO,MACrB,CACI,CAAE,MAAO,EAAe,QAAS,MAAO,CAAQ,EAChD,CAAE,MAAO,EAAe,WAAY,MAAO,CAAW,EACtD,CAAE,MAAO,EAAe,SAAU,MAAO,CAAS,EAClD,CAAE,MAAO,EAAe,YAAa,MAAO,CAAY,CAC5D,EACA,GAAQ,EAAK,KACjB,EACA,MAAO,CACM,UACT,MAAO,EAAY,MACnB,OAAQ,EAAY,OACpB,IAAK,EACL,OAAQ,EACR,KAAM,EACN,MAAO,EACE,UACA,UACG,aACD,YACF,UACG,aACF,WACG,cACN,QACG,WACG,aACjB,CACJ,CAKA,SAAS,EAAa,EAAY,EAAY,EAAa,EAAG,EAAa,EAAW,CAIlF,MAHA,KAAW,EACX,IAAW,EAEJ,KAAK,MAAc,EAAK,IAAI,GAAc,EAAK,IAAI,CAAE,CAChE,CAOA,SAAS,EAAkB,EAAqB,EAAwC,CACpF,IAAM,EAAgB,CAAC,EACvB,IAAK,IAAM,KAAO,EACd,AAGI,EAAS,GAHT,EAAA,OAAO,cAAe,EAAY,EAAI,GAAK,EAAA,OAAO,cAAe,IAAgB,EAAI,EACpE,EAAY,GAAQ,EAAe,GAEnC,EAAY,GAGrC,OAAO,CACX,CC5MA,IAAM,GAAN,KAAa,CAET,SAAA,EAAgD,EAAA,IAAA,CAAkB,EAAa,MAAM,EAErF,WAAA,EAAoD,EAAA,IAAA,CAAoB,CAAE,GAAG,CAAkB,CAAC,EAEhG,oBAAA,EAAyE,EAAA,IAAA,CAAgC,EAEzG,kBAAA,EAAuE,EAAA,IAAA,CAAgC,EAEvG,gBAAA,EAAyD,EAAA,IAAA,CAAoB,CAAE,GAAG,CAAkB,CAAC,EAErG,0BAAA,EAA2E,EAAA,SAAA,KAEnE,CAAC,KAAK,mBAAmB,OAEzB,KAAK,QAAQ,QAAU,EAAa,SAAiB,EAElD,EAAkB,KAAK,UAAU,MAAO,KAAK,mBAAmB,KAAK,CAC/E,EAED,sBAAA,EAAuE,EAAA,SAAA,KAE/D,CAAC,KAAK,mBAAmB,OAAS,CAAC,KAAK,iBAAiB,MAAc,EAEpE,EAAkB,KAAK,mBAAmB,MAAO,KAAK,iBAAiB,KAAK,CACtF,EAGD,IAAI,QAAuB,CACvB,OAAO,KAAK,QAAQ,KACxB,CAEA,IAAI,OAAO,EAAsB,CAC7B,KAAK,QAAQ,MAAQ,CACzB,CAGA,IAAI,UAA2B,CAC3B,OAAO,KAAK,UAAU,KAC1B,CAEA,IAAI,SAAS,EAA0B,CACnC,KAAK,eAAe,MAAQ,EAAkB,KAAK,UAAU,MAAO,CAAQ,EAC5E,KAAK,UAAU,MAAQ,CAAE,GAAG,CAAS,CACzC,CAGA,IAAI,mBAAgD,CAChD,OAAO,KAAK,mBAAmB,KACnC,CAEA,IAAI,kBAAkB,EAAsC,CACxD,KAAK,mBAAmB,MAAQ,EAAW,CAAE,GAAG,CAAS,EAAI,IAAA,EACjE,CAGA,IAAI,iBAA8C,CAC9C,OAAO,KAAK,iBAAiB,KACjC,CAEA,IAAI,gBAAgB,EAAsC,CACtD,KAAK,iBAAiB,MAAQ,EAAW,CAAE,GAAG,CAAS,EAAI,IAAA,EAC/D,CAGA,IAAI,eAAgC,CAChC,OAAO,KAAK,eAAe,KAC/B,CAGA,IAAI,yBAA0C,CAC1C,OAAO,KAAK,yBAAyB,KACzC,CAGA,IAAI,qBAAsC,CACtC,OAAO,KAAK,qBAAqB,KACrC,CAGA,YAAsB,CAClB,OAAO,KAAK,QAAQ,QAAU,EAAa,QAC/C,CACJ,ECpFM,GAAN,KAAuB,CAEnB,UAAA,EAAyD,EAAA,WAAA,CAA0B,CAAC,CAAC,EAErF,YAAA,EAAoE,EAAA,WAAA,CAAmC,CAAC,CAAC,EAEzG,WAAA,EAAiE,EAAA,WAAA,CAAiC,CAAC,CAAC,EAEpG,gBAAA,EAA0D,EAAA,SAAA,KAAwB,KAAK,UAAU,MAAM,OAAS,CAAC,EAEjH,UAAA,EAAoD,EAAA,SAAA,KAAwB,KAAK,UAAU,MAAM,SAAW,CAAC,EAE7G,YAAA,EAAuE,EAAA,WAAA,CAAsC,EAG7G,IAAI,SAAyB,CACzB,OAAO,KAAK,SAAS,KACzB,CAEA,IAAI,QAAQ,EAAsB,CAC9B,KAAK,SAAS,MAAQ,CAC1B,CAGA,IAAI,WAAoC,CACpC,OAAO,KAAK,WAAW,KAC3B,CAEA,IAAI,UAAU,EAA+B,CACzC,KAAK,WAAW,MAAQ,CAC5B,CAGA,IAAI,UAAiC,CACjC,OAAO,KAAK,UAAU,KAC1B,CAEA,IAAI,SAAS,EAA6B,CACtC,KAAK,UAAU,MAAQ,CAC3B,CAGA,IAAI,eAAyB,CACzB,OAAO,KAAK,eAAe,KAC/B,CAGA,IAAI,SAAmB,CACnB,OAAO,KAAK,SAAS,KACzB,CAGA,IAAI,WAAuC,CACvC,OAAO,KAAK,WAAW,KAC3B,CAEA,IAAI,UAAU,EAAkC,CAC5C,KAAK,WAAW,MAAQ,CAC5B,CAGA,OAAc,CACV,KAAK,UAAU,MAAQ,CAAC,EACxB,KAAK,SAAS,MAAQ,CAAC,EACvB,KAAK,WAAW,MAAQ,CAAC,EACzB,KAAK,WAAW,MAAQ,IAAA,EAC5B,CACJ,ECnEM,GAAN,KAAgB,CAEZ,WAAA,EAA6E,EAAA,WAAA,CAA6C,EAE1H,WAAA,EAAwE,EAAA,WAAA,CAAwC,EAEhH,cAAA,EAA2D,EAAA,IAAA,CAAwB,EAEnF,WAAA,EAAwD,EAAA,IAAA,CAAwB,EAEhF,SAAA,EAAsD,EAAA,IAAA,CAAwB,EAE9E,cAAA,EAA4D,EAAA,IAAA,CAAyB,EAErF,YAAA,EAA8C,EAAA,IAAA,CAAa,EAAK,EAGhE,IAAI,UAA6C,CAC7C,OAAO,KAAK,UAAU,KAC1B,CAEA,IAAI,SAAS,EAAyC,CAClD,KAAK,UAAU,MAAQ,CAC3B,CAGA,IAAI,UAAwC,CACxC,OAAO,KAAK,UAAU,KAC1B,CAEA,IAAI,SAAS,EAAoC,CAC7C,KAAK,UAAU,MAAQ,CAC3B,CAGA,IAAI,aAAkC,CAClC,OAAO,KAAK,aAAa,KAC7B,CAEA,IAAI,YAAY,EAA2B,CACvC,KAAK,aAAa,MAAQ,CAC9B,CAGA,IAAI,UAA+B,CAC/B,OAAO,KAAK,UAAU,KAC1B,CAEA,IAAI,SAAS,EAA2B,CACpC,KAAK,UAAU,MAAQ,CAC3B,CAGA,IAAI,QAA6B,CAC7B,OAAO,KAAK,QAAQ,KACxB,CAEA,IAAI,OAAO,EAA2B,CAClC,KAAK,QAAQ,MAAQ,CACzB,CAGA,IAAI,aAAmC,CACnC,OAAO,KAAK,aAAa,KAC7B,CAEA,IAAI,YAAY,EAA4B,CACxC,KAAK,aAAa,MAAQ,CAC9B,CAGA,IAAI,WAAqB,CACrB,OAAO,KAAK,WAAW,KAC3B,CAEA,IAAI,UAAU,EAAgB,CAC1B,KAAK,WAAW,MAAQ,CAC5B,CAGA,IAAI,WAAmC,CACnC,OAAO,KAAK,UAAU,OAAO,SACjC,CAGA,UAAoB,CAChB,IAAM,EAAY,KAAK,UAAU,OAAO,UAExC,OADK,EACE,CAAC,EAAU,IAAK,EAAU,IAAI,CAAC,CAAC,SAAS,CAAS,EADlC,EAE3B,CAGA,cAAwB,CACpB,IAAM,EAAY,KAAK,UAAU,OAAO,UAExC,OADK,EACE,CAAC,EAAU,KAAM,EAAU,KAAK,CAAC,CAAC,SAAS,CAAS,EADpC,EAE3B,CAGA,SAAmB,CACf,OAAO,EAAA,OAAO,QAAQ,KAAK,UAAU,OAAO,SAAS,CACzD,CAGA,kBAA8C,CACtC,SAAK,QAAQ,EACjB,MAAO,CACH,SAAU,KAAK,SACf,SAAU,KAAK,SACf,YAAa,KAAK,YAClB,SAAU,KAAK,SACf,OAAQ,KAAK,OACb,YAAa,KAAK,YAClB,UAAW,KAAK,UAChB,OAAQ,KAAK,SAAS,CAC1B,CACJ,CAGA,OAAc,CACV,KAAK,UAAU,MAAQ,IAAA,GACvB,KAAK,UAAU,MAAQ,IAAA,GACvB,KAAK,aAAa,MAAQ,IAAA,GAC1B,KAAK,UAAU,MAAQ,IAAA,GACvB,KAAK,QAAQ,MAAQ,IAAA,GACrB,KAAK,aAAa,MAAQ,IAAA,GAC1B,KAAK,WAAW,MAAQ,EAC5B,CACJ,ECjIA,SAAS,GAAkB,EAAkG,CACzH,GAAI,CAAC,EAAa,MAAO,GACzB,IAAK,IAAM,KAAQ,EAEf,GADe,EAAY,GACf,MAAO,GAEvB,MAAO,EACX,CCFA,IAAM,GAAN,KAAkB,CAEd,cAEA,gBAAA,EAA2E,EAAA,WAAA,CAAsC,EAEjH,WAAA,EAAwD,EAAA,IAAA,CAAwB,EAEhF,SAAA,EAAsD,EAAA,IAAA,CAAwB,EAE9E,WAAA,EAAwE,EAAA,WAAA,CAAwC,EAEhH,YAAY,EAA8B,CACtC,KAAK,cAAgB,CACzB,CAGA,IAAI,eAA2C,CAC3C,OAAO,KAAK,eAAe,KAC/B,CAEA,IAAI,cAAc,EAAkC,CAChD,KAAK,eAAe,MAAQ,CAChC,CAGA,IAAI,UAA+B,CAC/B,OAAO,KAAK,UAAU,KAC1B,CAEA,IAAI,SAAS,EAA2B,CACpC,KAAK,UAAU,MAAQ,CAC3B,CAGA,IAAI,QAA6B,CAC7B,OAAO,KAAK,QAAQ,KACxB,CAEA,IAAI,OAAO,EAA2B,CAClC,KAAK,QAAQ,MAAQ,CACzB,CAGA,IAAI,UAAwC,CACxC,OAAO,KAAK,UAAU,KAC1B,CAEA,IAAI,SAAS,EAAoC,CAC7C,KAAK,UAAU,MAAQ,CAC3B,CAGA,IAAI,aAAuB,CACvB,IAAM,EAAgB,KAAK,eAAe,MAE1C,OADK,EACE,GAAkB,EAAc,WAAW,EADvB,EAE/B,CAGA,gBAAuB,CACnB,GAAI,CAAC,KAAK,QAAQ,MAAO,OACzB,IAAM,EAAoB,KAAK,cAAc,kBAC7C,GAAI,CAAC,EAAmB,OACxB,IAAM,EAAO,EAAkB,cAAc,IAAI,EAAA,YAAY,OAAO,GAAG,KAAK,QAAQ,MAAM,EAAE,EACxF,EACA,KAAK,UAAU,MAAQ,EAAoB,EAAmB,CAAI,EAElE,KAAK,UAAU,MAAQ,IAAA,EAE/B,CAGA,OAAc,CACV,KAAK,eAAe,MAAQ,IAAA,GAC5B,KAAK,UAAU,MAAQ,IAAA,GACvB,KAAK,QAAQ,MAAQ,IAAA,GACrB,KAAK,UAAU,MAAQ,IAAA,EAC3B,CACJ,ECtFM,EAAN,cAAwB,EAAY,CACpC,ECAM,GAAiB,IAGjB,GAAkB,IAMlB,GAAN,KAAmB,CAEf,cAEA,WAAA,EAA4D,EAAA,gBAAA,CAAsC,CAAC,CAAC,EAEpG,WAAA,EAA4D,EAAA,gBAAA,CAAsC,CAAC,CAAC,EAEpG,gBAA4B,EAE5B,YAAY,EAA8B,CACtC,KAAK,cAAgB,CACzB,CAGA,IAAI,SAAmB,CACnB,OAAO,KAAK,UAAU,OAAS,CACnC,CAGA,IAAI,SAAmB,CACnB,OAAO,KAAK,UAAU,OAAS,CACnC,CAGA,IAAI,MAAe,CACf,OAAO,KAAK,UAAU,MAC1B,CAMA,QAAQ,EAAiC,CACrC,GAAI,CAAC,EAAQ,QAAQ,EAAG,MAAO,GAE/B,IAAM,EAAM,KAAK,UAAU,KAAK,UAAU,OAAS,GAiBnD,OAhBI,GAAK,UAAY,KAAK,IAAI,EAAI,KAAK,iBAAmB,IAAmB,EAAI,SAAS,CAAO,GAE7F,KAAK,UAAU,OAAS,EACxB,KAAK,gBAAkB,KAAK,IAAI,EAChC,KAAK,qBAAqB,UAAW,CAAO,EAC5C,KAAK,kBAAkB,EAChB,KAEX,KAAK,UAAU,KAAK,CAAO,EAE3B,KAAK,UAAU,OAAS,EAEpB,KAAK,UAAU,OAAS,IAAgB,KAAK,UAAU,OAAO,EAAG,KAAK,UAAU,OAAS,EAAc,EAC3G,KAAK,gBAAkB,KAAK,IAAI,EAChC,KAAK,qBAAqB,UAAW,CAAO,EAC5C,KAAK,kBAAkB,EAChB,GACX,CAGA,MAAkC,CAC9B,IAAM,EAAU,KAAK,UAAU,KAAK,UAAU,OAAS,GAClD,MACA,EAAQ,KAAK,EAKlB,OAJA,KAAK,UAAU,IAAI,EACnB,KAAK,UAAU,KAAK,CAAO,EAC3B,KAAK,qBAAqB,OAAQ,CAAO,EACzC,KAAK,kBAAkB,EAChB,CACX,CAGA,MAAkC,CAC9B,IAAM,EAAU,KAAK,UAAU,KAAK,UAAU,OAAS,GAClD,MACA,EAAQ,KAAK,EAKlB,OAJA,KAAK,UAAU,IAAI,EACnB,KAAK,UAAU,KAAK,CAAO,EAC3B,KAAK,qBAAqB,OAAQ,CAAO,EACzC,KAAK,kBAAkB,EAChB,CACX,CAOA,mBAAoC,CAChC,KAAK,cAAc,iBAAiB,kBAAkB,CAC1D,CAGA,OAAc,CACV,KAAK,UAAU,OAAS,EACxB,KAAK,UAAU,OAAS,CAC5B,CAGA,qBAA+B,EAAgC,EAA8B,CACzF,KAAK,cAAc,eAAe,SAAS,SAAS,IAAI,GAAa,CACjE,OACA,KAAM,EAAQ,KACd,KAAM,KAAK,cAAc,eAAe,kBAC5C,CAAC,CAAC,CACN,CACJ,EC/GM,GAAN,KAAuB,CAEnB,cAEA,eAAA,EAAuE,EAAA,IAAA,CAAmC,CAAC,CAAC,EAE5G,eAAA,EAAgD,EAAA,IAAA,CAAY,CAAC,EAE7D,YAAY,EAA8B,CACtC,KAAK,cAAgB,CACzB,CAGA,mBAA6B,EAAqD,CAC9E,GAAI,CAAC,EAAM,MAAO,CAAC,EACnB,IAAM,EAA8C,CAChD,MAAO,CAAC,EACR,MAAO,CAAC,KAAM,KAAM,KAAM,KAAM,OAAO,EACvC,SAAU,CAAC,CACf,EAWA,OADI,EAAK,OAAO,OAAO,EAAa,MAAM,KAAK,IAT3B,GAA+B,CAC/C,IAAM,EAAyB,CAAC,EAChC,IAAK,IAAM,KAAS,EACZ,EAAM,SAAW,IACjB,EAAQ,KAAK,EAAM,KAAK,EAGhC,OAAO,CACX,EACkD,CAAW,EAAK,OAAO,MAAM,MAAM,CAAC,EAC/E,CACX,CAGA,IAAI,cAA8C,CAC9C,OAAO,KAAK,cAAc,KAC9B,CAEA,IAAI,aAAa,EAAsC,CACnD,KAAK,cAAc,MAAQ,CAC/B,CAGA,oBAA2B,CACvB,KAAK,cAAc,MAAQ,KAAK,mBAAmB,KAAK,cAAc,qBAAqB,CAC/F,CAGA,IAAI,cAAuB,CACvB,OAAO,KAAK,cAAc,KAC9B,CAOA,mBAA0B,CACtB,KAAK,cAAc,OACvB,CACJ,ECtDM,GAAN,KAAoB,CAEhB,eAEA,oBAAA,EAA+D,EAAA,IAAA,CAAgC,EAE/F,wBAAA,EAAkE,EAAA,IAAA,CAA+B,EAEjG,MAEA,aAEA,iBAEA,YAAA,EAAyD,EAAA,gBAAA,CAAkC,CAAC,CAAC,EAE7F,YAAA,EAAoE,EAAA,SAAA,KAAsC,KAAK,WAAW,EAAE,EAE5H,kBAAA,EAA4D,EAAA,SAAA,KAAwB,KAAK,WAAW,OAAS,CAAC,EAE9G,kBAAA,EAA4D,EAAA,SAAA,KAAwB,KAAK,WAAW,SAAW,CAAC,EAEhH,cAAA,EAAmE,EAAA,SAAA,KAAmC,CAClG,IAAM,EAA4B,CAAC,EAC7B,EAAgB,KAAK,cAC3B,GAAI,EACA,IAAK,IAAM,KAAa,KAAK,WAAY,CACrC,IAAM,EAAS,EAAU,OACzB,GAAI,CAAC,EAAQ,SACb,IAAM,EAAO,EAAc,cAAc,QAAQ,GAC7C,GAAM,EAAM,MAAA,EAAK,EAAA,QAAA,CAAQ,CAAI,CAAC,CACtC,CAEJ,OAAO,CACX,CAAC,EAED,aAAA,EAAuE,EAAA,SAAA,KAAwC,CAC3G,IAAM,EAAgB,KAAK,cAE3B,GADI,CAAC,GACD,KAAK,WAAW,QAAU,EAAG,OACjC,IAAM,EAAS,KAAK,WAAW,EAAE,CAAC,OAC7B,KACL,OAAO,EAAc,cAAc,QAAQ,EAC/C,CAAC,EAED,wBAAA,EAAoF,EAAA,SAAA,KAA0C,KAAK,wBAAwB,CAAC,EAE5J,YAAY,EAAgC,CACxC,KAAK,eAAiB,EACtB,KAAK,MAAQ,IAAI,GAAY,IAAI,EACjC,KAAK,aAAe,IAAI,GAAa,IAAI,EACzC,KAAK,iBAAmB,IAAI,GAAiB,IAAI,CACrD,CAKA,yBAA+D,CAC3D,GAAI,KAAK,WAAW,QAAU,EAAG,OACjC,GAAI,KAAK,WAAW,SAAW,EAAG,OAAO,KAAK,WAAW,EAAE,CAAC,cAC5D,IAAI,EACE,EAAQ,IAAI,IAClB,IAAK,IAAM,KAAa,KAAK,WACpB,KAAU,gBACf,EAAgB,EAAU,cAC1B,EAAM,IAAI,EAAc,IAAI,EACxB,EAAM,KAAO,GAAG,OAExB,OAAO,CACX,CAGA,IAAI,mBAAgD,CAChD,OAAO,KAAK,oBAAoB,KACpC,CAGA,IAAI,kBAAkB,EAAmC,CACrD,KAAK,mBAAmB,MAAQ,CACpC,CAGA,IAAI,uBAAmD,CACnD,OAAO,KAAK,wBAAwB,KACxC,CAGA,IAAI,sBAAsB,EAAkC,CACxD,KAAK,uBAAuB,MAAQ,CACxC,CAGA,IAAI,eAA2C,CAC3C,OAAO,KAAK,wBAAwB,KACxC,CAGA,IAAI,WAAmC,CACnC,OAAO,KAAK,WAAW,KAC3B,CAGA,IAAI,iBAA2B,CAC3B,OAAO,KAAK,iBAAiB,KACjC,CAGA,IAAI,iBAA2B,CAC3B,OAAO,KAAK,iBAAiB,KACjC,CAGA,IAAI,aAAkC,CAClC,OAAO,KAAK,aAAa,KAC7B,CAGA,IAAI,YAAsC,CACtC,OAAO,KAAK,YAAY,KAC5B,CAGA,IAAI,uBAAmD,CACnD,OAAO,KAAK,uBAAuB,KACvC,CAGA,iBAAwB,CACpB,KAAK,WAAW,OAAS,CAC7B,CAOA,gBAAgB,EAA8B,EAC1C,EAAA,EAAA,SAAA,KAAe,CACX,IAAM,EAAgB,KAAK,cACtB,KACL,MAAK,WAAW,OAAS,EACzB,IAAK,IAAM,KAAU,EAAS,CAC1B,IAAM,EAAO,EAAc,cAAc,QAAQ,GACjD,GAAI,CAAC,EAAM,SACX,IAAM,EAAY,IAAI,EAAU,IAAI,EACpC,EAAU,OAAS,EAAK,GAExB,EAAU,SADK,EAAc,cAAc,WAAW,EACjC,EAAQ,GAC7B,EAAU,cAAgB,KAAK,eAAe,gBAAgB,iBAAiB,EAAK,IAAI,EACxF,IAAM,EAAY,KAAK,kBACjB,EAAU,GAAW,cAAc,IAAI,EAAA,YAAY,OAAO,GAAG,EAAO,EAAE,EACxE,GAAa,IACb,EAAU,SAAW,EAAoB,EAAW,CAAO,GAE/D,KAAK,WAAW,KAAK,CAAS,CAClC,CAfyB,CAgB7B,CAAC,CACL,CACJ,EClJM,GAAoC,CACtC,gBAAiB,IAAI,EAAA,mBACrB,QAAS,CAAC,EACV,QAAS,CAAC,EACV,gBAAiB,mBACrB,EAaM,GAAN,KAAqB,CAEjB,SAA8B,IAAI,GAElC,MAEA,QAAoD,CAAC,EAErD,QAAoD,CAAC,EAErD,OAA0B,IAAI,GAE9B,iBAA8C,IAAI,GAElD,UAAgC,IAAI,GAEpC,kBAAA,EAA4E,EAAA,gBAAA,CAA+C,CAAC,CAAC,EAE7H,qBAAA,EAAkE,EAAA,IAAA,CAAwB,EAE1F,kBAAA,EAAoD,EAAA,IAAA,CAAa,EAAK,EAEtE,mBAAA,EAAqD,EAAA,IAAA,CAAa,EAAK,EAEvE,QAA6B,GAE7B,YAAY,EAAsC,CAAC,EAAG,CAClD,KAAK,MAAQ,CAAE,GAAG,GAAc,GAAG,CAAM,CAC7C,CAGA,IAAI,iBAAmC,CACnC,OAAO,KAAK,MAAM,eACtB,CAGA,IAAI,WAAqB,CACrB,OAAO,KAAK,OAChB,CAGA,IAAI,oBAAyC,CACzC,OAAO,KAAK,oBAAoB,KACpC,CAEA,IAAI,mBAAmB,EAA2B,CAE1C,GAAS,CAAC,KAAK,iBAAiB,KAAQ,EAAQ,IAAA,IACpD,KAAK,oBAAoB,MAAQ,CACrC,CAGA,IAAI,qBAAiD,CACjD,IAAM,EAAqB,KAAK,mBAC3B,KACL,OAAO,KAAK,iBAAiB,EACjC,CAMA,iBAAiB,EAAiC,CAC9C,IAAI,EAAgB,KAAK,iBAAiB,GAK1C,OAJK,IACD,EAAgB,IAAI,GAAc,IAAI,EACtC,KAAK,iBAAiB,GAAY,GAE/B,CACX,CAMA,iBAAiB,EAA6C,CAC1D,IAAM,EAAgB,KAAK,iBAAiB,GAG5C,OAFA,OAAO,KAAK,iBAAiB,GACzB,KAAK,qBAAuB,IAAU,KAAK,mBAAqB,IAAA,IAC7D,CACX,CAGA,IAAI,iBAA2B,CAC3B,OAAO,KAAK,iBAAiB,KACjC,CAEA,IAAI,gBAAgB,EAAgB,CAChC,KAAK,iBAAiB,MAAQ,CAClC,CAGA,IAAI,kBAA4B,CAC5B,OAAO,KAAK,kBAAkB,KAClC,CAEA,IAAI,iBAAiB,EAAgB,CACjC,KAAK,kBAAkB,MAAQ,CACnC,CAOA,MAAM,EAA4B,SAAU,EAAiB,WAAuC,CAEhG,KAAK,QAAQ,EAEb,IAAM,EAAU,KAAK,MAAM,QAAQ,IAAI,GAAU,IAAI,EAAO,KAAM,EAAW,CAAM,CAAC,EAC9E,EAAU,KAAK,MAAM,QAAQ,IAAI,GAAU,IAAI,EAAO,KAAM,EAAW,CAAM,CAAC,EACpF,KAAK,QAAQ,KAAK,GAAG,CAAO,EAC5B,KAAK,QAAQ,KAAK,GAAG,CAAO,EAE5B,KAAK,QAAQ,QAAQ,GAAU,EAAO,OAAO,CAAC,EAE9C,KAAK,QAAQ,QAAQ,GAAU,EAAO,OAAO,CAAC,EAC9C,KAAK,QAAU,GAEf,IAAM,EAA6B,CAAE,YAAW,SAAQ,UAAW,KAAK,IAAI,CAAE,EAC9E,KAAK,SAAS,SAAS,IAAI,EAAiB,CAAI,CAAC,CACrD,CAGA,SAAgB,CACZ,GAAI,CAAC,KAAK,QAAS,OAEnB,IAAM,EAA+B,CAAE,UAAW,KAAK,IAAI,CAAE,EAC7D,KAAK,SAAS,SAAS,IAAI,EAAmB,CAAI,CAAC,EAEnD,KAAK,QAAQ,QAAQ,GAAU,EAAO,OAAO,CAAC,EAE9C,KAAK,QAAQ,QAAQ,GAAU,EAAO,QAAQ,CAAC,EAE/C,KAAK,SAAS,kBAAkB,EAEhC,KAAK,QAAQ,OAAS,EACtB,KAAK,QAAQ,OAAS,EACtB,KAAK,QAAU,EACnB,CACJ,EC9JM,GAAN,cAA6B,CAAe,CACxC,UAAwC,KAAK,cAAc,EAE3D,eAAqD,IAAI,IAEzD,eAAqC,CACjC,MAAO,CACH,SAAU,GACV,cAAe,IAAA,GACf,WAAY,IAAA,GACZ,UAAW,IAAA,EACf,CACJ,CAEA,QAAe,CAEX,KAAK,iBAAiB,YAAa,KAAK,YAAa,EAAI,CAC7D,CAEA,QAAe,CAEX,KAAK,oBAAoB,YAAa,KAAK,YAAa,EAAI,EAC5D,KAAK,oBAAoB,UAAW,KAAK,SAAS,EAClD,KAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,oBAAoB,YAAa,KAAK,gBAAgB,EAC3D,KAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,oBAAoB,UAAW,KAAK,SAAS,EAClD,KAAK,oBAAoB,WAAY,KAAK,WAAW,EACrD,KAAK,oBAAoB,cAAe,KAAK,eAAgB,EAAI,EAEjE,KAAK,UAAU,SAAW,GAC1B,KAAK,eAAe,MAAM,CAC9B,CAKA,YAAe,GAA4B,CAEvC,GAAI,EAAM,SAAW,GAAK,EAAM,SAAW,EAAM,QAAS,OAC1D,IAAM,EAAS,EAAM,OACrB,GAAI,CAAC,GAAQ,QAAS,OACtB,KAAK,eAAe,MAAM,EAE1B,IAAM,EAAkB,EAAO,QAAQ,EAAA,YAAY,EAC7C,EAAe,EAAA,eAAe,cAAc,EAAiB,KAAK,eAAe,EACvF,GAAI,EACA,KAAK,eAAe,IAAI,EAAA,YAAa,CAAY,MAC9C,CAEH,IAAI,EAAU,EAAO,QAAQ,IAAI,EAAA,YAAY,cAAc,EAAE,EACzD,GAAW,EAAQ,eAAiB,EAAA,eAAe,gBAAgB,CAAO,IAE1E,EAAU,EAAQ,cAAc,QAAQ,IAAI,EAAA,YAAY,cAAc,EAAE,GAE5E,IAAM,EAAS,EAAA,eAAe,OAAO,CAAO,EACtC,EAAgB,EAAA,eAAe,cAAc,EAAS,KAAK,eAAe,EAChF,GAAI,GAAU,EAAe,CAEzB,IAAM,EAAa,KAAK,eAAe,qBAAqB,WACxD,GAAc,EAAW,KAAK,GAAa,IAAW,EAAU,MAAM,EACtE,EAAW,QAAQ,GAAa,CACxB,EAAU,QAAU,EAAU,eAC9B,KAAK,eAAe,IAAI,EAAU,OAAQ,EAAU,aAAa,CAEzE,CAAC,EAGD,KAAK,eAAe,IAAI,EAAQ,CAAa,CAErD,CACJ,CACI,KAAK,eAAe,MAAQ,IAEhC,KAAK,UAAU,WAAa,EAC5B,KAAK,UAAU,SAAW,GAC1B,KAAK,UAAU,cAAgB,KAAK,IAAI,EAExC,KAAK,oBAAoB,UAAW,KAAK,SAAS,EAClD,KAAK,iBAAiB,UAAW,KAAK,SAAS,EAC/C,KAAK,oBAAoB,YAAa,KAAK,gBAAgB,EAC3D,KAAK,iBAAiB,YAAa,KAAK,gBAAgB,EAExD,KAAK,oBAAoB,UAAW,KAAK,SAAS,EAClD,KAAK,iBAAiB,UAAW,KAAK,SAAS,EAC/C,KAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,iBAAiB,YAAa,KAAK,WAAW,EACvD,EAKA,UAAa,GAA4B,CAEjC,KAAK,UAAU,UACf,KAAK,SAAS,SAAS,IAAI,EAAc,CAAK,CAAC,EAGnD,KAAK,oBAAoB,UAAW,KAAK,SAAS,EAClD,KAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,oBAAoB,YAAa,KAAK,gBAAgB,EAC3D,KAAK,oBAAoB,WAAY,KAAK,WAAW,EACrD,KAAK,oBAAoB,UAAW,KAAK,SAAS,EAClD,KAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,oBAAoB,cAAe,KAAK,eAAgB,EAAI,EAEjE,KAAK,UAAU,SAAW,EAC9B,EAMA,iBAAoB,GAA4B,CAC5C,IAAM,EAAgB,KAAK,UAAU,cAC/B,EAAa,KAAK,UAAU,WAElC,GAAI,EAAA,OAAO,QAAQ,CAAa,GAAK,EAAA,OAAO,QAAQ,CAAU,EAAG,OAEjE,IAAM,EAAW,EAAa,EAAM,MAAO,EAAM,MAAO,EAAW,MAAO,EAAW,KAAK,EACpF,EAAY,KAAK,IAAI,EAAI,EAE3B,IAAU,GAAc,EAAY,IAAM,EAAW,IAErD,KAAK,oBAAoB,YAAa,KAAK,gBAAgB,EAE3D,KAAK,YAAY,CAAK,EAE9B,EAKA,YAAe,GAAwC,CAE/C,KAAK,UAAU,WAEnB,KAAK,UAAU,WAAa,KAAK,UAAU,YAAe,EAE1D,KAAK,oBAAoB,cAAe,KAAK,eAAgB,EAAI,EACjE,KAAK,iBAAiB,cAAe,KAAK,eAAgB,EAAI,EAE9D,KAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,iBAAiB,YAAa,KAAK,WAAW,EAEnD,KAAK,oBAAoB,WAAY,KAAK,WAAW,EACrD,KAAK,iBAAiB,WAAY,KAAK,WAAW,EAElD,KAAK,SAAS,SAAS,IAAI,EAAe,KAAK,UAAU,WAAY,KAAK,cAAc,CAAC,EACzF,KAAK,UAAU,SAAW,GAC9B,EAKA,YAAe,GAAwC,EAE/C,EAAM,UAAY,KAAK,UAAU,WAAW,SAAW,EAAM,UAAY,KAAK,UAAU,WAAW,WAIvG,KAAK,SAAS,SAAS,IAAI,EAAc,CAAmB,CAAC,EAE7D,KAAK,UAAU,UAAY,EAC/B,CACJ,ECvLM,GAAN,cAA6B,CAAe,CAExC,YAA8C,IAAI,IAElD,QAAe,CACX,KAAK,iBAAiB,UAAW,KAAK,UAAU,EAChD,KAAK,iBAAiB,QAAS,KAAK,UAAU,EAG9C,KAAK,OAAO,iBAAiB,OAAQ,KAAK,MAAM,CACpD,CAEA,QAAe,CACX,KAAK,oBAAoB,UAAW,KAAK,UAAU,EACnD,KAAK,oBAAoB,QAAS,KAAK,UAAU,EACjD,KAAK,OAAO,oBAAoB,OAAQ,KAAK,MAAM,EAEnD,KAAK,cAAc,CACvB,CAGA,WAAqB,CACjB,KAAK,cAAc,CACvB,EAGA,eAAgC,CAC5B,KAAK,YAAY,MAAM,EACvB,KAAK,eAAe,gBAAkB,GACtC,KAAK,eAAe,iBAAmB,EAC3C,CAEA,WAAc,GAA+B,CACzC,IAAM,EAAM,EAAM,IAAI,YAAY,EAE9B,EAAM,OAAS,UACf,KAAK,YAAY,IAAI,CAAG,EAExB,KAAK,YAAY,OAAO,CAAG,EAG/B,KAAK,eAAe,gBAAkB,KAAK,YAAY,OAAS,GAAK,KAAK,YAAY,IAAI,SAAS,EACnG,KAAK,eAAe,iBAAmB,KAAK,YAAY,OAAS,GAAK,KAAK,YAAY,IAAI,OAAO,EAElG,KAAK,SAAS,SAAS,IAAI,GAAiB,EAAO,KAAK,WAAW,CAAC,CACxE,CACJ,EC5CM,GAAN,cAA+B,CAAe,CAC1C,QAAe,CACX,KAAK,iBAAiB,QAAS,KAAK,YAAY,EAChD,KAAK,iBAAiB,WAAY,KAAK,kBAAkB,CAC7D,CAEA,QAAe,CACX,KAAK,oBAAoB,QAAS,KAAK,YAAY,EACnD,KAAK,oBAAoB,WAAY,KAAK,kBAAkB,CAChE,CAEA,aAAgB,GAA4B,CACxC,IAAM,EAAS,EAAM,OAChB,GAAQ,SAEG,EAAO,QAAQ,KAAK,eAAe,MAAM,eACpD,GACL,KAAK,SAAS,SAAS,IAAI,GAAgB,CAAK,CAAC,CACrD,EAEA,mBAAsB,GAA4B,CAC9C,IAAM,EAAS,EAAM,OAChB,GAAQ,SAEG,EAAO,QAAQ,KAAK,eAAe,MAAM,eACpD,GACL,KAAK,SAAS,SAAS,IAAI,GAAsB,CAAK,CAAC,CAC3D,CACJ,EC9BM,GAAN,cAA8B,CAAe,CACzC,QAA2B,IAAA,GAE3B,QAAe,CACX,KAAK,iBAAiB,YAAa,KAAK,WAAW,CACvD,CAEA,QAAe,CACX,KAAK,oBAAoB,YAAa,KAAK,WAAW,EACtD,KAAK,cAAc,CACvB,CAEA,YAAe,GAA4B,CAEvC,KAAK,cAAc,EACnB,KAAK,QAAU,0BAA4B,CACvC,KAAK,QAAU,IAAA,GACf,KAAK,SAAS,SAAS,IAAI,EAAe,CAAK,CAAC,CACpD,CAAC,CACL,EAEA,eAAgC,CACxB,KAAK,UAAY,IAAA,KACjB,qBAAqB,KAAK,OAAO,EACjC,KAAK,QAAU,IAAA,GAEvB,CACJ,ECtBM,GAAN,cAA2B,CAAe,CAEtC,eAAiC,GAEjC,aAAmD,CAAC,EAEpD,UAA2B,CACvB,KAAK,eAAe,EACpB,KAAK,gBAAgB,CACzB,CAEA,WAA4B,CACxB,KAAK,aAAa,QAAQ,GAAe,EAAY,CAAC,EACtD,KAAK,aAAa,OAAS,EAE3B,AAEI,KAAK,kBADL,KAAK,wBAAwB,KAAK,cAAc,EAC1B,GAE9B,CAMA,iBAA2B,EAA2B,CAClD,MAAO,CACH,QAAS,GAAM,SAAW,EAC1B,QAAS,GAAM,SAAW,EAC1B,MAAO,GAAM,OAAS,EACtB,MAAO,GAAM,OAAS,EACtB,WAAY,GAAM,YAAc,EAChC,WAAY,GAAM,YAAc,EAChC,SAAU,GAAM,UAAY,EAC5B,SAAU,GAAM,UAAY,CAChC,CACJ,CAKA,gBAAiC,CAE7B,KAAK,aAAa,KACd,KAAK,SAAS,UAAU,EAAgB,GAAS,CAC7C,KAAK,eAAiB,KAAK,wBAAwB,EACnD,IAAM,EAAS,KAAK,eAAe,OACnC,EAAO,OAAS,EAAa,UAC7B,EAAO,kBAAoB,KAAK,iBAAiB,EAAM,IAAI,CAC/D,CAAC,EAED,KAAK,SAAS,UAAU,EAAe,GAAS,CAC5C,IAAM,EAAS,KAAK,eAAe,OACnC,EAAO,OAAS,EAAa,SAC7B,EAAO,SAAW,KAAK,iBAAiB,EAAM,IAAI,EAClD,EAAA,YAAY,gBAAkB,CAC1B,KAAK,wBAAwB,MAAM,CACvC,CAAC,CACL,CAAC,EAED,KAAK,SAAS,UAAU,EAAe,GAAS,CAC5C,IAAM,EAAS,KAAK,eAAe,OACnC,EAAO,OAAS,EAAa,SAC7B,EAAO,gBAAkB,KAAK,iBAAiB,EAAM,IAAI,EACzD,EAAO,kBAAoB,IAAA,GAC3B,EAAO,OAAS,EAAa,OAC7B,EAAA,YAAY,gBAAkB,KAAK,wBAAwB,KAAK,cAAc,CAAC,CACnF,CAAC,CACL,CACJ,CAKA,iBAAkC,CAE9B,KAAK,aAAa,KACd,KAAK,SAAS,UAAU,EAAgB,GAAS,CAC7C,IAAM,EAAS,KAAK,eAAe,OAC9B,CAAC,EAAa,SAAU,EAAa,SAAS,CAAC,CAAC,SAAS,EAAO,MAAM,IACvE,EAAO,OAAS,EAAa,QAE7B,EAAO,SAAW,EAAa,WACnC,EAAO,SAAW,KAAK,iBAAiB,EAAM,IAAI,EACtD,CAAC,CACL,CACJ,CACJ,ECtFM,GAAN,cAA6B,CAAe,CAExC,aAAmD,CAAC,EAEpD,UAA2B,CACvB,KAAK,uBAAuB,CAChC,CAEA,WAA4B,CACxB,KAAK,aAAa,QAAQ,GAAe,EAAY,CAAC,EACtD,KAAK,aAAa,OAAS,EAC3B,KAAK,eAAe,iBAAiB,MAAM,CAC/C,CAKA,wBAAyC,CACrC,KAAK,aAAa,KAEd,KAAK,SAAS,UAAU,EAAgB,GAAS,CAC7C,IAAM,EAAiB,EAAM,MAAM,eACnC,GAAI,CAAC,GAAkB,EAAe,MAAQ,EAAG,OACjD,IAAM,EAAmB,KAAK,eAAe,iBACvC,EAAiC,CAAC,EAClC,EAAyB,CAAC,EAC1B,EAAoC,CAAC,EACrC,EAAoB,KAAK,eAAe,qBAAqB,kBACnE,EAAe,SAAS,EAAM,IAAW,CAIrC,GAHA,EAAS,KAAK,CAAI,EAClB,EAAQ,KAAK,CAAM,EAEf,EAAmB,CACnB,IAAM,EAAU,EAAkB,cAAc,IAAI,EAAA,YAAY,OAAO,GAAG,EAAO,EAAE,EAC/E,GAAS,EAAU,KAAK,EAAoB,EAAmB,CAAO,CAAC,CAC/E,CACJ,CAAC,EACD,EAAiB,SAAW,EAC5B,EAAiB,QAAU,EAC3B,EAAiB,UAAY,CACjC,EAAG,GAAG,EAGN,KAAK,SAAS,UAAU,EAAe,GAAS,CAC5C,IAAM,EAAmB,KAAK,eAAe,iBACxC,EAAiB,gBAEtB,KAAK,SAAS,SAAS,IAAI,GAAc,CACrC,eAAgB,CAAC,GAAG,EAAiB,QAAQ,EAC7C,QAAS,CAAC,GAAG,EAAiB,OAAO,EACrC,OAAQ,EAAM,KAEd,UAAW,EAAiB,SAChC,CAAC,CAAC,EAEF,EAAiB,MAAM,EAC3B,EAAG,GAAG,CACV,CACJ,CACJ,EC9DA,SAAS,GAAY,EAAwB,EAA8B,EAAkB,EAA2B,CACpH,GAAI,CAAC,EAAQ,eAAgB,MAAO,GACpC,IAAM,EAAa,EAAc,KAC3B,CACF,YACA,YACA,WACA,EAAQ,eAgBZ,MALA,EAVI,EAAA,OAAO,SAAS,CAAS,GACrB,CAAC,EAAU,SAAS,CAAU,GAIlC,EAAA,OAAO,SAAS,CAAS,GACrB,EAAU,SAAS,CAAU,GAIjC,EAAA,OAAO,WAAW,CAAO,GACrB,CAAC,EAAQ,EAAS,EAAe,EAAU,CAAO,EAK9D,CCTA,IAAM,GAAN,cAA4B,CAAe,CAEvC,mBAAsC,GAEtC,gBAEA,kBAA4B,EAE5B,sBAAgC,EAEhC,aAAmD,CAAC,EAEpD,UAA2B,CACvB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,CACzB,CAEA,WAA4B,CACxB,KAAK,aAAa,QAAQ,GAAe,EAAY,CAAC,EACtD,KAAK,aAAa,OAAS,EAC3B,KAAK,gBAAkB,IAAA,EAC3B,CAGA,mBAA6B,EAA8B,EAAmD,CAC1G,GAAI,CAAC,GAAQ,QAAS,OACtB,IAAI,EAAqC,EAAc,kBAEvD,GADA,AAAgB,IAAY,EAAO,QAAQ,KAAK,eAAe,MAAM,eAAe,EAChF,CAAC,EAAW,OAEhB,IAAM,EAAU,EAAO,QAAQ,IAAI,EAAA,YAAY,QAAQ,SAAS,EAAA,YAAY,gBAAgB,GAAG,EAC1F,KACL,MAAO,CAAE,KAAM,EAAS,SAAU,CAAU,CAChD,CAGA,oBAA8B,EAAwC,CAElE,OADI,EAAS,QAAgB,GACtB,KAAK,IAAI,EAAS,IAAK,EAAS,MAAM,CACjD,CAGA,sBAAgC,EAAwC,CAEpE,OADI,EAAS,QAAgB,GACtB,KAAK,IAAI,EAAS,KAAM,EAAS,KAAK,CACjD,CAKA,aAAuB,EAA8B,EAAqB,EAAgC,EAAsB,GAAU,CACtI,IAAI,EAAoC,EAAc,mBAAqB,KAE3E,GADA,AAAwB,IAAoB,EAAS,QAAQ,QAAQ,KAAK,eAAe,MAAM,eAAe,EAC1G,CAAC,EAAmB,OACxB,KAAK,eAAe,UAAU,MAAM,EACpC,IAAM,EAAgB,EAAA,QAAO,KAAK,CAAW,CAAC,CAAC,OAAS,EACpD,EACA,EAUJ,GATI,GAEA,EAAS,EACT,EAAW,IAEX,EAAS,EAAA,eAAe,OAAO,EAAS,OAAO,EAC/C,EAAW,EAAA,eAAe,SAAS,EAAS,OAAO,GAGnD,KAAK,mBAAmB,EAAQ,KAAK,eAAe,iBAAiB,OAAO,EAC5E,OAEJ,IAAM,EAAY,EAAS,QAAQ,QAAQ,IAAI,EAAA,YAAY,OAAO,GAAG,EAAY,EAAE,EACnF,GAAI,CAAC,EACD,OAEJ,IAAM,EAAgB,EAAA,eAAe,cAAc,EAAW,KAAK,eAAe,EAC7E,IAIY,KAAK,eAAe,iBAAiB,SACxB,KAAK,GAAW,CAAC,GAAY,EAAS,EAAe,EAAU,CAAS,CAClG,IAEJ,KAAK,eAAe,UAAU,UAAY,GAC1C,KAAK,eAAe,UAAU,SAAW,EACzC,KAAK,eAAe,UAAU,SAAW,EAAoB,EAAmB,EAAS,OAAO,EAChG,KAAK,eAAe,UAAU,OAAS,EACvC,KAAK,eAAe,UAAU,YAAc,EAC5C,KAAK,eAAe,UAAU,SAAW,EACzC,KAAK,eAAe,UAAU,YAAc,GAChD,CAGA,mBAA6B,EAAgB,EAA6B,CACtE,GAAI,EAAI,SAAS,CAAM,EAAG,MAAO,GACjC,IAAM,EAAgB,KAAK,eAAe,qBAAqB,cAC/D,GAAI,EAAe,CACf,IAAM,EAAsB,IAAI,IAChC,IAAK,IAAM,KAAM,EAAK,CAClB,IAAM,EAAc,EAAc,cAAc,QAAQ,GACnD,IACL,EAAA,EAAA,wBAAA,CAAwB,EAAa,GAAW,EAAO,IAAI,EAAQ,EAAE,CAAC,CAC1E,CACA,OAAO,EAAO,IAAI,CAAM,CAC5B,CACA,MAAO,EACX,CAKA,mBAAoC,CAChC,KAAK,aAAa,KACd,KAAK,SAAS,UAAU,EAAgB,GAAS,CAC7C,IAAM,EAAM,KAAK,IAAI,EAErB,GAAI,EAAM,KAAM,SAAW,KAAK,gBAAiB,CAC7C,KAAK,kBAAoB,EACzB,MACJ,CACiB,EAAM,KAAK,kBACb,KAAK,qBACpB,KAAK,kBAAoB,EAEzB,EAAA,YAAY,gBAAkB,CAC1B,IAAM,EAAgB,KAAK,eAAe,oBAC1C,GAAI,CAAC,EAAe,OACpB,IAAM,EAAQ,EAAc,MACtB,EAAS,EAAM,KAAM,OACrB,EAAkB,KAAK,mBAAmB,EAAe,CAAM,EACrE,GAAI,CAAC,EAAiB,OACtB,IAAM,EAAS,EAAA,eAAe,OAAO,EAAgB,IAAI,EAEzD,GAAI,EAAc,WAAW,KAAK,GAAQ,EAAK,SAAW,CAAM,EAAG,CAC/D,EAAM,MAAM,EACZ,MACJ,CACA,EAAM,cAAgB,EAAA,eAAe,cAAc,EAAgB,KAAM,KAAK,eAAe,EAC7F,EAAM,OAAS,EACf,EAAM,SAAW,EAAoB,EAAgB,SAAU,EAAgB,IAAI,EACnF,KAAK,gBAAkB,EAAM,KAAM,MACvC,CAAC,EACL,CAAC,CACL,CACJ,CAKA,iBAAkC,CAC9B,KAAK,aAAa,KACd,KAAK,SAAS,UAAU,GAAiB,GAAS,CAE9C,GAAI,KAAK,IAAI,EAAI,KAAK,uBAAyB,GAAI,OACnD,IAAM,EAAgB,KAAK,eAAe,oBAC1C,GAAI,CAAC,EAAe,OACpB,IAAM,EAAS,EAAM,KAAM,OACrB,EAAkB,KAAK,mBAAmB,EAAe,CAAM,EACrE,GAAI,CAAC,EAAiB,OACtB,IAAM,EAAQ,EAAc,MACtB,EAAa,EAAc,WAC3B,EAAY,IAAI,EAAU,CAAa,EAC7C,EAAU,OAAS,EAAA,eAAe,OAAO,EAAgB,IAAI,EAC7D,EAAU,SAAW,EAAA,eAAe,aAAa,EAAgB,IAAI,EACjE,GAAW,KAAK,GAAQ,EAAK,SAAW,EAAU,MAAM,IAC5D,EAAU,cAAgB,EAAA,eAAe,cAAc,EAAgB,KAAM,KAAK,eAAe,EACjG,EAAU,SAAW,EAAoB,EAAgB,SAAU,EAAgB,IAAI,EAElF,KAAK,eAAe,kBAAiB,EAAW,OAAS,GAC9D,EAAW,KAAK,CAAS,EACrB,EAAM,QAAU,EAAW,KAAK,GAAQ,EAAK,SAAW,EAAM,MAAM,GACpE,EAAM,MAAM,EAEpB,CAAC,CACL,CACJ,CAKA,iBAAkC,CAC9B,KAAK,aAAa,KAEd,KAAK,SAAS,UAAU,EAAe,GAAS,CAE5C,GAAI,CADqB,KAAK,eAAe,iBACvB,cAAe,OACrC,IAAI,EAAS,EAAM,KAAM,OACpB,GACL,EAAA,YAAY,gBAAkB,CAE1B,GAAI,CAAC,GAAQ,SAAW,CAAC,EAAO,QAAQ,KAAK,eAAe,MAAM,eAAe,EAAG,CAChF,KAAK,eAAe,UAAU,MAAM,EACpC,MACJ,CACA,IAAM,EAAgB,KAAK,eAAe,oBAC1C,GAAI,CAAC,GAAe,kBAAmB,OACvC,IAAM,EAAgB,EAAc,cACpC,GAAI,CAAC,EAAe,OAEpB,IAAM,EAAc,EAAA,eAAe,gBAAgB,CAAM,EACzD,GAAI,EAAa,CACb,IAAM,EAAW,EAAyB,EAAM,KAAO,EAAM,KAAM,MAAiB,EAC9E,EAAe,EAAA,eAAe,aAAa,EAAS,OAAO,EACjE,GAAI,EAAc,CACd,KAAK,aAAa,EAAe,EAAc,EAAU,CAAW,EACpE,MACJ,CACJ,CAEA,IAAI,EAAgC,KAChC,EACJ,OAAa,CAKT,GAJI,CAAC,IACL,EAAgB,EAAO,QAAQ,IAAI,EAAA,YAAY,OAAO,EAAE,EACpD,CAAC,KACL,EAAc,EAAA,eAAe,OAAO,CAAa,EAC7C,CAAC,GAAa,OAClB,IAAM,EAAuC,EAAc,cAAc,QAAQ,GACjF,GAAI,CAAC,EAAa,OAElB,GADoB,GAAkB,EAAY,WAAW,iBACzD,EACA,MAGA,AAGI,EAHA,IAAW,EACF,EAAc,cAEd,CAGrB,CACA,GAAI,CAAC,GAAiB,CAAC,EAAa,OAEpC,GAAI,IAAkB,EAAM,KAAM,OAAQ,CACtC,IAAM,EAAW,EAAyB,EAAM,KAAO,CAAa,EAEpE,GADoB,KAAK,IAAI,EAAS,IAAK,EAAS,OAAQ,EAAS,KAAM,EAAS,KAChF,GAAe,GAAI,CACnB,IAAM,EAAe,EAAA,eAAe,aAAa,EAAS,OAAO,EACjE,GAAI,EAAc,CACd,KAAK,aAAa,EAAe,EAAc,CAAQ,EACvD,MACJ,CACJ,CACJ,CAEA,IAAM,EAAQ,EAAc,iBAAiB,IAAI,EAAA,YAAY,aAAa,GAAG,EAAY,EAAE,EACrF,EAAyC,CAAC,EAEhD,GADA,EAAM,QAAQ,GAAQ,EAAU,KAAK,EAAyB,EAAM,KAAO,CAAI,CAAC,CAAC,EAC7E,EAAU,QAAU,EAAG,OAE3B,IAAM,EAAc,EAAA,QAAO,IAAI,EAAU,IAAI,GAAY,KAAK,oBAAoB,CAAQ,CAAC,CAAC,EACtF,EAAoB,EAAU,OAAO,GAAY,KAAK,oBAAoB,CAAQ,GAAK,CAAW,EAClG,EAAgB,EAAA,QAAO,IAAI,EAAkB,IAAI,GAAY,KAAK,sBAAsB,CAAQ,CAAC,CAAC,EAClG,EAAsB,EAAkB,OAAO,GAAY,KAAK,sBAAsB,CAAQ,GAAK,CAAa,EAEhH,EAAc,EAAA,QAAO,MAAM,EAAqB,GAC9C,EAAS,WAAmB,GAC5B,EAAS,QAAU,EAAe,QAAgB,EAAS,QAC3D,EAAS,QAAU,EAAe,WAAmB,EAAS,WAC9D,EAAS,QAAU,EAAe,SAAiB,EAAS,SAC5D,EAAS,QAAU,EAAe,YAAoB,EAAS,YAC5D,OAAO,SACjB,EAED,KAAK,aAAa,EAAe,EAAa,CAAW,CAC7D,CAAC,CACL,CAAC,EAED,KAAK,SAAS,UAAU,MAAqB,CACzC,KAAK,sBAAwB,KAAK,IAAI,EACtC,IAAM,EAAY,KAAK,eAAe,UAChC,EAAmB,KAAK,eAAe,iBAC7C,EAAiB,UAAY,EAAU,iBAAiB,EACxD,EAAA,YAAY,gBAAkB,EAAU,MAAM,CAAC,CACnD,CAAC,CACL,CACJ,CACJ,ECtRA,SAAS,EAAoB,EAA8B,EAA0C,CAEjG,GAAI,CADS,EAAc,cAAc,QAAQ,GACtC,OACX,IAAM,EAAS,EAAc,cAAc,WAAW,GACtD,GAAI,CAAC,EAAQ,OAEb,IAAM,GAAU,EAAuC,IAA+C,CAClG,IAAM,EAAM,EAAI,UAAU,GAAQ,EAAA,OAAO,MAAM,CAAI,GAAK,CAAC,EAAA,OAAO,QAAQ,CAAI,GAAM,EAAqB,KAAO,CAAM,EAChH,OAAM,GACV,IAAI,EAAM,EAAG,CAET,IAAM,EAAO,EAAI,EAAM,GACvB,GAAI,EAAA,OAAO,MAAM,CAAI,GAAK,CAAC,EAAA,OAAO,QAAQ,CAAI,EAC1C,MAAO,CAAE,SAAU,EAAO,GAAI,WAAU,SAAU,QAAS,WAAa,EAAqB,EAAG,CAExG,CACA,MAAO,CAAE,SAAU,EAAO,GAAI,WAAU,SAAU,OAAQ,CAD1D,CAEJ,EACM,EAAS,EAAO,EAAO,MAAO,EAAA,aAAa,EACjD,GAAI,EAAQ,OAAO,EACnB,IAAK,IAAM,KAAY,EAAO,MAAO,CACjC,IAAM,EAAS,EAAO,EAAO,MAAM,GAAW,CAAQ,EACtD,GAAI,EAAQ,OAAO,CACvB,CAEJ,CAOA,SAAS,GAAgB,EAA8B,EAAwB,CAE3E,GAAI,CADS,EAAc,cAAc,QAAQ,GACtC,MAAO,GAClB,IAAM,EAAS,EAAc,cAAc,WAAW,GACtD,GAAI,CAAC,EAAQ,MAAO,GACpB,IAAM,EAAU,GAAkD,EAAI,UAClE,GAAQ,EAAA,OAAO,MAAM,CAAI,GAAK,CAAC,EAAA,OAAO,QAAQ,CAAI,GAAM,EAAqB,KAAO,CACxF,EACM,EAAM,EAAO,EAAO,KAAK,EAC/B,GAAI,GAAO,EAAG,OAAO,EACrB,IAAK,IAAM,KAAY,EAAO,MAAO,CACjC,IAAM,EAAM,EAAO,EAAO,MAAM,EAAS,EACzC,GAAI,GAAO,EAAG,OAAO,CACzB,CACA,MAAO,EACX,CASA,SAAS,GAAgB,EAA8B,EAA2C,CAC9F,GAAM,CAAE,WAAY,EAAc,cAKlC,OAJK,EAAQ,EAAO,WACf,EAAO,WAAa,UAAY,EAAO,WAAa,UAAY,EAAO,YAAc,CAAC,EAAQ,EAAO,YAC/F,CAAE,SAAU,EAAO,SAAU,SAAU,EAAO,SAAU,SAAU,MAAO,EAE7E,EAJ+B,IAK1C,CAMA,SAAS,GAAe,EAA8B,EAAsB,EAAqC,CAC7G,IAAM,EAAc,GAAgB,EAAe,CAAM,EACzD,GAAI,CAAC,EAAa,MAAO,GACzB,IAAM,EAAM,EAAc,QAE1B,GADgB,EAAY,OAAO,GAAM,EAAc,cAAc,QAAQ,EACzE,CAAA,CAAQ,QAAU,EAAG,MAAO,GAGhC,GAFA,EAAS,EACY,EAAO,WAAa,EAAA,cAErC,OAAQ,EAAO,SAAf,CACI,IAAK,SAAU,OAAO,EAAO,WAAa,EAAI,0BAA0B,EAAO,WAAY,CAAW,EAAI,GAC1G,IAAK,QAAS,OAAO,EAAO,WAAa,EAAI,yBAAyB,EAAO,WAAY,CAAW,EAAI,GACxG,IAAK,QAAS,OAAO,EAAI,yBAAyB,EAAO,SAAU,CAAW,EAC9E,IAAK,OAAQ,OAAO,EAAI,wBAAwB,EAAO,SAAU,CAAW,CAChF,CAEJ,OAAQ,EAAO,SAAf,CACI,IAAK,SAAU,OAAO,EAAO,WAAa,EAAI,0BAA0B,EAAO,WAAY,EAAO,SAAU,CAAW,EAAI,GAC3H,IAAK,QAAS,OAAO,EAAO,WAAa,EAAI,yBAAyB,EAAO,WAAY,EAAO,SAAU,CAAW,EAAI,GACzH,IAAK,QAAS,OAAO,EAAI,yBAAyB,EAAO,SAAU,EAAO,SAAU,CAAW,EAC/F,IAAK,OAAQ,OAAO,EAAI,wBAAwB,EAAO,SAAU,EAAO,SAAU,CAAW,CACjG,CACJ,CAMA,SAAS,GAAc,EAA8B,EAAsB,EAA4D,CACnI,IAAM,EAAc,GAAgB,EAAe,CAAM,EACzD,GAAI,CAAC,EAAa,MAAO,CAAC,EAC1B,EAAS,EACT,IAAM,EAAM,EAAc,QAE1B,GADqB,EAAO,WAAa,EAAA,cAErC,OAAQ,EAAO,SAAf,CACI,IAAK,SAAU,OAAO,EAAO,WAAa,EAAI,mBAAmB,EAAO,WAAY,CAAK,EAAI,CAAC,EAC9F,IAAK,QAAS,OAAO,EAAO,WAAa,EAAI,kBAAkB,EAAO,WAAY,CAAK,EAAI,CAAC,EAC5F,IAAK,QAAS,OAAO,EAAI,kBAAkB,EAAO,SAAU,CAAK,EACjE,IAAK,OAAQ,OAAO,EAAI,gBAAgB,EAAO,SAAU,CAAK,CAClE,CAEJ,OAAQ,EAAO,SAAf,CACI,IAAK,SAAU,OAAO,EAAO,WAAa,EAAI,mBAAmB,EAAO,WAAY,EAAO,SAAU,CAAK,EAAI,CAAC,EAC/G,IAAK,QAAS,OAAO,EAAO,WAAa,EAAI,kBAAkB,EAAO,WAAY,EAAO,SAAU,CAAK,EAAI,CAAC,EAC7G,IAAK,QAAS,OAAO,EAAI,kBAAkB,EAAO,SAAU,EAAO,SAAU,CAAK,EAClF,IAAK,OAAQ,OAAO,EAAI,gBAAgB,EAAO,SAAU,EAAO,SAAU,CAAK,CACnF,CACJ,CAKA,SAAS,GAAkB,EAA2H,CAMlJ,OALI,EAAU,YAEH,CAAE,SAAU,EAAU,YAAa,SAAU,EAAU,SAAU,SAAU,OAAQ,EAGvF,CACH,SAAU,EAAU,YACpB,SAAU,EAAU,SACpB,SAAU,EAAU,OAAS,SAAW,QACxC,WAAY,EAAU,MAC1B,CACJ,CAKA,SAAS,GAAe,EAA6D,CACjF,OAAO,EAAM,OAAO,GAAQ,EAAA,OAAO,MAAM,CAAI,GAAK,CAAC,EAAA,OAAO,QAAQ,CAAI,CAAC,CAC3E,CClJA,IAAM,GAAN,KAA+C,CAC3C,KAEA,cACA,QAEA,aAAwC,CAAC,EAEzC,YAAY,EAA8B,EAAc,EAAiC,CACrF,KAAK,cAAgB,EACrB,KAAK,KAAO,EACZ,KAAK,QAAU,CACnB,CAEA,SAAmB,CACf,OAAO,KAAK,MAAM,CACtB,CAEA,MAAgB,CACZ,GAAI,KAAK,aAAa,QAAU,EAAG,MAAO,GAC1C,IAAM,EAAgB,KAAK,cAAc,cAIzC,OAHK,GACL,EAAc,QAAQ,cAAc,KAAK,YAAY,EACrD,KAAK,aAAe,CAAC,EACd,IAHoB,EAI/B,CAEA,MAAgB,CACZ,OAAO,KAAK,MAAM,CACtB,CAGA,OAA2B,CACvB,IAAM,EAAgB,KAAK,cAAc,cACzC,GAAI,CAAC,EAAe,MAAO,GAE3B,IAAM,EAAmC,GADO,GAAc,EAAe,KAAK,QAAQ,OAAQ,KAAK,QAAQ,KACvD,CAAK,EAI7D,OAHI,EAAa,QAAU,EAAU,IACrC,KAAK,aAAe,EAAa,IAAI,GAAQ,EAAK,EAAE,EACpD,KAAK,QAAQ,YAAY,KAAK,YAAY,EACnC,GACX,CACJ,EChCM,GAAN,KAAgD,CAC5C,KACA,cACA,QAEA,gBAAmD,CAAC,EAEpD,YAAY,EAA8B,EAAc,EAAkC,CACtF,KAAK,cAAgB,EACrB,KAAK,KAAO,EACZ,KAAK,QAAU,CACnB,CAEA,SAAmB,CACf,OAAO,KAAK,OAAO,CACvB,CAEA,MAAgB,CACZ,GAAI,KAAK,gBAAgB,QAAU,EAAG,MAAO,GAC7C,IAAM,EAAgB,KAAK,cAAc,cACzC,GAAI,CAAC,EAAe,MAAO,GAE3B,IAAM,EAAS,CAAC,GAAG,KAAK,eAAe,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,SAAW,EAAE,QAAQ,EAC3E,EAAU,GACd,IAAK,IAAM,KAAU,EACb,GAAe,EAAe,EAAO,OAAQ,CAAC,EAAO,MAAM,CAAC,IAAG,EAAU,IAEjF,OAAO,CACX,CAEA,MAAgB,CACZ,OAAO,KAAK,OAAO,CACvB,CAGA,QAA4B,CACxB,IAAM,EAAgB,KAAK,cAAc,cACzC,GAAI,CAAC,EAAe,MAAO,GAC3B,IAAM,EAAU,KAAK,QAAQ,QAAQ,OAAO,GAAM,EAAc,cAAc,QAAQ,EAAG,EACzF,GAAI,EAAQ,QAAU,EAAG,MAAO,GAEhC,GAAI,KAAK,gBAAgB,QAAU,EAAG,CAClC,IAAK,IAAM,KAAU,EAAS,CAC1B,IAAM,EAAS,EAAoB,EAAe,CAAM,EACpD,GAAQ,KAAK,gBAAgB,KAAK,CAAE,SAAQ,SAAQ,SAAU,GAAgB,EAAe,CAAM,CAAE,CAAC,CAC9G,CACA,GAAI,KAAK,gBAAgB,QAAU,EAAG,MAAO,EACjD,CACA,IAAM,EAAU,GAAe,EAAe,KAAK,QAAQ,OAAQ,CAAO,EAE1E,OADI,GAAS,KAAK,QAAQ,YAAY,EAC/B,CACX,CACJ,EC9EM,GAAiB,IAAI,IAAY,CACnC,EAAA,YAAY,cACZ,EAAA,YAAY,OACZ,EAAA,YAAY,QACZ,EAAA,YAAY,aACZ,EAAA,YAAY,gBACZ,EAAA,YAAY,QAChB,CAAC,EAOD,SAAS,GAAsB,EAAa,CACxC,OAAO,EAAA,QAAO,cAAc,EAAO,GAAQ,CACvC,GAAI,EAAA,QAAO,WAAW,CAAI,EAAG,OAAO,CACxC,CAAC,CACL,CAMA,SAAS,GAAc,EAAiD,CACpE,IAAM,EAAmC,CAAC,EAC1C,IAAK,IAAM,KAAQ,EACX,GAAe,IAAI,CAAI,IAC3B,EAAY,GAAQ,EAAM,IAE9B,OAAO,CACX,CAKA,SAAS,GAAc,EAAqD,CACxE,OAAO,EACF,OAAO,GAAQ,EAAA,QAAO,IAAI,EAAM,MAAM,CAAC,CAAC,CACxC,IAAI,GACG,EAAA,QAAO,SAAS,CAAI,EAAU,EAC3B,EAAwB,CAAmB,CACrD,CACT,CAMA,SAAS,EAAwB,EAA+B,CAC5D,IAAM,EAAkC,CACpC,KAAM,EAAK,KACX,IAAK,EAAK,IACV,MAAO,GAAc,EAAK,KAAK,CACnC,EAkBA,GAhBI,EAAK,WAAa,OAAO,KAAK,EAAK,SAAS,CAAC,CAAC,OAAS,IACvD,EAAW,UAAY,GAAmB,EAAK,SAAS,GAGxD,EAAK,YAAc,OAAO,KAAK,EAAK,UAAU,CAAC,CAAC,OAAS,IACzD,EAAW,WAAa,EAAA,QAAO,UAAU,EAAK,UAAU,GAGxD,EAAK,KAAO,EAAK,IAAI,OAAS,IAC9B,EAAW,IAAM,CAAC,GAAG,EAAK,GAAG,GAG7B,EAAK,OAAS,EAAK,MAAM,OAAS,IAClC,EAAW,MAAQ,GAAc,EAAK,KAAK,GAG3C,EAAK,OAAS,OAAO,KAAK,EAAK,KAAK,CAAC,CAAC,OAAS,EAAG,CAClD,IAAM,EAA6B,CAAC,EACpC,IAAK,IAAM,KAAY,EAAK,MAAO,CAC/B,IAAM,EAAQ,EAAK,MAAM,GACrB,GAAS,EAAM,OAAS,IACxB,EAAM,GAAY,GAAc,CAAK,EAE7C,CACI,OAAO,KAAK,CAAK,CAAC,CAAC,OAAS,IAAG,EAAW,MAAQ,EAC1D,CAEA,IAAM,EAAQ,EACd,GAAI,EAAM,MAAO,CACb,EAAW,MAAQ,GACnB,IAAK,IAAM,IAAO,CAAC,OAAQ,WAAY,QAAS,UAAW,aAAc,OAAQ,MAAM,EAAY,CAC/F,IAAM,EAAS,EAAc,GACzB,GAAc,CAAK,IAAG,EAAW,GAAO,GAAmB,CAAK,EACxE,CACJ,CACA,OAAO,CACX,CAGA,SAAS,GAAc,EAAqB,CACxC,OAAgD,OAAO,GAAU,YAA1D,GAAsE,OAAO,KAAK,CAAK,CAAC,CAAC,OAAS,CAC7G,CClEA,IAAM,EAAN,KAAkD,CAC9C,KACA,cACA,QAEA,aAA6C,CAAC,EAE9C,eAA0C,CAAC,EAE3C,YAAY,EAA8B,EAAc,EAAoC,CACxF,KAAK,cAAgB,EACrB,KAAK,KAAO,EACZ,KAAK,QAAU,CACnB,CAEA,SAAmB,CACf,OAAO,KAAK,SAAS,CACzB,CAEA,MAAgB,CACZ,GAAI,KAAK,aAAa,QAAU,EAAG,MAAO,GAC1C,IAAM,EAAgB,KAAK,cAAc,cACzC,GAAI,CAAC,EAAe,MAAO,GAE3B,IAAM,EAAS,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,SAAW,EAAE,QAAQ,EACtE,EAAQ,IAAI,IACZ,EAA4B,CAAC,EAC/B,EAAU,GACd,IAAK,IAAM,KAAW,EAAQ,CAG1B,IAAM,EAAe,GAD2B,GAAc,EAD/C,KAAK,gBAAgB,EAAQ,OAAQ,CACyB,EAAQ,CAAC,EAAQ,UAAU,CACpE,CAAK,EACrC,EAAa,OAAS,IACtB,EAAU,GACV,EAAM,IAAI,EAAQ,UAAW,EAAa,EAAE,CAAC,EAAE,EAC/C,EAAW,KAAK,EAAa,EAAE,CAAC,EAAE,EAE1C,CAEA,OADI,IAAS,KAAK,eAAiB,GAC5B,CACX,CAEA,MAAgB,CACZ,OAAO,KAAK,SAAS,CACzB,CAGA,gBAA0B,EAAsB,EAA0C,CACtF,IAAM,EAAS,EAAM,IAAI,EAAO,UAAW,EAE3C,OADI,EAAO,YAAc,EAAe,CAAE,GAAG,EAAQ,WAAY,CAAO,EACjE,CACX,CAGA,UAA8B,CAC1B,IAAM,EAAgB,KAAK,cAAc,cACzC,GAAI,CAAC,EAAe,MAAO,GAE3B,IAAM,EAAU,KAAK,eAAe,OAAS,EAAI,KAAK,eAAiB,KAAK,QAAQ,QAE9E,EAA4B,CAAC,EACnC,IAAK,IAAM,KAAU,EAAS,CAC1B,IAAM,EAAO,EAAc,cAAc,QAAQ,GAC5C,GACA,EAAc,cAAc,WAAW,IAC5C,EAAM,KAAK,CAAI,CACnB,CACA,GAAI,EAAM,QAAU,EAAG,MAAO,GAE9B,KAAK,aAAe,EAAM,IAAI,IAAS,CACnC,WAAY,EAAwB,CAAI,EACxC,OAAQ,EAAoB,EAAe,EAAK,EAAE,EAClD,SAAU,GAAgB,EAAe,EAAK,EAAE,EAChD,UAAW,EAAK,EACpB,EAAE,EACF,KAAK,eAAiB,EAAM,IAAI,GAAQ,EAAK,EAAE,EAC/C,IAAM,EAAQ,EAAM,IAAI,GAAQ,KAAK,cAAc,eAAe,gBAAgB,iBAAiB,EAAK,IAAI,CAAC,EAAE,MAAQ,EAAK,IAAI,EAIhI,OAFA,EAAc,QAAQ,cAAc,KAAK,cAAc,EACvD,KAAK,QAAQ,YAAY,CAAK,EACvB,EACX,CACJ,ECrGM,GAAN,cAAkC,CAAe,CAE7C,aAAmD,CAAC,EAEpD,UAA2B,CACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,CAC3B,CAEA,WAA4B,CACxB,KAAK,aAAa,QAAQ,GAAe,EAAY,CAAC,EACtD,KAAK,aAAa,OAAS,CAC/B,CAGA,gBAAsD,CAClD,OAAO,KAAK,eAAe,mBAC/B,CAKA,gBAAiC,CAC7B,KAAK,aAAa,KACd,KAAK,SAAS,UAAU,GAAe,GAAS,CAC5C,IAAM,EAAgB,KAAK,eAAe,EACpC,EAAO,EAAM,KACb,EAAY,EAAK,UAEvB,GAAI,CAAC,GAAa,CAAC,EAAU,WAAa,CAAC,GAAe,cAAe,OACzE,IAAM,EAAS,GAAkB,CAAS,EACpC,EAAc,EAAK,QAAQ,OAAO,GAAM,IAAO,EAAA,WAAW,EAChE,GAAI,EAAY,OAAS,EAAG,CAExB,IAAM,EAAU,IAAI,GAAiB,EAAe,MAAM,EAAY,OAAO,MAAO,CAChF,SACA,QAAS,EAET,cAAiB,EAAc,gBAAgB,CAAW,CAC9D,CAAC,EACD,EAAc,aAAa,QAAQ,CAAO,CAC9C,KAAO,CAEH,IAAM,EAAQ,EAAK,eAAe,IAAI,IAAY,CAC9C,GAAI,EAAA,QAAO,UAAU,EAAQ,eAAiB,CAAC,CAAC,EAChD,KAAM,EAAQ,IAClB,EAAE,EACI,EAAU,IAAI,GAAgB,EAAe,MAAM,EAAM,OAAO,MAAO,CACzE,SACA,QACA,UAAW,GAAW,EAAc,gBAAgB,CAAO,CAC/D,CAAC,EACD,EAAc,aAAa,QAAQ,CAAO,CAC9C,CACJ,EAAG,GAAG,CACV,CACJ,CAKA,mBAAoC,CAChC,KAAK,aAAa,KACd,KAAK,SAAS,UAAU,GAAkB,GAAS,CAC/C,IAAM,EAAO,EAAM,KACnB,GAAI,EAAK,OAAS,UAAW,OAC7B,IAAM,EAAgB,KAAK,eAAe,EAC1C,GAAI,CAAC,EAAe,OACpB,IAAM,EAAO,EAAK,SAAW,EAAK,QAE5B,EAAS,EAAK,SAAS,OACvB,EAAa,CAAC,CAAC,IAAW,EAAO,UAAY,SAAW,EAAO,UAAY,YAAc,EAAO,mBAEtG,GAAI,GAAQ,CAAC,EAAK,UAAY,EAAK,MAAQ,IAAK,CAC5C,GAAI,EAAY,OAChB,EAAK,SAAS,eAAe,EAC7B,EAAc,aAAa,KAAK,EAChC,EAAc,gBAAgB,EAC9B,MACJ,CAEA,GAAI,IAAS,EAAK,MAAQ,KAAQ,EAAK,UAAY,EAAK,MAAQ,KAAO,CACnE,GAAI,EAAY,OAChB,EAAK,SAAS,eAAe,EAC7B,EAAc,aAAa,KAAK,EAChC,EAAc,gBAAgB,EAC9B,MACJ,CAEA,IAAK,EAAK,MAAQ,UAAY,EAAK,MAAQ,cAAgB,EAAc,gBAAiB,CACtF,GAAI,EAAY,OAChB,EAAK,SAAS,eAAe,EAC7B,IAAM,EAAU,EAAc,WAAW,IAAI,GAAa,EAAU,MAAO,CAAC,CAAC,OAAO,OAAO,EAC3F,GAAI,EAAQ,QAAU,EAAG,OACzB,IAAM,EAAU,IAAI,EAAmB,EAAe,MAAM,EAAQ,OAAO,MAAO,CAC9E,UACA,cAAiB,EAAc,gBAAgB,CACnD,CAAC,EACD,EAAc,aAAa,QAAQ,CAAO,CAC9C,CACJ,CAAC,CACL,CACJ,CACJ,ECrFM,EAAN,MAAM,CAA4C,CAC9C,KACA,cACA,QAEA,YAAY,EAA8B,EAAc,EAAoC,CACxF,KAAK,cAAgB,EACrB,KAAK,KAAO,EACZ,KAAK,QAAU,CACnB,CAEA,IAAI,SAAoC,CACpC,OAAO,KAAK,QAAQ,OACxB,CAEA,SAAmB,CACf,OAAO,KAAK,aAAa,EAAK,CAClC,CAEA,MAAgB,CACZ,OAAO,KAAK,aAAa,EAAI,CACjC,CAEA,MAAgB,CACZ,OAAO,KAAK,aAAa,EAAK,CAClC,CAGA,aAAuB,EAAyB,CAC5C,IAAM,EAAgB,KAAK,cAAc,cACzC,GAAI,CAAC,EAAe,MAAO,GAC3B,IAAM,EAA4B,CAAC,EACnC,IAAK,IAAM,KAAU,KAAK,QAAQ,QAAS,CACvC,IAAM,EAAO,EAAc,cAAc,QAAQ,EAAO,QACnD,IACL,EAAO,MAAM,EAAM,EAAQ,EAAO,SAAW,EAAO,QAAQ,EAC5D,EAAM,KAAK,CAAI,EACnB,CAGA,OAFI,EAAM,QAAU,EAAU,IAC9B,KAAK,SAAS,CAAK,EACZ,GACX,CAGA,SAAmB,EAAiC,CAChD,GAAI,KAAK,QAAQ,gBAAiB,OAClC,IAAM,EAAgB,KAAK,cAAc,cACpC,IACL,EAAc,aAAa,EAC3B,EAAc,cAAgB,CAC1B,IAAM,EAAU,IAAI,IAAI,EAAM,IAAI,GAAQ,EAAK,EAAE,CAAC,EAClD,IAAK,IAAM,KAAa,KAAK,cAAc,WACnC,EAAU,QAAU,EAAQ,IAAI,EAAU,MAAM,GAAG,EAAU,eAAe,CAExF,CAAC,EACL,CAMA,SAAS,EAA8B,CACnC,GAAI,EAAE,aAAgB,GAAqB,MAAO,GAClD,IAAM,EAAO,IAAI,IAAI,KAAK,QAAQ,QAAQ,IAAI,GAAU,GAAG,EAAO,OAAO,GAAG,EAAO,WAAW,CAAC,EAE/F,GAAI,CADoB,EAAK,QAAQ,QAAQ,KAAK,GAAU,EAAK,IAAI,GAAG,EAAO,OAAO,GAAG,EAAO,WAAW,CACtG,EAAiB,MAAO,GAC7B,IAAK,IAAM,KAAU,EAAK,QAAQ,QAAS,CACvC,IAAM,EAAS,KAAK,QAAQ,QAAQ,KAAK,GAAQ,EAAK,SAAW,EAAO,QAAU,EAAK,YAAc,EAAO,SAAS,EACjH,EACA,EAAO,SAAW,EAAO,SAEzB,KAAK,QAAQ,QAAQ,KAAK,CAAM,CAExC,CACA,MAAO,EACX,CACJ,ECjFM,EAAN,MAAM,CAAgD,CAClD,KACA,cACA,QAEA,YAAY,EAA8B,EAAc,EAAwC,CAC5F,KAAK,cAAgB,EACrB,KAAK,KAAO,EACZ,KAAK,QAAU,CACnB,CAEA,SAAmB,CACf,OAAO,KAAK,aAAa,EAAK,CAClC,CAEA,MAAgB,CACZ,OAAO,KAAK,aAAa,EAAI,CACjC,CAEA,MAAgB,CACZ,OAAO,KAAK,aAAa,EAAK,CAClC,CAGA,aAAuB,EAAyB,CAC5C,IAAM,EAAgB,KAAK,cAAc,cACzC,GAAI,CAAC,EAAe,MAAO,GAC3B,IAAM,EAAM,EAAc,QACtB,EAAU,GACd,IAAK,IAAM,KAAU,KAAK,QAAQ,QAAS,CACvC,IAAM,EAAW,EAAQ,EAAO,YAAc,EAAO,YACrD,AAGI,EAHA,EACU,EAAI,iBAAiB,EAAO,OAAQ,EAAO,MAAO,CAAQ,GAAK,EAE/D,EAAI,mBAAmB,EAAO,OAAQ,EAAO,KAAK,GAAK,CAEzE,CACA,OAAO,CACX,CAGA,SAAS,EAA8B,CACnC,GAAI,EAAE,aAAgB,GAAyB,MAAO,GACtD,IAAM,EAAO,IAAI,IAAI,KAAK,QAAQ,QAAQ,IAAI,GAAU,GAAG,EAAO,OAAO,GAAG,EAAO,OAAO,CAAC,EAE3F,GAAI,CADoB,EAAK,QAAQ,QAAQ,KAAK,GAAU,EAAK,IAAI,GAAG,EAAO,OAAO,GAAG,EAAO,OAAO,CAClG,EAAiB,MAAO,GAC7B,IAAK,IAAM,KAAU,EAAK,QAAQ,QAAS,CACvC,IAAM,EAAS,KAAK,QAAQ,QAAQ,KAAK,GAAQ,EAAK,SAAW,EAAO,QAAU,EAAK,QAAU,EAAO,KAAK,EACzG,EACA,EAAO,YAAc,EAAO,YAE5B,KAAK,QAAQ,QAAQ,KAAK,CAAM,CAExC,CACA,MAAO,EACX,CACJ,6MCjEA,IAAM,EAAQ,EAKR,GAAA,EAAe,EAAA,IAAA,CAAgC,EAE/C,GAAA,EAAoB,EAAA,IAAA,CAAqD,EAE3E,EAGE,EAAmC,EAAM,cAAc,eAAe,iBAG5E,EAAA,EAAA,UAAA,KAAgB,CACZ,EAAM,cAAc,kBAAoB,EAAa,MAEjD,EAAa,OAAS,OAAO,eAAmB,MAChD,EAAiB,IAAI,mBAAqB,CACtC,EAAM,cAAc,MAAM,eAAe,EACzC,IAAK,IAAM,KAAa,EAAM,cAAc,WACxC,EAAU,eAAe,CAEjC,CAAC,EACD,EAAe,QAAQ,EAAa,KAAK,EAEjD,CAAC,GAED,EAAA,EAAA,gBAAA,KAAsB,CAClB,GAAgB,WAAW,EAC3B,EAAiB,IAAA,GAGb,EAAM,cAAc,oBAAsB,EAAa,QACvD,EAAM,cAAc,kBAAoB,IAAA,GAEhD,CAAC,GAGD,EAAA,EAAA,MAAA,KAAY,EAAkB,OAAO,cAAgB,GAA6C,CAC9F,EAAM,cAAc,sBAAwB,CAChD,EAAG,CAAE,UAAW,EAAK,CAAC,EAItB,IAAM,EAAQ,EAAM,cAAc,MAC5B,EAAa,EAAM,cAAc,WACjC,EAAY,EAAM,cAAc,eAAe,UAG/C,GAAA,EAAa,EAAA,SAAA,KAA8B,CAC7C,IAAM,EAAW,EAAM,SAEvB,OADK,EACE,CACH,SAAU,WACV,IAAK,GAAG,EAAS,IAAI,IACrB,KAAM,GAAG,EAAS,KAAK,IACvB,MAAO,GAAG,EAAS,MAAM,IACzB,OAAQ,GAAG,EAAS,OAAO,GAC/B,EAPsB,CAAE,QAAS,MAAO,CAQ5C,CAAC,EAGK,GAAA,EAAkB,EAAA,SAAA,KACb,EAAW,KAAK,EAAW,IAAQ,CACtC,IAAM,EAAW,EAAU,SACrB,EAAuB,EAAW,CACpC,SAAU,WACV,IAAK,GAAG,EAAS,IAAI,IACrB,KAAM,GAAG,EAAS,KAAK,IACvB,MAAO,GAAG,EAAS,MAAM,IACzB,OAAQ,GAAG,EAAS,OAAO,GAC/B,EAAI,CAAE,QAAS,MAAO,EACtB,MAAO,CAAE,IAAK,EAAU,QAAU,OAAO,CAAG,EAAG,QAAO,KAAM,EAAU,eAAe,MAAQ,EAAG,CACpG,CAAC,CACJ,EAGK,GAAA,EAAiB,EAAA,SAAA,KAA8B,CACjD,IAAM,EAAW,EAAU,SAa3B,MAZI,CAAC,GAAY,EAAU,QAAQ,EAAU,CAAE,QAAS,MAAO,EAC3D,EAAU,aAAa,EAEhB,CACH,SAAU,WACV,IAAK,GAAG,EAAU,SAAS,EAAI,EAAS,IAAM,EAAS,IAAM,EAAS,OAAO,IAC7E,KAAM,GAAG,EAAS,KAAK,IACvB,MAAO,GAAG,EAAS,MAAM,IACzB,OAAQ,KACZ,EAGG,CACH,SAAU,WACV,IAAK,GAAG,EAAS,IAAI,IACrB,KAAM,GAAG,EAAU,SAAS,EAAI,EAAS,KAAO,EAAS,KAAO,EAAS,MAAM,IAC/E,MAAO,MACP,OAAQ,GAAG,EAAS,OAAO,GAC/B,CACJ,CAAC,iBAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAqBM,MAAA,CArBG,QAAA,eAAJ,IAAI,EAAe,MAAM,oCAC1B,EAAA,EAAA,YAAA,EAAA,EAME,EAAA,MAAA,CAAA,EAAA,cAAA,EAAA,CALM,QAAA,oBAAJ,IAAI,EACH,iBAAA,EAAiB,EAAA,MAAA,CAAA,CAAA,EACjB,MAAO,EAAM,MACb,kBAAmB,EAAM,kBACzB,YAAa,6DAGP,EAAA,EAAA,MAAA,CAAA,CAAA,CAAK,CAAC,SAAA,EAAjB,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAA+E,MAAA,OAAtD,MAAM,sBAAuB,OAAA,EAAK,EAAA,eAAA,CAAE,EAAA,KAAU,8CAEvE,EAAA,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAOM,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CANa,EAAA,MAAR,KADX,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAOM,MAAA,CALD,IAAK,EAAK,IACX,MAAM,0BACL,OAAA,EAAK,EAAA,eAAA,CAAE,EAAK,KAAK,CAEN,EAAA,CAAA,EAAK,OAAA,EAAjB,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAAkF,OAAlF,IAAA,EAAkF,EAAA,gBAAA,CAAnB,EAAK,IAAI,EAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,CAAA,EAAA,CAAA,WAG5E,EAAA,EAAA,mBAAA,CAAmE,MAAA,CAA9D,MAAM,0BAA2B,OAAA,EAAK,EAAA,eAAA,CAAE,EAAA,KAAc,qQE/HnE,IAAM,EAAQ,EAGR,GAAA,EAAQ,EAAA,IAAA,CAAgC,EAExC,EAAS,EAAM,eAAe,OAC9B,EAAmB,EAAM,eAAe,iBAGxC,GAAA,EAAa,EAAA,SAAA,KAA8B,CAC7C,GAAI,CAAC,EAAM,MAAO,MAAO,CAAC,EAC1B,IAAM,EAAW,EAAO,SAIxB,MAHI,CAAC,EAAA,OAAO,MAAM,EAAS,UAAU,GAAK,CAAC,EAAA,OAAO,MAAM,EAAS,UAAU,EAChE,CAAC,EAEL,CACH,UAAW,gCAAgC,EAAS,WAAa,EAAE,MAAM,EAAS,WAAa,GAAG,kBACtG,CACJ,CAAC,iBAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,CAWW,EAAA,SAAA,CAXD,GAAG,MAAM,EAAA,EAAA,EAEL,EAAA,MAAA,CAAA,CAAA,CAAM,CAAC,UAAA,EAAW,EAAA,MAAA,CAAA,CAAA,CAAY,CAAC,WAAA,EAAY,EAAA,MAAA,CAAA,CAAA,CAAgB,CAAC,gBAAA,EADtE,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CASM,MAAA,OAPE,QAAA,QAAJ,IAAI,EACJ,MAAM,iBACL,OAAA,EAAK,EAAA,eAAA,CAAE,EAAA,KAAU,CAElB,EAAA,EAAA,EAAA,EAAA,mBAAA,CAEO,OAFP,IAAA,EAEO,EAAA,gBAAA,EAAA,EADA,EAAA,MAAA,CAAA,CAAA,CAAgB,CAAC,SAAS,IAAI,GAAQ,EAAK,IAAI,CAAA,CAAE,KAAI,GAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,CAAA,CAAA,kQE7BxE,IAAM,EAAQ,EAGR,GAAA,EAAc,EAAA,SAAA,KAAe,EAAM,cAAc,WAAW,EAGlE,SAAS,EAAa,EAAwB,CAI1C,OAHI,EAAA,OAAO,MAAM,CAAG,GAAK,EAAA,EAAC,EAAA,UAAA,CAAU,CAAG,EAC5B,EAAM,cAAc,eAAe,gBAAgB,aAAa,CAAG,EAEvE,CACX,CAGA,SAAS,EAAe,EAA6B,CACjD,GAAM,CACF,MACA,WACA,QACA,YACA,aACA,eACA,aACA,GAAG,GACH,EACJ,MAAO,CACH,cAAe,EAAM,cACrB,cAAe,EAAM,cAAc,cACnC,MAAO,EAAY,MACnB,GAAG,EACH,GAAG,CACP,CACJ,CAGA,SAAS,EAAQ,EAAyB,CACtC,GAAM,CAAE,YAAW,cAAe,EAClC,GAAI,IAAe,IAAS,EAAA,OAAO,QAAQ,CAAS,EAAG,MAAO,GAC9D,IAAM,EAAQ,EAAY,MACpB,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EACf,EAAO,IAAI,EAAK,MAAM,EAAW,EAErC,GAAI,EAAO,OAAS,EAAG,MAAO,GAC9B,IAAM,EAAa,EAAO,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAC1C,GAAI,CAAC,EAAA,OAAO,MAAM,CAAU,EAAG,MAAO,GACtC,IAAM,EAAU,EAAA,QAAO,KAAK,CAAU,EACtC,OAAO,EAAQ,WAAW,IAAI,GAAK,EAAQ,SAAS,IAAI,CAC5D,CAKA,SAAS,EAAW,EAAsB,CACtC,GAAM,CAAE,aAAc,EACtB,GAAI,EAAA,OAAO,QAAQ,CAAS,EAAG,OAC/B,IAAM,EAAQ,EAAY,MACpB,EAAS,CAAC,EAAQ,CAAM,EAC9B,IAAK,IAAM,KAAQ,EAAO,CACtB,IAAM,EAAY,EAAK,UAGvB,GAFA,AAA6B,EAAU,eAAe,CAAC,EACvD,AAA+B,EAAU,iBAAiB,CAAC,EACvD,EAEI,EAAA,QAAO,MAAM,EAAK,MAAO,CAAS,EAClC,EAAU,eAAe,GAAa,EAAK,MAAM,GAEjD,OAAO,EAAU,eAAe,GAEpC,EAAK,MAAM,GAAa,EAAU,aAAa,IAAc,aAC1D,CAEH,IAAM,EAAa,EAAK,MAAM,GAC9B,GAAI,EAAA,OAAO,MAAM,CAAU,EAAG,CAC1B,IAAM,EAAU,EAAA,QAAO,KAAK,CAAU,EAClC,EAAQ,WAAW,IAAI,GAAK,EAAQ,SAAS,IAAI,IACjD,EAAU,aAAa,GAAa,EAE5C,CACI,EAAA,QAAO,MAAM,EAAU,eAAgB,CAAS,EAChD,EAAU,eAAe,GAAa,EAAK,MAAM,GAEjD,OAAO,EAAK,MAAM,EAE1B,CACJ,CAEA,EAAM,cAAc,eAAe,aAAa,EAChD,EAAM,cAAc,iBAAiB,kBAAkB,CAC3D,gBAII,EAAA,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAqBM,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CArBuB,EAAM,MAAM,OAA5B,EAAQ,MAArB,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAqBM,MAAA,CArB2C,IAAK,EAAK,MAAM,yBAC7D,EAAA,EAAA,mBAAA,CAKM,MALN,GAKM,CAJa,EAAO,YAAA,EAAtB,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAEU,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,OAFwB,MAAO,EAAO,YAC5C,SAAA,EAAA,EAAA,QAAA,KAA+B,EAAA,EAA/B,EAAA,mBAAA,CAA+B,OAAA,MAAA,EAAA,EAAA,gBAAA,CAAtB,EAAO,KAAK,EAAA,CAAA,CAAA,CAAA,KAEzB,EAAA,KAAA,CAAA,OAAA,CAAA,KAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAAsC,OAAA,IAAA,EAAA,EAAA,gBAAA,CAAtB,EAAO,KAAK,EAAA,CAAA,EAAA,CAAA,GAEhC,EAAA,EAAA,mBAAA,CAMM,MANN,GAMM,CAHQ,EAAa,EAAO,GAAG,IAAA,EAFjC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAIE,EAAA,wBAAA,CAHO,EAAa,EAAO,GAAG,CAAA,GAAA,EADhC,EAAA,WAAA,CAIE,iBADU,EAAA,EAAe,CAAM,CAAA,EAAA,KAAA,EAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,CAAA,CAAA,EAI3B,EAAO,aAAU,IAAc,EAAO,YAAA,EADhD,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAMkB,MAAA,OAJd,OAAA,EAAK,EAAA,eAAA,CAAA,CAAC,sBAAqB,CAAA,6BACa,EAAQ,CAAM,CAAA,CAAA,CAAA,EACtD,MAAM,wBACL,QAAK,GAAE,EAAW,CAAM,CACzB,GAAA,EAAA,EAAA,gBAAA,CAAA,KAAK,EAAA,GAAA,EAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,6RElHjB,IAAM,EAAQ,EAGR,GAAA,EAAe,EAAA,SAAA,KAAe,EAAM,cAAc,iBAAiB,YAAY,EAG/E,GAAA,EAAgB,EAAA,SAAA,KACL,EAAM,cAAc,YAEzB,EAAM,YAAY,QAAU,CAAC,EAAA,CAChC,IAAI,GAAS,CACV,IAAM,EAAQ,EAAM,MAAM,OAAO,GAAQ,CAAC,EAAa,CAAI,CAAC,EAC5D,MAAO,CAAE,GAAG,EAAO,OAAM,CAC7B,CAAC,CAAA,CACA,OAAO,GAAS,EAAM,MAAM,OAAS,CAAC,EANzB,CAAC,CAOtB,EAGD,SAAS,EAAa,EAAyB,CAC3C,GAAI,CAAC,EAAO,aAAc,MAAO,GACjC,IAAM,EAAO,EAAM,cAAc,WAEjC,OADK,EACE,EAAO,aAAa,EAAM,EAAM,cAAc,YAAa,IAAA,EAAgB,IAAM,GADtE,EAEtB,CAEA,IAAM,GAAA,EAAgB,EAAA,SAAA,KAClB,EAAc,MAAM,IAAI,IAAU,CAC9B,IAAK,EAAM,MACX,MAAO,EAAM,MACb,SAAA,EAAS,EAAA,EAAA,CAAE,GAAkB,CAAE,cAAe,EAAM,cAAe,OAAM,CAAC,CAC9E,EAAE,CACN,SAGA,EAAA,EAAA,MAAA,KAAY,EAAM,cAAc,0BAA6B,CACzD,EAAM,cAAc,iBAAiB,mBAAmB,CAC5D,EAAG,CAAE,UAAW,EAAK,CAAC,WAKlB,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CASM,MAAA,CATA,IAAK,EAAM,cAAc,iBAAiB,aAAc,MAAM,sBAClD,EAAA,CAAA,EAAM,cAAc,kBAClC,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAMW,EAAA,SAAA,CAAA,IAAA,CAAA,EAAA,EAAA,EALP,EAAA,mBAAA,CAGM,MAHN,GAGM,EAAA,EAFF,EAAA,mBAAA,CAA0G,OAA1G,IAAA,EAA0G,EAAA,gBAAA,CAAhE,EAAM,cAAc,uBAAuB,MAAI,GAAA,EAAA,CAAA,GAAA,EACzF,EAAA,mBAAA,CAAwF,OAAxF,IAAA,EAAwF,EAAA,gBAAA,CAA9C,EAAM,cAAc,YAAY,IAAI,EAAA,CAAA,CAAA,CAAA,GAAA,EAElF,EAAA,YAAA,EAAA,EAAsG,EAAA,MAAA,CAAA,EAAA,QAAA,EAAA,CAApF,UAAY,EAAA,MAAqB,MAArB,qBAAA,AAAA,EAAA,KAAA,GAAA,EAAA,MAAqB,MAAK,EAAE,MAAA,GAAM,KAAK,QAAS,MAAO,EAAA,6CANvD,EAAlC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAA6E,EAAA,MAAA,CAAA,EAAA,KAAA,EAAA,OAA1B,YAAY,WAC/D,CAAA,4CEbF,GAA6C,CAC/C,CACI,MAAO,KACP,WAAY,gBACZ,MAAO,CACH,CAAE,SAAU,UAAW,MAAO,OAAQ,IAAK,eAAgB,QAAS,CAnB5E,CAAE,MAAO,QAAS,MAAO,WAAY,EACrC,CAAE,MAAO,eAAgB,MAAO,mBAAoB,EACpD,CAAE,MAAO,SAAU,MAAO,YAAa,EACvC,CAAE,MAAO,OAAQ,MAAO,UAAW,EACnC,CAAE,MAAO,cAAe,MAAO,mBAAoB,EACnD,CAAE,MAAO,OAAQ,MAAO,UAAW,EACnC,CAAE,MAAO,cAAe,MAAO,mBAAoB,EACnD,CAAE,MAAO,OAAQ,MAAO,UAAW,CAYyC,CAAe,EACnF,CAAE,SAAU,gBAAiB,MAAO,OAAQ,IAAK,eAAgB,QAAS,CACtE,CAAE,MAAO,MAAO,MAAO,SAAU,EACjC,CAAE,MAAO,SAAU,MAAO,YAAa,EACvC,CAAE,MAAO,cAAe,MAAO,MAAO,EACtC,CAAE,MAAO,iBAAkB,MAAO,MAAO,CAC7C,CAAG,EACH,CAAE,SAAU,iBAAkB,MAAO,OAAQ,IAAK,eAAgB,QAAS,CACvE,CAAE,MAAO,aAAc,MAAO,IAAK,EACnC,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,WAAY,MAAO,IAAK,EACjC,CAAE,MAAO,gBAAiB,MAAO,IAAK,EACtC,CAAE,MAAO,eAAgB,MAAO,IAAK,EACrC,CAAE,MAAO,eAAgB,MAAO,IAAK,CACzC,CAAE,EACF,CAAE,SAAU,aAAc,MAAO,OAAQ,IAAK,eAAgB,QAAS,CACnE,CAAE,MAAO,aAAc,MAAO,IAAK,EACnC,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,WAAY,MAAO,IAAK,EACjC,CAAE,MAAO,UAAW,MAAO,IAAK,EAChC,CAAE,MAAO,WAAY,MAAO,IAAK,CACrC,CAAE,EACF,CAAE,SAAU,WAAY,MAAO,KAAM,IAAK,eAAgB,QAAS,CAC/D,CAAE,MAAO,SAAU,MAAO,KAAM,EAChC,CAAE,MAAO,OAAQ,MAAO,IAAK,EAC7B,CAAE,MAAO,eAAgB,MAAO,MAAO,CAC3C,CAAE,EACF,CAAE,SAAU,MAAO,MAAO,KAAM,IAAK,cAAe,CACxD,CACJ,EACA,CACI,MAAO,KACP,QAxCe,GAA+B,OAAO,EAAM,SAAc,EAAE,CAAC,CAAC,SAAS,MAAM,EAyC5F,MAAO,CACH,CAAE,SAAU,sBAAuB,MAAO,MAAO,IAAK,cAAe,EACrE,CAAE,SAAU,mBAAoB,MAAO,MAAO,IAAK,cAAe,EAClE,CAAE,SAAU,eAAgB,MAAO,OAAQ,IAAK,eAAgB,QAAS,CACrE,CAAE,MAAO,MAAO,MAAO,IAAK,EAC5B,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,QAAS,MAAO,IAAK,CAClC,CAAE,EACF,CAAE,SAAU,UAAW,MAAO,OAAQ,IAAK,cAAe,CAC9D,CACJ,EACA,CACI,MAAO,KACP,WAAY,iBACZ,MAAO,CACH,CAAE,SAAU,SAAU,MAAO,MAAO,IAAK,cAAe,EACxD,CAAE,SAAU,YAAa,MAAO,SAAU,IAAK,cAAe,EAC9D,CAAE,SAAU,cAAe,MAAO,SAAU,IAAK,cAAe,EAChE,CAAE,SAAU,eAAgB,MAAO,SAAU,IAAK,cAAe,EACjE,CAAE,SAAU,aAAc,MAAO,SAAU,IAAK,cAAe,EAC/D,CAAE,SAAU,UAAW,MAAO,MAAO,IAAK,cAAe,EACzD,CAAE,SAAU,aAAc,MAAO,SAAU,IAAK,cAAe,EAC/D,CAAE,SAAU,eAAgB,MAAO,SAAU,IAAK,cAAe,EACjE,CAAE,SAAU,gBAAiB,MAAO,SAAU,IAAK,cAAe,EAClE,CAAE,SAAU,cAAe,MAAO,SAAU,IAAK,cAAe,CACpE,CACJ,EACA,CACI,MAAO,KACP,WAAY,cACZ,MAAO,CACH,CAAE,SAAU,QAAS,MAAO,KAAM,IAAK,cAAe,EACtD,CAAE,SAAU,SAAU,MAAO,KAAM,IAAK,cAAe,EACvD,CAAE,SAAU,WAAY,MAAO,OAAQ,IAAK,cAAe,EAC3D,CAAE,SAAU,YAAa,MAAO,OAAQ,IAAK,cAAe,EAC5D,CAAE,SAAU,WAAY,MAAO,OAAQ,IAAK,cAAe,EAC3D,CAAE,SAAU,YAAa,MAAO,OAAQ,IAAK,cAAe,CAChE,CACJ,EACA,CACI,MAAO,KACP,WAAY,kBACZ,MAAO,CACH,CAAE,SAAU,WAAY,MAAO,OAAQ,IAAK,eAAgB,QAAS,CACjE,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,WAAY,MAAO,IAAK,EACjC,CAAE,MAAO,WAAY,MAAO,IAAK,EACjC,CAAE,MAAO,QAAS,MAAO,IAAK,EAC9B,CAAE,MAAO,SAAU,MAAO,IAAK,CACnC,CAAE,EACF,CAAE,SAAU,MAAO,MAAO,MAAO,IAAK,cAAe,EACrD,CAAE,SAAU,QAAS,MAAO,MAAO,IAAK,cAAe,EACvD,CAAE,SAAU,SAAU,MAAO,MAAO,IAAK,cAAe,EACxD,CAAE,SAAU,OAAQ,MAAO,MAAO,IAAK,cAAe,EACtD,CAAE,SAAU,SAAU,MAAO,KAAM,IAAK,cAAe,CAC3D,CACJ,EACA,CACI,MAAO,KACP,WAAY,cACZ,MAAO,CACH,CAAE,SAAU,WAAY,MAAO,KAAM,IAAK,cAAe,EACzD,CAAE,SAAU,aAAc,MAAO,KAAM,IAAK,eAAgB,QAAS,CACjE,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,OAAQ,MAAO,IAAK,EAC7B,CAAE,MAAO,MAAO,MAAO,GAAI,EAC3B,CAAE,MAAO,MAAO,MAAO,GAAI,EAC3B,CAAE,MAAO,MAAO,MAAO,IAAK,EAC5B,CAAE,MAAO,MAAO,MAAO,IAAK,CAChC,CAAE,EACF,CAAE,SAAU,QAAS,MAAO,KAAM,IAAK,aAAc,EACrD,CAAE,SAAU,YAAa,MAAO,KAAM,IAAK,eAAgB,QAAS,CAChE,CAAE,MAAO,OAAQ,MAAO,GAAI,EAC5B,CAAE,MAAO,SAAU,MAAO,GAAI,EAC9B,CAAE,MAAO,QAAS,MAAO,GAAI,EAC7B,CAAE,MAAO,UAAW,MAAO,IAAK,CACpC,CAAE,EACF,CAAE,SAAU,aAAc,MAAO,KAAM,IAAK,cAAe,EAC3D,CAAE,SAAU,aAAc,MAAO,KAAM,IAAK,cAAe,EAC3D,CAAE,SAAU,iBAAkB,MAAO,KAAM,IAAK,eAAgB,QAAS,CACrE,CAAE,MAAO,OAAQ,MAAO,GAAI,EAC5B,CAAE,MAAO,YAAa,MAAO,KAAM,EACnC,CAAE,MAAO,eAAgB,MAAO,KAAM,EACtC,CAAE,MAAO,WAAY,MAAO,KAAM,CACtC,CAAE,CACN,CACJ,EACA,CACI,MAAO,KACP,WAAY,gBACZ,MAAO,CACH,CAAE,SAAU,cAAe,MAAO,OAAQ,IAAK,cAAe,EAC9D,CAAE,SAAU,cAAe,MAAO,OAAQ,IAAK,eAAgB,QAAS,CACpE,CAAE,MAAO,OAAQ,MAAO,GAAI,EAC5B,CAAE,MAAO,QAAS,MAAO,IAAK,EAC9B,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,SAAU,MAAO,IAAK,CACnC,CAAE,EACF,CAAE,SAAU,cAAe,MAAO,OAAQ,IAAK,aAAc,EAC7D,CAAE,SAAU,eAAgB,MAAO,KAAM,IAAK,cAAe,CACjE,CACJ,EACA,CACI,MAAO,QACP,WAAY,gBACZ,MAAO,CACH,CAAE,SAAU,kBAAmB,MAAO,OAAQ,IAAK,aAAc,EACjE,CAAE,SAAU,kBAAmB,MAAO,OAAQ,IAAK,cAAe,EAClE,CAAE,SAAU,UAAW,MAAO,OAAQ,IAAK,cAAe,EAC1D,CAAE,SAAU,YAAa,MAAO,KAAM,IAAK,cAAe,EAC1D,CAAE,SAAU,SAAU,MAAO,KAAM,IAAK,eAAgB,QAAS,CAC7D,CAAE,MAAO,OAAQ,MAAO,IAAK,EAC7B,CAAE,MAAO,UAAW,MAAO,IAAK,EAChC,CAAE,MAAO,cAAe,MAAO,IAAK,EACpC,CAAE,MAAO,OAAQ,MAAO,IAAK,EAC7B,CAAE,MAAO,OAAQ,MAAO,IAAK,CACjC,CAAE,EACF,CAAE,SAAU,WAAY,MAAO,KAAM,IAAK,eAAgB,QAAS,CAC/D,CAAE,MAAO,UAAW,MAAO,IAAK,EAChC,CAAE,MAAO,SAAU,MAAO,IAAK,EAC/B,CAAE,MAAO,OAAQ,MAAO,IAAK,EAC7B,CAAE,MAAO,SAAU,MAAO,IAAK,CACnC,CAAE,CACN,CACJ,CACJ,EC1MM,GAAyB,IAU/B,SAAS,EAAc,EAA6C,CAC5D,MAAA,OAAO,QAAQ,CAAK,EACxB,IAAI,EAAA,OAAO,MAAM,CAAK,EAClB,GAAI,CACA,OAAA,EAAO,EAAA,iBAAA,CAAiB,CAAK,CACjC,MAAQ,CACJ,MACJ,CAEJ,GAAI,EAAA,OAAO,MAAM,CAAK,EAAG,OAAO,CAF5B,CAIR,CAQA,SAAS,GAAkB,EAAyB,EAAuB,EAA+B,EAAyE,CAC/K,GAAM,CAAE,SAAU,EAClB,GAAI,CAAC,EAAO,OACZ,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAO,CACtB,IAAI,EACE,EAAQ,EAAc,EAAK,OAAO,KAAK,EAK7C,GAJI,IAAO,EAAQ,EAAA,QAAO,IAAI,EAAO,CAAa,GAC9C,EAAA,OAAO,WAAW,CAAS,IAAG,EAAQ,EAAU,CAAK,GACrD,EAAA,OAAO,QAAQ,CAAK,IAAG,EAAQ,IAAA,IACnC,EAAO,IAAI,CAAK,EACZ,EAAO,KAAO,EAAG,KACzB,CACI,OAAO,MAAQ,GACnB,IAAI,EAAO,OAAS,EAAG,OAAO,EAAO,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MACrD,IAAuB,EAAI,CAD0B,CAGzD,CAGA,IAAI,EAME,GAAsB,EAAA,QAAO,SAAS,UAAkB,CAC1D,IAAM,EAAU,EAEhB,GADA,EAAoB,IAAA,GAChB,CAAC,EAAS,OACd,GAAM,CAAE,QAAO,eAAgB,EACzB,EAA+B,EAAM,cACrC,CAAE,SAAU,EAClB,GAAI,CAAC,GAAS,EAAM,QAAU,EAAG,OACjC,IAAM,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAQ,EAAO,CACtB,IAAM,EAAQ,EAAc,EAAK,OAAO,KAAK,GAAK,CAAC,EAC7C,EAAgC,CAAC,EACvC,IAAK,IAAM,KAAY,EACnB,EAAS,GAAY,EAAA,QAAO,IAAI,EAAO,CAAQ,EAEnD,EAAQ,KAAK,CACT,OAAQ,EAAK,GAEb,UAAW,QACX,WACA,SAAU,CAAE,GAAG,CAAY,EAC3B,OAAQ,EAAQ,IAAW,CACvB,IAAM,EAAc,EAAc,EAAO,OAAO,KAAK,GAAK,CAAC,EAC3D,IAAK,IAAM,KAAY,EAAQ,CAC3B,IAAM,EAAQ,EAAO,GACjB,EAAA,OAAO,QAAQ,CAAK,GAAM,EAAA,OAAO,MAAM,CAAK,GAAK,EAAA,QAAO,KAAK,CAAK,CAAC,CAAC,QAAU,EAC9E,EAAA,QAAO,MAAM,EAAa,CAAQ,EAElC,EAAA,QAAO,IAAI,EAAa,EAAU,CAAK,CAE/C,CACA,EAAO,MAAM,MAAQ,CACzB,CACJ,CAAC,CACL,CACI,EAAQ,QAAU,GACtB,EAAc,aAAa,QAAQ,IAAI,EAAmB,EAAe,OAAQ,CAAE,SAAQ,CAAC,CAAC,CACjG,EAAA,GAAyB,EAOzB,SAAS,GAAW,EAAyB,EAAwC,EAC7E,CAAC,GAAqB,EAAkB,QAAU,KAE9C,GAAmB,GAAoB,MAAM,EACjD,EAAoB,CAAE,QAAO,YAAa,CAAC,CAAE,GAEjD,OAAO,OAAO,EAAkB,YAAa,CAAW,EACxD,GAAoB,CACxB,CAMA,SAAS,GAAW,EAAyB,EAA+B,CACxE,GAAM,CAAE,gBAAe,SAAU,EACjC,GAAI,CAAC,GAAS,EAAM,QAAU,EAAG,OACjC,IAAM,EAAU,EAAA,QAAO,KAAK,GAAO,EAAE,EAC/B,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAQ,EAAO,CAElB,EAAA,OAAO,QAAQ,EAAK,UAAU,aAAa,IAC3C,EAAK,UAAU,cAAgB,EAAK,MAAM,OAAS,IAGvD,IAAM,EAAW,CADA,EAAA,QAAO,KAAK,EAAK,UAAU,aAC1B,EAAU,CAAO,CAAC,CAAC,OAAO,GAAQ,EAAK,OAAS,CAAC,CAAC,CAAC,KAAK,GAAG,EACvE,EAAW,EAAK,MAAM,MACxB,EAAA,QAAO,KAAK,GAAY,EAAE,IAAM,GACpC,EAAQ,KAAK,CACT,OAAQ,EAAK,GACb,UAAW,QACX,WACA,SAAU,EAAS,OAAS,EAAI,EAAW,IAAA,GAC3C,OAAQ,EAAQ,IAAU,CACtB,EAAO,MAAM,MAAQ,CACzB,CACJ,CAAC,CACL,CACI,EAAQ,QAAU,GACtB,EAAc,aAAa,QAAQ,IAAI,EAAmB,EAAe,SAAU,CAAE,SAAQ,CAAC,CAAC,CACnG,CAKA,SAAS,GAAe,EAAyB,EAA8E,CAC3H,GAAM,CAAE,SAAU,EAClB,GAAI,CAAC,GAAS,EAAM,SAAW,EAAG,OAClC,IAAM,EAAO,EAAM,GACf,EAAA,OAAO,QAAQ,EAAK,UAAU,aAAa,IAC3C,EAAK,UAAU,cAAgB,EAAK,MAAM,OAAS,IAEvD,IAAM,EAAW,EAAA,QAAO,KAAK,EAAK,UAAU,aAAa,EACnD,EAAa,EAAA,QAAO,KAAK,EAAK,MAAM,OAAO,UAAU,EAAS,MAAM,GAAK,EAAE,EAEjF,OADc,EAAiB,KAAK,GAAQ,EAAK,QAAU,CACpD,CAAA,EAAO,KAClB,iNCnJA,IAAM,EAAQ,EAGR,GAAA,EAAmB,EAAA,SAAA,MACd,CACH,cAAe,EAAM,cACrB,cAAe,EAAM,cAAc,cACnC,MAAO,EAAM,cAAc,WAC/B,EACH,EAGD,SAAS,EAAa,EAA4B,CAC9C,OAAO,GAAS,EAAiB,MAAO,EAAK,QAAQ,CACzD,CAGA,SAAS,EAAe,EAAuB,EAAkB,CAC7D,GAAW,EAAiB,MAAO,EAAG,EAAK,UAAW,CAAM,CAAC,CACjE,CAGA,SAAS,EAAmB,EAA4B,CACpD,MAAO,CACH,cAAe,EAAM,cACrB,cAAe,EAAM,cAAc,cACnC,MAAO,EAAM,cAAc,YAE3B,cAAgB,GAAgB,EAAa,CAAI,EACjD,iBAAkB,EAAa,KAC3B,EAAe,EAAM,CAAK,EACnB,IAEX,GAAI,EAAK,MAAQ,eAAiB,CAAE,QAAS,EAAK,OAAQ,EAAI,CAAC,CACnE,CACJ,CAGA,SAAS,EAAa,EAAkB,CACpC,OAAO,EAAM,cAAc,eAAe,gBAAgB,aAAa,CAAG,CAC9E,gBAII,EAAA,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAWM,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CAXqB,EAAM,MAAM,OAA1B,EAAM,MAAnB,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAWM,MAAA,CAXyC,IAAK,EAAK,SAAW,EAAK,MAAM,qBAC3E,EAAA,EAAA,EAAA,EAAA,mBAAA,CAEM,MAFN,GAEM,EAAA,EADF,EAAA,mBAAA,CAAoD,OAAA,CAA7C,MAAO,EAAK,QAAa,GAAA,EAAA,EAAA,gBAAA,CAAA,EAAK,KAAK,EAAA,EAAA,EAAA,CAAA,CAAA,GAAA,EAE9C,EAAA,mBAAA,CAMM,MANN,GAMM,CAHQ,EAAa,EAAK,GAAG,IAAA,EAF/B,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAIE,EAAA,wBAAA,CAHO,EAAa,EAAK,GAAG,CAAA,GAAA,EAD9B,EAAA,WAAA,CAIE,iBADU,EAAA,EAAmB,CAAI,CAAA,EAAA,KAAA,EAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,CAAA,CAAA,CAAA,CAAA,uSElD/C,IAAM,EAAQ,EAGR,GAAA,EAAmB,EAAA,SAAA,MACd,CACH,cAAe,EAAM,cACrB,cAAe,EAAM,cAAc,cACnC,MAAO,EAAM,cAAc,WAC/B,EACH,EAGK,GAAA,EAAe,EAAA,SAAA,KAAoC,CACrD,IAAM,EAAO,EAAM,cAAc,WAEjC,OADK,EACE,EAAc,EAAK,OAAO,KAAK,GAAK,CAAC,EAD1B,CAAC,CAEvB,CAAC,EAGK,GAAA,EAAgB,EAAA,SAAA,KAAwC,CAC1D,IAAM,EAAU,EAAM,YAAc,CAAC,EAC/B,EAAQ,EAAa,MAC3B,OAAO,GAAkB,OAAO,GAE5B,EADI,EAAM,YAAe,EAAgB,EAAM,aAC3C,EAAM,SAAW,CAAC,EAAM,QAAQ,CAAK,EAE5C,CACL,CAAC,EAGK,GAAA,EAAwB,EAAA,SAAA,KACnB,EAAM,cAAc,uBAAuB,OAAO,OAAO,iBAAiB,IAAI,IAAS,CAC1F,MAAO,EAAK,MACZ,MAAO,EAAK,IAChB,EAAE,GAAK,CAAC,CACX,EAGK,GAAA,EAAc,EAAA,SAAA,KAAe,GAC/B,EAAiB,MACjB,EAAM,cAAc,uBAAuB,OAAO,OAAO,iBAAmB,CAAC,CACjF,CAAC,EAGD,SAAS,EAAc,EAA+B,CAClD,GAAW,EAAiB,MAAO,CAAG,CAC1C,CAEA,IAAM,GAAA,EAAgB,EAAA,SAAA,KAClB,EAAc,MAAM,IAAI,IAAU,CAC9B,IAAK,EAAM,MACX,MAAO,EAAM,MACb,SAAA,EAAS,EAAA,EAAA,CAAE,GAAkB,CAAE,cAAe,EAAM,cAAe,OAAM,CAAC,CAC9E,EAAE,CACN,EAGM,GAAA,EAAa,EAAA,SAAA,CAAS,CACxB,SAAY,EAAM,cAAc,iBAAiB,aAAa,OAAS,CAAC,EAAA,CAAG,MAAM,EACjF,IAAM,GAAyB,CAC3B,EAAM,cAAc,iBAAiB,aAAe,CAChD,GAAG,EAAM,cAAc,iBAAiB,aACxC,MAAO,CACX,CACJ,CACJ,CAAC,SAED,EAAA,EAAA,MAAA,KAAY,EAAM,cAAc,0BAA6B,CACzD,EAAM,cAAc,iBAAiB,mBAAmB,CAC5D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAkBM,MAlBN,GAkBM,CAjBY,EAAM,cAAc,kBAClC,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAeW,EAAA,SAAA,CAAA,IAAA,CAAA,EAAA,CAbI,EAAA,MAAsB,OAAM,IAAA,EAAvC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAWM,MAXN,GAWM,CAVF,AAAA,EAAA,MAAA,EAAA,EAAA,mBAAA,CAAkD,MAAA,CAA7C,MAAM,4BAA4B,EAAC,OAAI,EAAA,GAAA,EAC5C,EAAA,mBAAA,CAQM,MARN,GAQM,EAAA,EAPF,EAAA,YAAA,EAAA,EAME,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CALE,WAAA,GACA,YAAY,OACX,QAAS,EAAA,MACT,MAAO,EAAA,OAAe,IAAA,GACtB,SAAQ,CAIrB,EAAA,KAAA,EAAA,CAAA,UAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAAqF,EAAA,MAAA,CAAA,EAAA,QAAA,EAAA,CAAnE,UAAW,EAAA,MAAA,qBAAA,AAAA,EAAA,KAAA,GAAA,EAAU,MAAA,EAAE,MAAA,GAAM,KAAK,QAAS,MAAO,EAAA,6CAftC,EAAlC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAA6E,EAAA,MAAA,CAAA,EAAA,KAAA,EAAA,OAA1B,YAAY,WAC/D,CAAA,obE3ER,IAAM,EAAQ,EASR,EAA2E,CAC7E,CACI,MAAO,OACP,MAAO,CACH,CAAE,KAAM,QAAS,YAAa,IAAK,EACnC,CAAE,KAAM,WAAY,YAAa,IAAK,EACtC,CAAE,KAAM,aAAc,YAAa,IAAK,EACxC,CAAE,KAAM,aAAc,YAAa,IAAK,EACxC,CAAE,KAAM,YAAa,YAAa,IAAK,EACvC,CAAE,KAAM,UAAW,YAAa,IAAK,CACzC,CACJ,EACA,CACI,MAAO,OACP,MAAO,CACH,CAAE,KAAM,UAAW,YAAa,IAAK,EACrC,CAAE,KAAM,QAAS,YAAa,IAAK,CACvC,CACJ,CACJ,EAEM,GAAA,EAAQ,EAAA,SAAA,KAAmC,EAAM,cAAc,WAAW,EAG1E,GAAA,EAAc,EAAA,SAAA,KAA4D,CAC5E,IAAM,EAAsD,CAAC,EACvD,EAAa,EAAM,YAAY,OACjC,GAAc,EAAW,OAAS,GAAG,EAAO,KAAK,GAAG,CAAiB,EACzE,IAAM,EAAU,EAAM,YAAY,mBAClC,GAAI,EAAM,YAAY,qBAAuB,GACzC,IAAK,IAAM,KAAS,EACZ,GAAS,SAAS,EAAM,KAAK,GACjC,EAAO,KAAK,CAAK,EAGzB,OAAO,CACX,CAAC,EAGK,GAAA,EAAe,EAAA,SAAA,CAAwD,CACzE,MAAO,GACP,KAAM,GACN,IAAK,EACT,CAAC,EAGD,SAAS,EAAc,EAA2B,CAC9C,OAAA,EAAO,EAAA,iBAAA,CAAiB,CAAS,CACrC,CAGA,SAAS,EAAY,EAAwB,CACzC,IAAM,EAAM,EAAc,CAAS,EAC7B,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAM,MACrB,EAAO,IAAI,EAAK,UAAU,EAAI,EAE9B,KAAO,OAAS,EACpB,OAAO,EAAO,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAClC,CAGA,SAAS,EAAQ,EAA4B,CAEzC,MAAO,CAAC,CADS,EAAY,CACpB,CAAA,EAAU,OACvB,CAGA,SAAS,EAAa,EAA2B,CAE7C,IAAM,EADW,EAAY,CACb,CAAA,EAAU,QAC1B,GAAI,CAAC,EAAA,OAAO,MAAM,CAAO,EAAG,MAAO,GACnC,GAAI,CACA,IAAM,EAAS,EAAQ,SAAS,EAC1B,EAAU,EAAO,MAAM,gBAAgB,EAC7C,OAAO,EAAU,EAAQ,EAAE,CAAC,KAAK,EAAI,CACzC,MAAQ,CACJ,MAAO,EACX,CACJ,CAGA,SAAS,EAAU,EAAyB,CACxC,EAAa,MAAQ,EACrB,EAAa,KAAO,EAAa,CAAS,GAAK,6BAC/C,EAAa,IAAM,CAAC,EAAQ,CAAS,CACzC,CAOA,SAAS,GAAiB,CACtB,IAAM,EAAY,EAAa,MAC/B,GAAI,CAAC,EAAW,OAChB,IAAM,EAA+B,EAAM,cAC3C,GAAI,CAAC,EAAc,cAAe,OAClC,IAAM,EAAO,EAAA,QAAO,KAAK,EAAa,IAAI,EACtC,EACJ,GAAI,CACI,EAAK,OAAS,IAAG,GAAA,EAAU,EAAA,UAAA,CAAU,CAAE,MAAK,CAAC,EACrD,OAAS,EAAK,CACV,QAAQ,KAAK,wBAAyB,CAAG,EACzC,MACJ,CACA,IAAM,EAAM,EAAc,CAAS,EAC7B,EAAwC,CAAC,EAC/C,IAAK,IAAM,KAAQ,EAAM,MAAO,CAC5B,IAAM,EAAc,EAAK,UAAU,GAE/B,GAAW,GAAa,SACrB,SAAS,UAAU,SAAS,KAAK,EAAY,OAAO,IAAM,SAAS,UAAU,SAAS,KAAK,CAAO,GACzG,EAAQ,KAAK,CACT,OAAQ,EAAK,GACb,MAAO,EACP,cACA,YAAa,EAAU,CAAE,SAAQ,EAAI,IAAA,EACzC,CAAC,CACL,CACA,EAAa,MAAQ,GACjB,EAAQ,OAAS,GACjB,EAAc,aAAa,QAAQ,IAAI,EAAuB,EAAe,QAAQ,IAAa,CAAE,SAAQ,CAAC,CAAC,CAEtH,CAGA,SAAS,EAAW,EAAyB,CACzC,IAAM,EAA+B,EAAM,cAC3C,GAAI,CAAC,EAAc,cAAe,OAClC,IAAM,EAAM,EAAc,CAAS,EAC7B,EAAwC,CAAC,EAC/C,IAAK,IAAM,KAAQ,EAAM,MAAO,CAC5B,IAAM,EAAc,EAAK,UAAU,GAC9B,GACL,EAAQ,KAAK,CACT,OAAQ,EAAK,GACb,MAAO,EACP,cACA,YAAa,IAAA,EACjB,CAAC,CACL,CACI,EAAQ,OAAS,GACjB,EAAc,aAAa,QAAQ,IAAI,EAAuB,EAAe,QAAQ,IAAa,CAAE,SAAQ,CAAC,CAAC,CAEtH,gBAKI,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAiCM,MAAA,CAjCA,IAAK,EAAM,cAAc,iBAAiB,aAAc,MAAM,sBAClD,EAAA,CAAA,EAAM,cAAc,kBAClC,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CA8BW,EAAA,SAAA,CAAA,IAAA,CAAA,EAAA,GAAA,EA7BP,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAaM,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CAbe,EAAA,MAAT,KAAZ,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAaM,MAAA,CAb6B,IAAK,EAAM,MAAO,MAAM,sBACvD,EAAA,EAAA,EAAA,EAAA,mBAAA,CAA+D,MAA/D,IAAA,EAA+D,EAAA,gBAAA,CAApB,EAAM,KAAK,EAAA,CAAA,IAAA,EACtD,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAUM,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CAVc,EAAM,MAAd,KAAZ,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAUM,MAAA,CAV4B,IAAK,EAAK,KAAM,MAAM,qBACpD,EAAA,EAAA,EAAA,EAAA,mBAAA,CAGM,MAHN,GAGM,EAAA,EAFC,EAAA,gBAAA,EAAA,EAAA,EAAA,gBAAA,CAAA,EAAK,aAAe,EAAK,IAAI,EAAG,IACnC,CAAA,GAAA,EAAA,EAAA,mBAAA,CAAuD,OAAvD,IAAA,EAAuD,EAAA,gBAAA,CAAnB,EAAK,IAAI,EAAA,CAAA,CAAA,CAAA,GAAA,EAEjD,EAAA,mBAAA,CAIM,MAJN,GAIM,CAHS,EAAQ,EAAK,IAAI,IAAA,EAA5B,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAAgF,EAAA,MAAA,CAAA,EAAA,GAAA,EAAA,OAAjD,MAAM,OAAO,MAAM,uBAAqB,SAAA,EAAA,EAAA,QAAA,KAAG,CAAA,GAAA,AAAA,EAAA,KAAA,EAAA,EAAH,EAAA,gBAAA,CAAA,MAAG,EAAA,CAAA,CAAA,CAAA,0CAC1E,EAAA,EAAA,YAAA,EAAA,EAA8G,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAAtG,KAAK,QAAQ,KAAK,OAAQ,QAAK,GAAE,EAAU,EAAK,IAAI,IAAG,SAAA,EAAA,EAAA,QAAA,KAAsC,EAAA,EAAnC,EAAA,gBAAA,EAAA,EAAA,EAAA,gBAAA,CAAA,EAAQ,EAAK,IAAI,EAAA,KAAA,IAAA,EAAA,CAAA,CAAA,CAAA,yBACrE,EAAQ,EAAK,IAAI,IAAA,EAA/B,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAA4G,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,OAA1E,KAAK,QAAQ,KAAK,OAAO,OAAA,GAAQ,QAAK,GAAE,EAAW,EAAK,IAAI,IAAG,SAAA,EAAA,EAAA,QAAA,KAAE,CAAA,GAAA,AAAA,EAAA,KAAA,EAAA,EAAF,EAAA,gBAAA,CAAA,KAAE,EAAA,CAAA,CAAA,CAAA,qEAKpG,EAAA,GAAA,GAAA,EAAa,QAAA,EAAxB,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAaM,MAbN,GAaM,EAZF,EAAA,EAAA,mBAAA,CAEM,MAFN,GAEM,CAFmC,AAAA,EAAA,MAAA,EAAA,EAAA,gBAAA,CAAA,YAC7B,EAAA,GAAA,EAAA,EAAA,mBAAA,CAA+B,IAAA,MAAA,EAAA,EAAA,gBAAA,CAAzB,EAAa,KAAK,EAAA,CAAA,CAAA,CAAA,GAEpC,EAAA,EAAA,eAAA,EAAA,EAAA,EAAA,mBAAA,CAIY,WAAA,CAHR,MAAM,0BACG,sBAAA,AAAA,EAAA,KAAA,GAAA,EAAa,KAAI,EAC1B,YAAY,gDADH,EAAA,KAAA,GAAA,EAAA,CAAA,CAAA,EAAA,WAAA,EAAa,IAAI,CAAA,CAAA,GAG9B,EAAA,EAAA,mBAAA,CAGM,MAHN,GAGM,EAAA,EAFF,EAAA,YAAA,EAAA,EAAiE,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAAzD,KAAK,QAAQ,KAAK,UAAW,QAAO,IAAU,SAAA,EAAA,EAAA,QAAA,KAAE,CAAA,GAAA,AAAA,EAAA,KAAA,EAAA,EAAF,EAAA,gBAAA,CAAA,KAAE,EAAA,CAAA,CAAA,CAAA,KACxD,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAAiE,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAAzD,KAAK,QAAS,QAAK,AAAA,EAAA,KAAA,GAAE,EAAa,MAAK,KAAO,SAAA,EAAA,EAAA,QAAA,KAAE,CAAA,GAAA,AAAA,EAAA,KAAA,EAAA,EAAF,EAAA,gBAAA,CAAA,KAAE,EAAA,CAAA,CAAA,CAAA,qDA5BlC,EAAlC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAA6E,EAAA,MAAA,CAAA,EAAA,KAAA,EAAA,OAA1B,YAAY,WAC/D,CAAA,uiBEhKR,IAAM,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,KAAmC,EAAM,cAAc,WAAW,EAMhF,SAAS,EAAa,EAAuF,CACzG,IAAM,EAAU,EAAA,QAAO,KAAK,CAAG,CAAC,CAAC,MAAM,qBAAqB,EAC5D,GAAI,CAAC,EAAS,OACd,IAAM,EAAU,EAAA,QAAO,KAAK,EAAQ,EAAE,CAAC,CAAC,QAAQ,aAAc,IAAI,EAC5D,EAAO,EAAA,QAAO,KAAK,EAAQ,EAAE,EAC7B,EAAO,EAAQ,MAAM,GAAG,CAAC,CAAC,IAAI,GAAW,EAAA,QAAO,KAAK,CAAO,CAAC,CAAC,CAAC,OAAO,GAAW,EAAQ,OAAS,CAAC,EACrG,OAAK,QAAU,GAAK,EAAK,QAAU,GACvC,MAAO,CAAE,OAAM,KAAM,EAAK,GAAI,IAAK,EAAK,GAAI,MAAO,EAAK,EAAG,CAC/D,CAGA,SAAS,EAAU,EAA2B,CAC1C,GAAI,EAAA,OAAO,MAAM,CAAY,EAAG,OAAO,EACvC,GAAI,CAAC,EAAA,OAAO,MAAM,CAAY,EAAG,MAAO,GACxC,IAAM,EAAO,CAAC,EAAa,KAAM,EAAa,IAAK,EAAa,KAAK,CAAA,CAChE,OAAQ,GAAiB,EAAA,OAAO,MAAM,CAAO,GAAK,EAAA,QAAO,KAAK,CAAO,CAAC,CAAC,OAAS,CAAC,CAAA,CACjF,IAAK,GAAoB,EAAA,QAAO,KAAK,CAAO,CAAC,EAC5C,EAAO,EAAA,OAAO,MAAM,EAAa,IAAI,EAAI,EAAA,QAAO,KAAK,EAAa,IAAI,EAAI,GAEhF,OADI,EAAK,QAAU,GAAK,EAAK,QAAU,EAAU,GAC1C,EAAK,OAAS,EAAI,IAAI,EAAK,KAAK,IAAI,EAAE,OAAO,IAAS,GAAG,EAAK,GAAG,MAAM,GAClF,CAGA,SAAS,EAAkB,EAAkC,CAEzD,GAAI,CADU,EAAM,MAAM,GACd,OACZ,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAM,MAAO,CAC5B,IAAM,EAAS,EAAK,WAAmB,GACvC,EAAO,IAAI,EAAA,OAAO,MAAM,CAAK,GAAK,CAAC,EAAA,OAAO,MAAM,CAAK,EAAK,EAAc,MAAQ,CAAK,CACzF,CACI,KAAO,OAAS,EACpB,OAAO,EAAO,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAClC,CAEA,IAAM,GAAA,EAAY,EAAA,SAAA,KAAe,CAI7B,IAAM,EAAO,EAAM,MAAM,GAGzB,MAFA,CAAK,IACS,EAAA,OAAO,MAAM,EAAK,OAAO,KAAK,EAAI,EAAK,MAAM,MAAQ,CAAC,EAAA,CACvD,UAAY,MAC7B,CAAC,EACK,GAAA,EAAU,EAAA,SAAA,KAAe,EAAA,OAAO,MAAM,EAAkB,IAAI,CAAC,EAAI,EAAkB,IAAI,EAAI,OAAO,EAAkB,IAAI,GAAK,EAAE,CAAC,EAChI,GAAA,EAAW,EAAA,SAAA,KAAe,EAAU,EAAkB,KAAK,CAAC,CAAC,EAGnE,SAAS,EAAqB,EAA8B,EAAc,EAAyC,CAC3G,EAAQ,QAAU,GACtB,EAAc,aAAa,QAAQ,IAAI,EAAmB,EAAe,EAAM,CAAE,SAAQ,CAAC,CAAC,CAC/F,CAGA,SAAS,EAAU,EAAwB,CACvC,IAAM,EAA+B,EAAM,cAC3C,GAAI,CAAC,EAAc,cAAe,OAClC,IAAM,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAQ,EAAM,MAAO,CAC5B,IAAM,EAAQ,EAAA,OAAO,MAAM,EAAK,OAAO,KAAK,EAAI,CAAE,GAAG,EAAK,MAAM,KAAM,EAAI,CAAC,EACrE,EAAW,EAAK,MAAM,MACxB,EACI,EAAM,UAAY,QAAQ,OAAO,EAAM,QAE3C,EAAM,QAAU,OAEhB,GAAA,QAAO,QAAQ,EAAU,CAAK,GAClC,EAAQ,KAAK,CACT,OAAQ,EAAK,GACb,UAAW,gBACX,WACA,SAAU,EACV,OAAQ,EAAQ,IAAU,CACtB,EAAO,MAAM,MAAQ,EAAA,OAAO,MAAM,CAAK,EAAI,EAAQ,IAAA,EACvD,CACJ,CAAC,CACL,CACA,EAAqB,EAAe,EAAU,OAAS,OAAQ,CAAO,CAC1E,CAOA,SAAS,EAAe,EAA6B,EAAkB,CACnE,IAAM,EAA+B,EAAM,cAC3C,GAAI,CAAC,EAAc,cAAe,OAClC,IAAM,EAAM,EAAA,QAAO,KAAK,OAAO,GAAS,EAAE,CAAC,EACvC,EACJ,GAAI,IAAS,MACL,IAAA,EAAI,OAAS,IACb,EAAiB,EAAa,CAAG,EAE7B,CAAC,GAAgB,MACzB,KAEA,GAAiB,EAAI,OAAS,EAAI,EAAM,IAAA,GAE5C,IAAM,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAQ,EAAM,MAAO,CAC5B,IAAM,EAAY,EAAK,WAAmB,GACtC,EAAA,QAAO,QAAQ,EAAU,CAAc,GAC3C,EAAQ,KAAK,CACT,OAAQ,EAAK,GACb,UAAW,cAAc,IACzB,WACA,SAAU,EACV,OAAQ,EAAQ,IAAQ,CAChB,EAAA,OAAO,QAAQ,CAAG,EAClB,OAAQ,EAAO,WAAmB,GAElC,EAAQ,WAAmB,GAAQ,CAE3C,CACJ,CAAC,CACL,CACA,EAAqB,EAAe,QAAQ,EAAK,KAAM,CAAO,CAClE,gBAKI,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAsCM,MAAA,CAtCA,IAAK,EAAM,cAAc,iBAAiB,aAAc,MAAM,yBAClD,EAAA,CAAA,EAAM,cAAc,kBAClC,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAmCW,EAAA,SAAA,CAAA,IAAA,CAAA,EAAA,CAjCK,EAAM,eAAe,cAKH,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,IALG,EAAjC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAQM,MARN,GAQM,CAPF,AAAA,EAAA,MAAA,EAAA,EAAA,mBAAA,CAAqD,MAAA,CAAhD,MAAM,yBAAyB,EAAC,aAAU,EAAA,GAAA,EAC/C,EAAA,mBAAA,CAKM,MALN,GAKM,EAAA,EAJF,EAAA,mBAAA,CAGQ,QAHR,GAGQ,EAAA,EAFJ,EAAA,mBAAA,CAAuH,QAAA,CAAhH,KAAK,WAAY,QAAS,EAAA,MAAY,SAAM,AAAA,EAAA,KAAE,GAAS,EAAW,EAAM,OAA4B,OAAO,CAClH,EAAA,KAAA,GAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAA0C,OAAA,MAAA,EAAA,EAAA,gBAAA,CAAjC,EAAA,MAAS,KAAA,IAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAKlB,EAAM,eAAe,6CAAA,EAAjC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAUM,MAVN,GAUM,CATF,AAAA,EAAA,MAAA,EAAA,EAAA,mBAAA,CAAqD,MAAA,CAAhD,MAAM,yBAAyB,EAAC,aAAU,EAAA,GAAA,EAC/C,EAAA,mBAAA,CAOM,MAPN,GAOM,EAAA,EANF,EAAA,mBAAA,CAKY,WAAA,CAJR,MAAM,6BACN,YAAY,4CACX,MAAO,EAAA,MACP,SAAM,AAAA,EAAA,KAAE,GAAS,EAAc,KAAQ,EAAM,OAA+B,KAAK,oBAKlF,EAAM,eAAe,8CAAA,EAAjC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAUM,MAVN,GAUM,CATF,AAAA,EAAA,MAAA,EAAA,EAAA,mBAAA,CAAsD,MAAA,CAAjD,MAAM,yBAAyB,EAAC,cAAW,EAAA,GAAA,EAChD,EAAA,mBAAA,CAOM,MAPN,GAOM,EAAA,EANF,EAAA,mBAAA,CAKY,WAAA,CAJR,MAAM,6BACN,YAAY,kCACX,MAAO,EAAA,MACP,SAAM,AAAA,EAAA,KAAE,GAAS,EAAc,MAAS,EAAM,OAA+B,KAAK,4BAhCjE,EAAlC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAA6E,EAAA,MAAA,CAAA,EAAA,KAAA,EAAA,OAA1B,YAAY,WAC/D,CAAA,waEvIR,IAAM,EAAQ,EAGR,GAAA,EAAa,EAAA,IAAA,CAAY,EAAE,EAG3B,GAAA,EAAc,EAAA,IAAA,CAAmC,CAAC,CAAC,GAGzD,EAAA,EAAA,UAAA,CAAU,SAAY,CAClB,IAAM,EAAQ,IAAI,IACZ,EAAW,GAAuB,CACpC,GAAI,EAAM,IAAI,CAAI,EAAG,OACrB,EAAM,IAAI,CAAI,EAEd,IAAM,EAAe,EAAM,aAAa,GACpC,GAAc,EAAa,QAAQ,GAAc,EAAQ,CAAU,CAAC,CAC5E,EACA,IAAK,IAAM,KAAO,EAAM,cAAgB,CAAC,EACrC,IAAK,IAAM,KAAS,EAAI,OACpB,IAAK,IAAM,KAAQ,EAAM,MACrB,EAAQ,CAAI,EAIpB,OAAM,MAAQ,GAClB,GAAI,CACA,IAAM,EAAW,MAAM,KAAK,CAAK,EAC3B,CAAC,GAAS,MAAM,QAAQ,IAAI,CAC9B,EAAM,cAAc,eAAe,gBAAgB,uBAAuB,CAAQ,EAElF,EAAM,cAAc,eAAe,gBAAgB,mBAAmB,EAAS,OAAO,GAAQ,EAAA,EAAC,EAAA,UAAA,CAAU,CAAI,CAAC,CAAC,CACnH,CAAC,EACD,EAAY,MAAQ,CACxB,OAAS,EAAK,CACV,QAAQ,KAAK,YAAa,CAAG,CACjC,CACJ,CAAC,EAGD,IAAM,GAAA,EAAc,EAAA,SAAA,KAAe,CAC/B,IAAM,GAAW,EAAW,OAAS,GAAA,CAAI,KAAK,CAAC,CAAC,YAAY,EAC5D,OAAQ,EAAM,cAAgB,CAAC,EAAA,CAAG,IAAI,IAAQ,CAC1C,GAAG,EACH,OAAQ,EAAI,OAAO,IAAI,IAAU,CAC7B,GAAG,EACH,MAAO,EAAM,MAAM,IAAI,GAAQ,EAAY,MAAM,EAAK,CAAC,CAAC,OAAO,OAAO,CAC1E,EAAE,CAAC,CAAC,OAAO,GAAS,EAAM,MAAM,OAAS,CAAC,CAAC,CAAC,IAAI,IAAU,CACtD,GAAG,EACH,MAAO,EAAQ,OAAS,EAClB,EAAM,MAAM,OAAO,GAAQ,EAAK,KAAK,YAAY,CAAC,CAAC,SAAS,CAAO,GAAK,EAAK,KAAK,YAAY,CAAC,CAAC,SAAS,CAAO,CAAC,EACjH,EAAM,KAChB,EAAE,CAAC,CAAC,OAAO,GAAS,EAAM,MAAM,OAAS,CAAC,CAC9C,EAAE,CAAC,CAAC,OAAO,GAAO,EAAI,OAAO,OAAS,CAAC,CAC3C,CAAC,EAEK,GAAA,EAAW,EAAA,SAAA,KAAe,EAAY,MAAM,IAAI,IAAQ,CAAE,IAAK,EAAI,MAAO,MAAO,EAAI,KAAM,EAAE,CAAC,iBAIhG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAgCM,MAhCN,GAgCM,EAAA,EA/BF,EAAA,mBAAA,CAOM,MAPN,GAOM,EAAA,EANF,EAAA,YAAA,EAAA,EAKE,EAAA,MAAA,CAAA,EAAA,KAAA,EAAA,CAJU,MAAO,EAAA,MAAA,iBAAA,AAAA,EAAA,KAAA,GAAA,EAAU,MAAA,EACzB,KAAK,QACL,WAAA,GACA,YAAY,MAGR,EAAA,KAAA,EAAA,CAAA,OAAA,CAAA,CAAA,CAAA,EAAA,EAAA,MAAY,OAAM,IAAA,EAA9B,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAqBO,EAAA,MAAA,CAAA,EAAA,IAAA,EAAA,OArB6B,KAAK,QAAQ,MAAM,yBAA0B,MAAO,EAAA,QACzE,eAAA,EAAa,EAAA,QAAA,EACgB,CADZ,UAAI,GAAA,EAC5B,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAiBW,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CAjBa,EAAA,MAAP,KAA0B,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAAA,EAAA,SAAA,CAAA,IAAA,EAAI,KAAA,EAAA,CAChC,EAAI,QAAU,EAAK,MAAA,EAA9B,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAeM,MAAA,GAAA,GAAA,EAdF,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAaM,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CAbe,EAAI,OAAb,KAAZ,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAaM,MAAA,CAb4B,IAAK,EAAM,MAAO,MAAM,yBACtD,EAAA,EAAA,EAAA,EAAA,mBAAA,CAAkE,MAAlE,IAAA,EAAkE,EAAA,gBAAA,CAApB,EAAM,KAAK,EAAA,CAAA,GAAA,EACzD,EAAA,mBAAA,CAUM,MAVN,GAUM,GAAA,EATF,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAQM,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CAPa,EAAM,MAAd,KADX,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAQM,MAAA,CAND,IAAK,EAAK,KACX,MAAM,0BACL,sBAAqB,EAAK,KAC1B,MAAO,EAAK,IAEV,GAAA,EAAA,EAAA,gBAAA,CAAA,EAAK,IAAI,EAAA,EAAA,EAAA,2EAQxC,EAAA,EAAA,CAAA,OAAA,CAAA,KAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAA6D,MAA7D,GAA4C,aAAW,EAAA,CAAA,qLE9F/D,IAAM,EAAQ,EAUd,SAAS,EAAe,EAAyC,EAAgB,EAA2B,CACxG,GAAI,EAAQ,GAAI,MAAO,CAAC,EACxB,IAAM,EAAiC,CAAC,EACxC,IAAK,IAAM,KAAQ,EAAO,CACtB,GAAI,CAAC,EAAA,OAAO,MAAM,CAAI,GAAK,EAAA,OAAO,QAAQ,CAAI,EAAG,SACjD,IAAM,EAAO,EACP,EAAO,EAAM,cAAc,eAAe,gBAAgB,iBAAiB,EAAK,IAAI,EACpF,EAAmC,CAAC,EAE1C,EAAS,KAAK,GAAG,EAAe,EAAK,OAAS,CAAC,EAAG,EAAQ,CAAC,CAAC,EAC5D,IAAK,IAAM,KAAY,EAAK,MAAO,CAC/B,IAAM,EAAe,EAAe,EAAK,MAAM,IAAa,CAAC,EAAG,EAAQ,CAAC,EACrE,EAAa,OAAS,GACtB,EAAS,KAAK,GAAG,CAAY,CAErC,CACA,EAAO,KAAK,CACR,MAAO,GAAM,MAAQ,EAAK,KAC1B,IAAK,EAAK,GACV,SAAU,EAAS,OAAS,EAAI,EAAW,IAAA,EAC/C,CAAC,CACL,CACA,OAAO,CACX,CAGA,IAAM,GAAA,EAAW,EAAA,SAAA,KAAuC,CAEpD,IAAM,EADgB,EAAM,cAAc,eACN,cAAc,aAElD,OADK,EACE,EAAe,EAAa,OAAS,CAAC,CAAC,EADpB,CAAC,CAE/B,CAAC,EAGK,GAAA,EAAe,EAAA,SAAA,KACV,EAAM,cAAc,WAAW,IAAI,GAAa,EAAU,MAAO,CAAC,CAAC,OAAO,OAAO,CAC3F,EAGD,SAAS,EAAS,EAA2B,CACrC,EAAK,SAAW,GAChB,EAAM,cAAc,gBAAgB,CAAC,EAAK,EAAE,CAAC,CAErD,gBAII,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAUM,MAVN,GAUM,CATW,EAAA,MAAS,QAAM,IAAA,EAA5B,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAAwD,EAAA,MAAA,CAAA,EAAA,KAAA,EAAA,OAArB,YAAY,MAC/C,CAAA,KAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAOE,EAAA,MAAA,CAAA,EAAA,IAAA,EAAA,OALE,aAAA,GACC,YAAW,EAAA,MACX,gBAAe,EAAA,MAChB,qBAAA,GACS,6mBEnDrB,IAAM,EAAQ,EAER,GAAA,EAAS,EAAA,SAAA,KAAe,EAAM,cAAc,cAAc,EAE1D,GAAA,EAAc,EAAA,IAAA,CAAa,EAAK,EAEhC,GAAA,EAAU,EAAA,IAAA,CAAY,UAAU,EAEhC,GAAA,EAAW,EAAA,IAAA,CAAY,OAAO,EAGpC,SAAS,GAAe,CACpB,EAAM,cAAc,aAAa,KAAK,EACtC,EAAM,cAAc,gBAAgB,CACxC,CAGA,SAAS,GAAe,CACpB,EAAM,cAAc,aAAa,KAAK,EACtC,EAAM,cAAc,gBAAgB,CACxC,CAGA,SAAS,GAAiB,CACtB,IAAM,EAAU,EAAM,cAAc,WAAW,IAAI,GAAa,EAAU,MAAO,CAAC,CAAC,OAAO,OAAO,EACjG,GAAI,EAAQ,QAAU,EAAG,OACzB,IAAM,EAAU,IAAI,EAAmB,EAAM,cAAe,MAAM,EAAQ,OAAO,MAAO,CACpF,UACA,cAAiB,EAAM,cAAc,gBAAgB,CACzD,CAAC,EACD,EAAM,cAAc,aAAa,QAAQ,CAAO,CACpD,CAGA,SAAS,GAAgB,CAErB,IAAM,EADgB,EAAM,cAAc,eACN,cAAc,aAClD,GAAI,CAAC,EAAc,OACnB,IAAM,GAAW,EAAa,OAAS,CAAC,EAAA,CACnC,OAAQ,GAA8B,CAAC,CAAC,GAAQ,OAAO,GAAS,UAAY,CAAC,MAAM,QAAQ,CAAI,CAAC,CAAA,CAChG,IAAI,GAAQ,EAAK,EAAE,EACxB,GAAI,EAAQ,QAAU,EAAG,CACrB,EAAA,QAAQ,KAAK,SAAS,EACtB,MACJ,CACA,IAAM,EAAU,IAAI,EAAmB,EAAM,cAAe,OAAQ,CAChE,UACA,cAAiB,EAAM,cAAc,gBAAgB,CACzD,CAAC,EACD,EAAM,cAAc,aAAa,QAAQ,CAAO,CACpD,CAGA,IAAM,GAAA,EAAa,EAAA,SAAA,KAAe,EAAM,cAAc,uBAAuB,QAAQ,KAAK,EACpF,GAAA,EAAa,EAAA,SAAA,KAAe,EAAM,cAAc,uBAAuB,QAAQ,KAAK,EACpF,GAAA,EAAa,EAAA,SAAA,KAAe,EAAM,cAAc,uBAAuB,QAAQ,MAAM,EACrF,GAAA,EAAgB,EAAA,SAAA,KAAe,EAAM,cAAc,uBAAuB,QAAQ,QAAQ,EAG1F,GAAA,EAAe,EAAA,SAAA,KAAwC,CACzD,GAAI,CAAC,EAAY,MAAO,OACxB,IAAM,EAAe,EAAM,cAAc,eAAe,cAAc,aACtE,OAAO,EAAgB,EAAwB,CAAY,EAA+B,IAAA,EAC9F,CAAC,iBAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CA0EM,MA1EN,GA0EM,EAxEF,EAAA,EAAA,mBAAA,CA+BM,MA/BN,GA+BM,EA9BF,EAAA,EAAA,mBAAA,CAqBM,MArBN,GAqBM,EApBF,EAAA,EAAA,YAAA,EAAA,EAIU,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAJD,MAAM,WAAW,EAAA,CACtB,SAAA,EAAA,EAAA,QAAA,KAES,EAAA,EAFT,EAAA,YAAA,EAAA,EAES,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAFD,KAAK,QAAQ,KAAK,OAAQ,SAAQ,CAAG,EAAA,cAAc,aAAa,SAAW,EAAA,MAAc,QAAO,IACpG,SAAA,EAAA,EAAA,QAAA,KAAgB,EAAA,EAAhB,EAAA,YAAA,EAAA,EAAgB,EAAA,MAAA,CAAA,EAAA,YAAA,CAAA,CAAA,CAAA,gCAGxB,EAAA,EAAA,YAAA,EAAA,EAIU,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAJD,MAAM,WAAW,EAAA,CACtB,SAAA,EAAA,EAAA,QAAA,KAES,EAAA,EAFT,EAAA,YAAA,EAAA,EAES,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAFD,KAAK,QAAQ,KAAK,OAAQ,SAAQ,CAAG,EAAA,cAAc,aAAa,SAAW,EAAA,MAAc,QAAO,IACpG,SAAA,EAAA,EAAA,QAAA,KAAgB,EAAA,EAAhB,EAAA,YAAA,EAAA,EAAgB,EAAA,MAAA,CAAA,EAAA,YAAA,CAAA,CAAA,CAAA,gCAGxB,EAAA,EAAA,YAAA,EAAA,EAIU,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAJD,MAAM,aAAa,EAAA,CACxB,SAAA,EAAA,EAAA,QAAA,KAES,EAAA,EAFT,EAAA,YAAA,EAAA,EAES,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAFD,KAAK,QAAQ,KAAK,OAAO,OAAA,GAAQ,SAAQ,CAAG,EAAA,cAAc,iBAAmB,EAAA,MAAc,QAAO,IACtG,SAAA,EAAA,EAAA,QAAA,KAAkB,EAAA,EAAlB,EAAA,YAAA,EAAA,EAAkB,EAAA,MAAA,CAAA,EAAA,cAAA,CAAA,CAAA,CAAA,gCAG1B,EAAA,EAAA,YAAA,EAAA,EAIU,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAJD,MAAM,MAAM,EAAA,CACjB,SAAA,EAAA,EAAA,QAAA,KAES,EAAA,EAFT,EAAA,YAAA,EAAA,EAES,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAFD,KAAK,QAAQ,KAAK,OAAO,OAAA,GAAQ,SAAU,EAAA,MAAc,QAAO,IACpE,SAAA,EAAA,EAAA,QAAA,KAAiB,EAAA,EAAjB,EAAA,YAAA,EAAA,EAAiB,EAAA,MAAA,CAAA,EAAA,aAAA,CAAA,CAAA,CAAA,iCAI7B,AAAA,EAAA,MAAA,EAAA,EAAA,mBAAA,CAA4D,MAAA,CAAvD,MAAM,kCAAkC,EAAC,WAAQ,EAAA,GACtD,EAAA,EAAA,mBAAA,CAMM,MANN,GAMM,EAAA,EALF,EAAA,YAAA,EAAA,EAIS,EAAA,MAAA,CAAA,EAAA,MAAA,EAAA,CAJD,KAAK,QAAS,KAAM,EAAA,MAAW,UAAA,UAA2B,QAAK,AAAA,EAAA,KAAA,GAAE,EAAA,MAAW,CAAI,EAAA,QACpF,SAAA,EAAA,EAAA,QAAA,KAAmC,CAAf,EAAA,QAAe,EACnC,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAAuB,EAAA,MAAA,CAAA,EAAA,YAAA,EAAA,CAAA,IAAA,CAAA,CAAA,KADH,EAApB,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAAmC,EAAA,MAAA,CAAA,EAAA,WAAA,EAAA,CAAA,IAAA,CAAA,CAAA,IACZ,EAAA,EAAA,gBAAA,CAAA,KAAA,EACvB,EAAA,gBAAA,CAAG,EAAA,MAAW,KAAA,IAAA,EAAA,CAAA,CAAA,CAAA,wBAK1B,EAAA,EAAA,mBAAA,CAqCM,MArCN,GAqCM,EAnCF,EAAA,EAAA,mBAAA,CAOM,MAPN,GAOM,EAAA,EANF,EAAA,YAAA,EAAA,EACoF,EAAA,MAAA,CAAA,EAAA,IAAA,EAAA,CADtE,UAAW,EAAA,MAAA,qBAAA,AAAA,EAAA,KAAA,GAAA,EAAO,MAAA,EAAE,KAAK,QAAQ,MAAM,+BAC9C,MAAO,CAAA,CAAA,IAAA,WAAA,MAAA,IAAA,EAAA,CAAA,IAAA,UAAA,MAAA,IAAA,CAAA,CACd,EAAA,KAAA,EAAA,CAAA,WAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAGM,MAHN,GAGM,EAAA,EAFF,EAAA,eAAA,EAAA,EAAA,EAAA,YAAA,CAAmH,GAAA,CAAnE,cAAe,EAAA,cAAgB,aAAc,EAAM,YAA5E,EAAA,KAAA,EAAA,CAAA,gBAAA,cAAA,CAAA,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,QAAO,UAAA,CAAA,CAAA,GAAA,EAC9B,EAAA,eAAA,EAAA,EAAA,EAAA,YAAA,CAA8E,GAAA,CAAhC,cAAe,EAAA,aAAa,EAAA,KAAA,EAAA,CAAA,eAAA,CAAA,EAAA,CAApD,CAAA,EAAA,MAAA,EAAA,QAAO,SAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAIrC,EAAA,EAAA,mBAAA,CASM,MATN,GASM,CARmB,EAAA,QACrB,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAME,EAAA,MAAA,CAAA,EAAA,cAAA,EAAA,OAJE,MAAM,6BACL,gBAAiB,EAAA,MAAO,gBACxB,MAAO,EAAA,MACP,YAAa,2CANG,EAArB,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,CAAwF,GAAA,OAArD,cAAe,EAAA,cAAgB,MAAO,EAAM,KAC/E,EAAA,KAAA,EAAA,CAAA,gBAAA,OAAA,CAAA,MASJ,EAAA,EAAA,mBAAA,CAcM,MAdN,GAcM,EAAA,EAbF,EAAA,YAAA,EAAA,EAMU,EAAA,MAAA,CAAA,EAAA,IAAA,EAAA,CANI,UAAW,EAAA,MAAA,qBAAA,AAAA,EAAA,KAAA,GAAA,EAAQ,MAAA,EAAE,KAAK,QAAQ,MAAM,gCAC/C,MAAO,wGAKP,CACP,EAAA,KAAA,EAAA,CAAA,WAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAKM,MALN,GAKM,EAJF,EAAA,EAAA,eAAA,EAAA,EAAA,EAAA,YAAA,CAA0G,GAAA,CAAzD,cAAe,EAAA,cAAgB,WAAY,EAAA,KAAlE,EAAA,KAAA,EAAA,CAAA,gBAAA,YAAA,CAAA,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,QAAQ,OAAA,CAAA,CAAA,GAClC,EAAA,EAAA,eAAA,EAAA,EAAA,EAAA,YAAA,CAA0G,GAAA,CAAzD,cAAe,EAAA,cAAgB,WAAY,EAAA,KAAlE,EAAA,KAAA,EAAA,CAAA,gBAAA,YAAA,CAAA,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,QAAQ,OAAA,CAAA,CAAA,GAClC,EAAA,EAAA,eAAA,EAAA,EAAA,EAAA,YAAA,CAA2G,GAAA,CAAzD,cAAe,EAAA,cAAgB,WAAY,EAAA,KAAnE,EAAA,KAAA,EAAA,CAAA,gBAAA,YAAA,CAAA,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,QAAQ,QAAA,CAAA,CAAA,GAClC,EAAA,EAAA,eAAA,EAAA,EAAA,EAAA,YAAA,CAAsH,GAAA,CAA/D,cAAe,EAAA,cAAgB,cAAe,EAAA,KAAxE,EAAA,KAAA,EAAA,CAAA,gBAAA,eAAA,CAAA,EAAA,CAAA,CAAA,EAAA,MAAA,EAAA,QAAQ,UAAA,CAAA,CAAA,SAIjD,EAAA,EAAA,YAAA,CAAsC,GAAA,CAA1B,eAAgB,EAAA,KAAM,EAAA,KAAA,EAAA,CAAA,gBAAA,CAAA,2CEjKpC,GAAqB,UAMrB,GAAwB,GAAS,CAC/B,MAAA,OAAO,QAAQ,CAAK,EACxB,OAAA,EAAO,EAAA,QAAA,CAAQ,CAAK,CACxB,EAGM,EAAgC,GAC3B,EAAA,QAAO,SAAS,CAAK,EAI1B,EAAkC,GAC7B,CAAC,CAAC,EAIP,EAAmC,GAAS,CAC1C,MAAA,OAAO,QAAQ,CAAK,EAKxB,MAJA,GAAQ,EAAA,QAAO,SAAS,CAAK,GACzB,IAAU,KAAY,MAAM,CAAK,KACjC,EAAQ,IAAA,IAEL,CACX,EAGM,GAAwC,GACrC,EACE,KAAK,UAAU,EAAO,KAAM,CAAC,EADjB,GAOvB,SAAS,GAA2B,CAChC,MAAO,CACH,eAAgB,GAChB,MAAO,IAAA,EACX,CACJ,CAQA,SAAS,EAAkB,EAAoB,EAAoB,EAAkC,CACjG,IAAI,EAAQ,GAAY,EAAO,EAAO,CAAS,EAI/C,OAHI,EAAA,OAAO,WAAW,CAAS,IAC3B,EAAQ,EAAU,CAAK,GAEpB,CACX,CAEA,SAAS,GAAY,EAAoB,EAAoB,EAAiC,CAC1F,GAAM,CAAE,QAAO,YAAW,iBAAkB,EAE5C,GADI,CAAC,GACD,CAAC,GAAa,CAAC,EAAA,OAAO,WAAW,CAAa,EAAG,OACrD,IAAM,EAAS,IAAI,IACnB,IAAK,IAAM,KAAQ,EAAO,CACtB,IAAI,EAgBJ,GAfI,EAEA,EAAQ,EAAc,EAAK,MAAO,CAAI,EAC/B,IACP,AAKI,EALA,EAAA,QAAO,MAAM,EAAK,MAAO,CAAS,EAE1B,EAAK,QAAQ,GAGb,EAAM,eAGlB,EAAA,OAAO,WAAW,CAAS,IAAG,EAAQ,EAAU,CAAK,GACrD,EAAA,OAAO,QAAQ,CAAK,IAAG,EAAQ,IAAA,IACnC,EAAO,IAAI,CAAK,EACZ,EAAO,KAAO,EACd,KAER,CACI,OAAO,MAAQ,GAEZ,IAAI,EAAO,OAAS,EACvB,OAAO,EAAO,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAE9B,EAAM,eAAiB,GACvB,EAAM,MAAQ,IAAA,EAElB,CACJ,CAYA,SAAS,EAAoB,EAAoB,EAAoB,EAAa,EAAmB,CACjG,GAAM,CACF,gBACA,gBACA,QACA,YACA,kBACA,kBACA,wBACA,6BACA,kBACA,EACA,EAAM,GAEV,GADI,CAAC,GACD,CAAC,GAAa,CAAC,EAAA,OAAO,WAAW,CAAe,EAAG,OAAO,EAE9D,GAAI,EAAA,OAAO,WAAW,CAAe,EAAG,CACpC,IAAK,IAAM,KAAQ,EACf,EAAM,EAAgB,EAAK,MAAO,EAAO,EAAM,CAAM,IAAM,GAEvD,GAAkB,IAClB,EAAK,UAAU,UAAY,gBAAgB,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,EAAE,KAOvG,OAJI,IACA,EAAM,eAAiB,GACvB,GAAiB,EAAe,EAAe,EAAO,EAAiB,EAAuB,CAA0B,GAErH,CACX,CAEA,GAAI,CAAC,EAAW,OAAO,EACvB,IAAM,EAAoC,CAAC,EAC3C,IAAK,IAAM,KAAQ,EAAO,CACtB,GAAI,CAAC,EAAK,MAAO,SACjB,IAAM,EAAW,EAAA,QAAO,MAAM,EAAK,MAAO,CAAS,EAAI,EAAA,QAAO,UAAU,EAAK,MAAM,EAAU,EAAI,IAAA,GAE7F,EAAA,QAAO,QAAQ,EAAU,CAAK,GAClC,EAAQ,KAAK,CACT,OAAQ,EAAK,GACb,UAAW,SAAS,IACpB,WACA,SAAU,EACV,OAAQ,EAAQ,IAAQ,CACpB,EAAO,MAAM,GAAc,EACvB,IACA,EAAO,UAAU,UAAY,gBAAgB,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,EAAE,IAEzG,CACJ,CAAC,CACL,CACA,GAAI,EAAQ,QAAU,EAAG,OAAO,EAChC,IAAM,EAAU,IAAI,EAAmB,EAAe,QAAQ,IAAa,CACvE,UACA,iBACJ,CAAC,EAGD,MAFA,GAAM,EAAc,aAAa,QAAQ,CAAO,EAC5C,IAAK,EAAM,eAAiB,IACzB,CACX,CAKA,SAAS,GAAiB,EAA8B,EAA0C,EAA2B,EAA2B,EAAiC,EAA2C,CAChO,GAAI,CAAC,GAAmB,IACpB,EAAc,aAAa,EAEvB,GAAuB,CACvB,IAAM,MAAkB,CACpB,IAAM,EAAU,EAAM,IAAI,GAAQ,EAAK,EAAE,EACzC,IAAK,IAAM,KAAa,EAAc,WAC9B,EAAU,QAAU,EAAQ,SAAS,EAAU,MAAM,GACrD,EAAU,eAAe,CAGrC,EACA,EAAc,cAAgB,EACrB,GAA8B,GAAK,EACpC,WAAW,EAAW,CAA0B,EAEhD,EAAU,CAElB,CAAC,CACL,CAER,CAKA,SAAS,EAAW,EAAoB,EAAoB,EAAkC,EAC1F,EAAA,EAAA,MAAA,KAAY,EAAM,UAAa,CAC3B,EAAM,MAAQ,EAAS,EAAO,EAAO,CAAS,CAClD,CAAC,CACL,CAKA,SAAS,EAAyB,EAAoB,EAAoB,EAAa,EAA+B,CAClH,MAAO,CACH,cAAe,EAAM,cACrB,cAAe,EAAM,cACrB,MAAO,EAAM,MACb,aAAgB,EAAM,MACtB,SAAW,GAAe,CAClB,EAAA,OAAO,WAAW,CAAS,IAAG,EAAQ,EAAU,CAAK,GACzD,EAAM,MAAQ,EACd,EAAW,EAAO,EAAO,EAAQ,CAAK,CAC1C,CACJ,CACJ,4WC5NA,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA8B,CACxC,GAAG,EAAY,CACnB,CAAC,QACD,GAAM,MAAQ,EAAiB,EAAO,EAAO,CAAK,EAClD,EAAW,EAAO,EAAO,CAAK,EAE9B,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAK,CAC3D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAME,EAAA,MAAA,CAAA,EAAA,KAAA,GAAA,EANF,EAAA,WAAA,CAME,CALG,YAAa,EAAM,eAAc,UAAA,MACjC,MAAO,EAAM,eAAc,UAAe,IAAA,EACnCA,EAAAA,EAAAA,OAAM,CACN,MAAO,EAAM,MAAN,iBAAA,AAAA,EAAA,KAAA,GAAA,EAAM,MAAK,EACzB,SAAM,AAAA,EAAA,UAAA,EAAQ,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,EAAM,KAAK,0ZEpB5E,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA8B,CACxC,GAAG,EAAY,CACnB,CAAC,QACD,GAAM,MAAQ,EAAiB,EAAO,EAAO,CAAQ,EACrD,EAAW,EAAO,EAAO,CAAQ,EAEjC,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAQ,CAC9D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAME,EAAA,MAAA,CAAA,EAAA,WAAA,GAAA,EANF,EAAA,WAAA,CAME,CALE,MAAM,uBACL,YAAa,EAAM,eAAc,UAAA,KAC1BC,EAAAA,EAAAA,OAAM,CACN,MAAO,EAAM,MAAN,iBAAA,AAAA,EAAA,KAAA,GAAA,EAAM,MAAK,EACzB,SAAM,AAAA,EAAA,KAAE,IAAA,EAAS,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,CAAK,+aEpBzE,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA+B,CACzC,GAAG,EAAY,CACnB,CAAC,QACD,GAAM,MAAQ,EAAkB,EAAO,EAAO,CAAM,EACpD,EAAW,EAAO,EAAO,CAAM,EAE/B,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAM,CAC5D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAIE,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,EAJF,EAAA,WAAA,CACYC,EAGV,OAHgB,CACb,QAAO,CAAA,CAAI,EAAM,MACjB,SAAM,AAAA,EAAA,KAAG,GAAY,CAAO,EAAM,MAAQ,GAAS,EAAA,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,CAAO,CAAA,sYElB7G,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA2B,CACrC,GAAG,EAAY,CACnB,CAAC,QAED,GAAM,MAAQ,EAAS,EAAO,EAAO,CAAK,EAC1C,EAAW,EAAO,EAAO,CAAK,EAE9B,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAK,CAC3D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAME,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,EANF,EAAA,WAAA,CAME,CALE,MAAM,uBACL,YAAa,EAAM,eAAc,UAAA,KAC1BC,EAAAA,EAAAA,OAAM,CACb,MAAO,EAAM,MACb,SAAM,AAAA,EAAA,KAAE,GAAK,CAAM,EAAM,MAAQ,GAAO,EAAA,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,CAAK,CAAA,2fEtBhG,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA8B,CACxC,GAAG,EAAY,CACnB,CAAC,EACD,EAAM,MAAQ,EAAiB,EAAO,EAAO,CAAK,EAClD,EAAW,EAAO,EAAO,CAAK,EAE9B,SAAS,GAAmB,CACxB,EAAM,MAAQ,IAAA,GACd,EAAW,EAAO,EAAO,GAAU,MAAO,IAAA,EAAS,CACvD,QAEA,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAK,CAC3D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CASM,MATN,GASM,EARF,EAAA,EAAA,mBAAA,CAKE,QAAA,CAJE,MAAM,cACN,KAAK,QACJ,MAAO,EAAM,OAAK,UAClB,SAAM,AAAA,EAAA,KAAE,GAAK,CAAM,EAAM,MAAS,EAAM,OAA4B,OAAO,EAAA,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,EAAM,KAAK,CAAA,gBAErI,EAAA,EAAA,mBAAA,CAAiD,OAAjD,IAAA,EAAiD,EAAA,gBAAA,CAArB,EAAM,KAAK,EAAA,CAAA,GACvC,EAAA,EAAA,eAAA,EAAA,EAAA,EAAA,mBAAA,CAAwF,OAAA,CAA7D,MAAM,cAAc,MAAM,OAAQ,QAAO,CAAY,EAAA,IAAC,GAAA,EAAA,CAAnE,CAAA,EAAA,MAAA,EAAM,KAAK,CAAA,CAAA,gZE1BjC,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA8B,CACxC,GAAG,EAAY,CACnB,CAAC,EACD,EAAM,MAAQ,EAAiB,EAAO,EAAO,CAAK,EAClD,EAAW,EAAO,EAAO,CAAK,EAG9B,SAAS,EAAQ,EAA8C,CAC3D,OAAO,GAAA,EAAQ,EAAA,QAAA,CAAM,CAAK,EAAI,IAAA,EAClC,QAEA,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAK,CAC3D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAUE,EAAA,MAAA,CAAA,EAAA,UAAA,GAAA,EAVF,EAAA,WAAA,CAUE,CATE,MAAM,uBACL,MAAO,EAAQ,EAAM,KAAK,CACnBC,EAAAA,EAAAA,OAAM,CACd,YAAY,aACX,SAAM,AAAA,EAAA,MAAG,EAAY,IAAkC,CAAyB,IAAA,EAAQ,MAAM,QAAQ,CAAU,EAAI,EAAU,GAAM,EAAwB,EAAM,MAAQ,GAAS,IAAA,IAAuB,EAAA,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,EAAM,KAAK,oaEzBxQ,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA8B,CACxC,GAAG,EAAY,CACnB,CAAC,EACD,EAAM,MAAQ,EAAiB,EAAO,EAAO,CAAK,EAClD,EAAW,EAAO,EAAO,CAAK,EAG9B,SAAS,EAAQ,EAA8C,CAC3D,OAAO,GAAA,EAAQ,EAAA,QAAA,CAAM,EAAO,UAAU,EAAI,IAAA,EAC9C,QAEA,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAK,CAC3D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAUE,EAAA,MAAA,CAAA,EAAA,UAAA,GAAA,EAVF,EAAA,WAAA,CAUE,CATE,MAAM,uBACL,MAAO,EAAQ,EAAM,KAAK,CACnBC,EAAAA,EAAAA,OAAM,CACd,YAAY,WACX,SAAM,AAAA,EAAA,MAAG,EAAY,IAAkC,CAAyB,IAAA,EAAQ,MAAM,QAAQ,CAAU,EAAI,EAAU,GAAM,EAAwB,EAAM,MAAQ,GAAS,IAAA,IAAuB,EAAA,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,EAAM,KAAK,saE1BxQ,IAAM,GAAA,EAAW,EAAA,mBAAA,CAAmB,EAC9B,EAAQ,EAER,GAAA,EAAQ,EAAA,SAAA,CAA8B,CACxC,GAAG,EAAY,CACnB,CAAC,QACD,GAAM,MAAQ,EAAiB,EAAO,EAAO,CAAK,EAClD,EAAW,EAAO,EAAO,CAAK,EAE9B,EAA2B,CACvB,GAAG,EAAgB,EAAO,EAAO,GAAU,MAAO,CAAK,CAC3D,CAAC,WAIG,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,EAAA,EAME,EAAA,MAAA,CAAA,EAAA,QAAA,GAAA,EANF,EAAA,WAAA,CAME,CALG,YAAa,EAAM,eAAc,UAAA,OAC1BC,EAAAA,EAAAA,OAAM,CACN,MAAO,EAAM,MAAN,iBAAA,AAAA,EAAA,KAAA,GAAA,EAAM,MAAK,EACzB,SAAU,CAAA,QAAA,EAAA,QAAA,EAAA,EACV,SAAM,AAAA,EAAA,UAAA,EAAQ,EAAA,MAAA,CAAA,CAAA,CAAU,CAAC,EAAO,GAAA,EAAO,EAAA,MAAA,CAAA,CAAA,CAAQ,EAAE,MAAO,EAAM,KAAK,yCEd5E,SAAS,GAAyB,EAAwC,CACtE,EAAgB,kBAAkB,eAAgB,EAAY,EAC9D,EAAgB,kBAAkB,eAAgB,EAAY,EAC9D,EAAgB,kBAAkB,aAAc,EAAU,EAC1D,EAAgB,kBAAkB,eAAgB,EAAY,EAC9D,EAAgB,kBAAkB,cAAe,EAAW,EAC5D,EAAgB,kBAAkB,aAAc,EAAU,EAC1D,EAAgB,kBAAkB,aAAc,EAAU,EAC1D,EAAgB,kBAAkB,eAAgB,EAAY,CAClE,CChBA,IAAM,GAAmB,QAGnB,GAAiB"}
|