54 lines
1.8 KiB
Swift
54 lines
1.8 KiB
Swift
import SwiftUI
|
|
import WebKit
|
|
|
|
/// A SwiftUI wrapper for WKWebView that loads HTML content.
|
|
/// Replaces the iOS 26-only WebPage / WebView combo.
|
|
struct HTMLWebView: UIViewRepresentable {
|
|
let html: String
|
|
let baseURL: URL?
|
|
/// When true, tapped links open in the default browser instead of navigating in-place.
|
|
var openLinksExternally: Bool = true
|
|
|
|
func makeCoordinator() -> Coordinator { Coordinator() }
|
|
|
|
func makeUIView(context: Context) -> WKWebView {
|
|
let webView = WKWebView()
|
|
webView.scrollView.bounces = true
|
|
webView.isOpaque = false
|
|
webView.backgroundColor = .clear
|
|
webView.navigationDelegate = context.coordinator
|
|
return webView
|
|
}
|
|
|
|
func updateUIView(_ webView: WKWebView, context: Context) {
|
|
let coordinator = context.coordinator
|
|
coordinator.openLinksExternally = openLinksExternally
|
|
// Only reload when the HTML has actually changed to avoid flicker.
|
|
guard coordinator.lastHTML != html else { return }
|
|
coordinator.lastHTML = html
|
|
webView.loadHTMLString(html, baseURL: baseURL)
|
|
}
|
|
|
|
// MARK: - Coordinator
|
|
|
|
final class Coordinator: NSObject, WKNavigationDelegate {
|
|
var lastHTML: String = ""
|
|
var openLinksExternally: Bool = true
|
|
|
|
func webView(
|
|
_ webView: WKWebView,
|
|
decidePolicyFor navigationAction: WKNavigationAction,
|
|
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
|
|
) {
|
|
if openLinksExternally,
|
|
navigationAction.navigationType == .linkActivated,
|
|
let url = navigationAction.request.url {
|
|
UIApplication.shared.open(url)
|
|
decisionHandler(.cancel)
|
|
} else {
|
|
decisionHandler(.allow)
|
|
}
|
|
}
|
|
}
|
|
}
|