import Foundation import Capacitor /// Hosts a native left-edge drawer (the "sidebar") that floats above the /// Capacitor web view. The drawer's *content* is a second, transparent /// WKWebView that renders the existing `Sidebar.js` from data pushed in via /// `setData`. Taps inside that content web view are forwarded back to the main /// app as an `action` event, mirroring how the NativeInput plugin works. @objc(NativeSidebarPlugin) public class NativeSidebarPlugin: CAPPlugin { private var drawer: SidebarDrawer? // MARK: Helpers private func hostView() -> UIView? { // Pin the drawer as a sibling of the web view inside the same parent so // it can float above the web content (same pattern as NativeInput). return webView?.superview ?? webView } private func ensureDrawer() -> SidebarDrawer? { if let drawer = drawer { return drawer } guard let host = hostView() else { return nil } let drawer = SidebarDrawer(hostView: host, mainWebView: webView, parentVC: bridge?.viewController) drawer.onAction = { [weak self] data in self?.notifyListeners("action", data: data) } drawer.onStateChange = { [weak self] open in self?.notifyListeners("stateChange", data: ["open": open]) } drawer.attach() self.drawer = drawer return drawer } // MARK: Plugin methods @objc func setData(_ call: CAPPluginCall) { // Forward the whole options object (minus Capacitor's callbackId) to the // content web view as the sidebar payload. var payload = (call.options as? [String: Any]) ?? [:] payload.removeValue(forKey: "callbackId") DispatchQueue.main.async { guard let drawer = self.ensureDrawer() else { call.reject("No host view"); return } drawer.setData(payload) call.resolve() } } @objc func setTheme(_ call: CAPPluginCall) { let theme = call.getString("theme") ?? "" DispatchQueue.main.async { self.drawer?.setTheme(theme) call.resolve() } } @objc func open(_ call: CAPPluginCall) { DispatchQueue.main.async { self.ensureDrawer()?.open() call.resolve() } } @objc func close(_ call: CAPPluginCall) { DispatchQueue.main.async { self.drawer?.close() call.resolve() } } @objc func setEnabled(_ call: CAPPluginCall) { let enabled = call.getBool("enabled") ?? true DispatchQueue.main.async { self.drawer?.setEnabled(enabled) call.resolve() } } @objc func dismiss(_ call: CAPPluginCall) { DispatchQueue.main.async { self.drawer?.removeFromHost() self.drawer = nil call.resolve() } } }