Hermes Agent 36967370fd SwiftBricks: Bricks JSON UI framework native Swift/SwiftUI implementation
- 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
2026-06-21 12:12:03 +08:00

114 lines
3.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
import Combine
/// 线 Bricks/
/// Bricksdispatch/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"
}