Created
March 5, 2023 08:40
-
-
Save boraseoksoon/8199d7232b21458f6c02a7cbf8234b4e to your computer and use it in GitHub Desktop.
Load Monaco editor in a single html file for MacOS SwiftUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import WebKit | |
@main | |
struct MonacoApp: App { | |
let codeSnippet = """ | |
var body: some Scene { | |
WindowGroup { | |
EditorView(content: codeSnippet, language: "swift", theme: "vs-dark") | |
} | |
} | |
""" | |
var body: some Scene { | |
WindowGroup { | |
CodeView(codeSnippet: codeSnippet, language: "swift", theme: "vs-light") | |
} | |
} | |
} | |
struct CodeView: NSViewRepresentable { | |
let codeSnippet: String | |
let language: String | |
let theme: String | |
private let webView = { | |
let config = WKWebViewConfiguration() | |
let webView = WKWebView(frame: .zero, configuration: config) | |
webView.layer?.backgroundColor = NSColor.clear.cgColor | |
return webView | |
}() | |
func makeNSView(context: Context) -> WKWebView { | |
let html = #""" | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Monaco Editor Example</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs/loader.js"></script> | |
<style> | |
#container { | |
width: 800px; | |
height: 600px; | |
border: 1px solid grey; | |
position: absolute; | |
top: 0; | |
right: 0; | |
bottom: 0; | |
left: 0; | |
border: none; | |
margin: 0; | |
padding: 0; | |
} | |
</style> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
</head> | |
<body> | |
<div id="container"></div> | |
<script> | |
require.config({ | |
paths: { | |
'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.30.1/min/vs' | |
} | |
}); | |
require(['vs/editor/editor.main'], function() { | |
var editor = monaco.editor.create(document.getElementById('container'), { | |
value: `\#(codeSnippet)`, | |
language: `\#(language)`, | |
theme: `\#(theme)`, | |
automaticLayout: true, // enable automatic resizing of the editor | |
fontFamily: 'Droid Sans Mono, Monaco, Menlo, Consolas, "DejaVu Sans Mono", monospace', // set the font family | |
fontSize: 14, // set the font size | |
lineNumbers: "on", // show line numbers | |
wordWrap: "on", // enable word wrapping | |
wrappingIndent: "indent", // wrap at the indentation level | |
tabSize: 2, // set the tab size to 2 spaces | |
insertSpaces: true, // use spaces instead of tabs | |
scrollBeyondLastLine: false, // disable scrolling beyond the last line | |
minimap: { | |
enabled: true, // enable the minimap | |
renderCharacters: false // disable rendering of characters in the minimap | |
} | |
}); | |
}); | |
</script> | |
</body> | |
</html> | |
"""# | |
webView.loadHTMLString(html, baseURL: nil) | |
webView.navigationDelegate = context.coordinator | |
return webView | |
} | |
func updateNSView(_ webView: WKWebView, context: Context) { } | |
func makeCoordinator() -> Coordinator { | |
Coordinator(webView: webView) | |
} | |
class Coordinator: NSObject, WKNavigationDelegate, NSWindowDelegate { | |
var window: NSWindow? | |
let webView: WKWebView | |
init(webView: WKWebView) { | |
self.webView = webView | |
super.init() | |
} | |
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { | |
if let window = webView.window { | |
self.window = window | |
window.delegate = self | |
} | |
} | |
func windowDidResize(_ notification: Notification) { | |
guard let window = notification.object as? NSWindow else { return } | |
resizeEditorSize(to: window.frame.size) | |
} | |
func resizeEditorSize(to size: CGSize) { | |
let width = size.width | |
let height = size.height | |
let resizeEditorJS = """ | |
(() => { | |
var element = document.getElementById("container"); | |
element.style.width = "\(width)px"; | |
element.style.height = "\(height)px"; | |
element.style.paddingTop = '0px'; | |
element.style.paddingBottom = '500px'; | |
})() | |
""" | |
self.webView.evaluateJavaScript(resizeEditorJS, completionHandler: nil) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment