Skip to content

Instantly share code, notes, and snippets.

@boraseoksoon
Created March 5, 2023 08:40
Show Gist options
  • Save boraseoksoon/8199d7232b21458f6c02a7cbf8234b4e to your computer and use it in GitHub Desktop.
Save boraseoksoon/8199d7232b21458f6c02a7cbf8234b4e to your computer and use it in GitHub Desktop.
Load Monaco editor in a single html file for MacOS SwiftUI
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