- Core: Schema (Codable), Store, EventBus, RPC, Engine, I18n - Controls: Text, Title1-6, Label, Input, Textarea, Number, Date, Button, Select VBox, HBox, ScrollPanel, DynamicColumn, Tabular, Form, InlineForm, TabView, Menu, PopupWindow, Html, Image, UrlWidget - Renderer: BricksView (main entry), ControlRenderer (recursive dispatch) - 30+ widget types, 9 bind actiontypes - Form validation (required/minlength/maxlength/min/max/email/number/pattern) - i18n with multi-language JSON files - 18 tests covering schema parsing, store, i18n, events
114 lines
3.1 KiB
Swift
114 lines
3.1 KiB
Swift
import Foundation
|
||
import Combine
|
||
|
||
/// 事件总线 — Bricks事件发布/订阅系统
|
||
/// 对应Bricks的dispatch/subscribe机制
|
||
@MainActor
|
||
public final class BricksEventBus: ObservableObject {
|
||
|
||
/// 事件定义: eventName → [callback]
|
||
private var handlers: [String: [(EventData) async -> Void]] = [:]
|
||
|
||
/// 已发布的事件历史(调试用)
|
||
@Published public var eventLog: [(name: String, data: EventData, timestamp: Date)] = []
|
||
|
||
private let maxLogSize = 100
|
||
|
||
public init() {}
|
||
|
||
// MARK: - 订阅
|
||
|
||
/// 订阅事件
|
||
public func on(_ eventName: String, handler: @escaping (EventData) async -> Void) {
|
||
if handlers[eventName] == nil {
|
||
handlers[eventName] = []
|
||
}
|
||
handlers[eventName]?.append(handler)
|
||
}
|
||
|
||
/// 取消订阅
|
||
public func off(_ eventName: String) {
|
||
handlers.removeValue(forKey: eventName)
|
||
}
|
||
|
||
// MARK: - 发布
|
||
|
||
/// 派发事件
|
||
public func dispatch(_ eventName: String, data: EventData = [:]) async {
|
||
// 记录日志
|
||
eventLog.append((name: eventName, data: data, timestamp: Date()))
|
||
if eventLog.count > maxLogSize {
|
||
eventLog.removeFirst()
|
||
}
|
||
|
||
// 调用所有handler
|
||
if let callbacks = handlers[eventName] {
|
||
for callback in callbacks {
|
||
await callback(data)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 同步派发(用于UI事件)
|
||
public func dispatchSync(_ eventName: String, data: EventData = [:]) {
|
||
Task { @MainActor in
|
||
await dispatch(eventName, data: data)
|
||
}
|
||
}
|
||
|
||
// MARK: - 工具
|
||
|
||
public func hasSubscribers(_ eventName: String) -> Bool {
|
||
!(handlers[eventName]?.isEmpty ?? true)
|
||
}
|
||
|
||
public func subscriberCount(_ eventName: String) -> Int {
|
||
handlers[eventName]?.count ?? 0
|
||
}
|
||
}
|
||
|
||
/// 事件数据 — 类型安全的事件载荷
|
||
public struct EventData: Sendable {
|
||
private var storage: [String: Any]
|
||
|
||
public init(_ dict: [String: Any] = [:]) {
|
||
self.storage = dict
|
||
}
|
||
|
||
public subscript(key: String) -> Any? {
|
||
get { storage[key] }
|
||
set { storage[key] = newValue }
|
||
}
|
||
|
||
public var asDictionary: [String: Any] { storage }
|
||
|
||
/// 合并两个EventData
|
||
public func merged(with other: EventData) -> EventData {
|
||
var result = EventData()
|
||
for (k, v) in storage { result[k] = v }
|
||
for (k, v) in other.storage { result[k] = v }
|
||
return result
|
||
}
|
||
|
||
/// 从字典创建
|
||
public static func from(_ dict: [String: Any]) -> EventData {
|
||
EventData(dict)
|
||
}
|
||
}
|
||
|
||
// MARK: - 常用事件名
|
||
|
||
public enum BricksEvent {
|
||
public static let click = "click"
|
||
public static let submit = "submit"
|
||
public static let change = "change"
|
||
public static let select = "select"
|
||
public static let load = "load"
|
||
public static let render = "render"
|
||
public static let close = "close"
|
||
public static let open = "open"
|
||
public static let toggle = "toggle"
|
||
public static let refresh = "refresh"
|
||
public static let navigate = "navigate"
|
||
}
|