### Install markupeditor-js Project Source: https://github.com/stevengharris/markupeditor/blob/main/markupeditor-js/README.md Run this command to install the markupeditor-js project and its dependencies. This also triggers a prepare script that copies necessary files from markupeditor-base into the Swift MarkupEditor project. ```bash $ npm install > markupeditor@0.8.6 prepare > sh prepare.sh Updating dependencies from markupeditor base project... Copying ./node_modules/markupeditor/dist/markup-editor.js to ../MarkupEditor/Resources/markup-editor.js Warning: ./node_modules/markupeditor/test does not exist. To run tests, you must install using a local markupeditor dev-dependency. added 84 packages, and audited 85 packages in 2s 22 packages are looking for funding run `npm fund` for details found 0 vulnerabilities $ ``` -------------------------------- ### SwiftUI MarkupEditorView Example Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Demonstrates the simplest way to integrate MarkupEditorView in a SwiftUI view. It binds to an HTML string state variable for editing. ```swift import SwiftUI import MarkupEditor struct SimplestContentView: View { @State private var demoHtml: String = "

Hello World

" var body: some View { MarkupEditorView(html: $demoHtml) } } ``` -------------------------------- ### Run Prepare Script After Local Dependency Setup Source: https://github.com/stevengharris/markupeditor/blob/main/markupeditor-js/README.md After setting up a local dependency, rerun the prepare script to copy the updated files from your local markupeditor-base into the Swift MarkupEditor project, including test data. ```bash $ sh prepare.sh Updating dependencies from markupeditor base project... Copying ./node_modules/markupeditor/dist/markup-editor.js to ../MarkupEditor/Resources/markup-editor.js Copying test data ./node_modules/markupeditor/test/*.json to ../MarkupEditorTests/BaseTests/Data $ ``` -------------------------------- ### Install Local markupeditor-base Dependency Source: https://github.com/stevengharris/markupeditor/blob/main/markupeditor-js/README.md After cloning, use this command to replace the default npm registry dependency with your local copy of markupeditor-base. This ensures changes in your local clone are reflected in the Swift MarkupEditor project. ```bash npm install --save-dev ``` -------------------------------- ### Customize MarkupEditor Toolbar Style and Contents Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Set the toolbar style to compact and customize format options. This setup should be done before creating the MarkupMenu, typically in an AppDelegate's init(). ```swift override init() { MarkupEditor.style = .compact MarkupEditor.allowLocalImages = true let myToolbarContents = ToolbarContents( correction: true, // Off by default but accessible via menu, hotkeys, inputAccessoryView // Remove code, strikethrough, subscript, and superscript as formatting options formatContents: FormatContents(code: false, strike: false, subSuper: false) ) ToolbarContents.custom = myToolbarContents } ``` -------------------------------- ### Indented Code Example in MarkupEditor Source: https://github.com/stevengharris/markupeditor/blob/main/SharedDemo/demo.html Demonstrates how to display indented code within the MarkupEditor. This is useful for code blocks that need to be visually distinct and indented from the surrounding text. ```swift // Here is an example of code that has been indented. print("Hello, world!") ``` -------------------------------- ### Invoke Custom JavaScript Function from Swift Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Extend MarkupWKWebView to create a Swift method that executes a custom JavaScript function defined in your user script. This example invokes the `MU.wordCount` function. ```swift extension MarkupWKWebView { /// Invoke the MU.wordcount method on the JavaScript side that was added-in via custom.js. public func wordcount(_ handler: ((Int?)->Void)? = nil) { executeJavaScript("MU.wordCount()") { result, error in if let error { print(error.localizedDescription) } handler?(result as? Int) } } } ``` -------------------------------- ### Query Selection State in MarkupEditor Source: https://context7.com/stevengharris/markupeditor/llms.txt Access and query the observable SelectionState object to get information about the current selection, including formatting, styles, links, images, and tables. Automatically updated as the user interacts with the document. ```swift // Access the global selection state let state = MarkupEditor.selectionState // Query formatting state if state.bold { print("Selection is bold") } if state.italic { print("Selection is italic") } if state.underline { print("Selection is underlined") } if state.code { print("Selection is code") } // Query paragraph style print("Current style: \(state.style.tag)") // P, H1, H2, etc. // Query list context if state.isInList { print("In \(state.list.tag) list") // UL or OL } // Query link information if state.isInLink { print("Link href: \(state.href ?? "")") print("Link text: \(state.link ?? "")") } // Query image information if state.isInImage { print("Image src: \(state.src ?? "")") print("Image alt: \(state.alt ?? "")") print("Dimensions: \(state.width ?? 0)x\(state.height ?? 0)") } // Query table context if state.isInTable { print("Table: \(state.rows)x\(state.cols)") print("Current cell: row \(state.row), col \(state.col)") } // Check undo/redo availability if state.canUndo { print("Undo available") } if state.canRedo { print("Redo available") } ``` -------------------------------- ### Build MarkupEditor Base Source: https://github.com/stevengharris/markupeditor/blob/main/markupeditor-js/README.md Run this command in the markupeditor-base directory to build the project. It uses Rollup to bundle the JavaScript files. ```bash $ npm run build > markupeditor-base@0.8.6 build > rollup -c src/main.js → dist/markupeditor.umd.js... created dist/markupeditor.umd.js in 352ms src/main.js → dist/markupeditor.cjs.js, dist/markupeditor.esm.js... created dist/markupeditor.cjs.js, dist/markupeditor.esm.js in 72ms $ ``` -------------------------------- ### Specify Additional User Resources in Configuration Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Use this to include additional resources, such as images or other assets, that your custom scripts might need. These files are co-located with the document. ```swift markupConfiguration.userResourceFiles = ["myImage.png"] ``` -------------------------------- ### Override Default CSS for H4 Element Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Example of overriding the default font-weight for H4 elements in markup.css using custom CSS. This demonstrates how to target specific HTML elements for styling. ```css h4 { font-weight: normal; } ``` -------------------------------- ### Prepare MarkupEditor JS Source: https://github.com/stevengharris/markupeditor/blob/main/markupeditor-js/README.md Execute this command in the markupeditor-js directory to copy updated files from the base project into the Swift MarkupEditor source control. This script also copies test data. ```bash $ npm run prepare > markupeditor@0.8.6 prepare > sh prepare.sh Updating dependencies from markupeditor base project... Copying ./node_modules/markupeditor/dist/markup-editor.js to ../MarkupEditor/Resources/markup-editor.js Copying test data ./node_modules/markupeditor/test/*.json to ../MarkupEditorTests/BaseTests/Data $ ``` -------------------------------- ### Specify User Script File in Configuration Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Use this to specify a JavaScript file to be loaded after the main markup-editor.js. The script is loaded as a module. ```swift markupConfiguration.userScriptFile = "custom.js" ``` -------------------------------- ### MarkupWKWebViewConfiguration with Custom Files Source: https://context7.com/stevengharris/markupeditor/llms.txt Initialize MarkupWKWebViewConfiguration to customize the editor with external CSS and JavaScript files. Ensure these files are included in your app bundle. ```swift import MarkupEditor // Create configuration with custom CSS and JavaScript let config = MarkupWKWebViewConfiguration() // Custom CSS file (must be in app bundle) config.userCssFile = "custom.css" // Custom JavaScript file (must be in app bundle) config.userScriptFile = "custom.js" // Additional resource files to co-locate with document config.userResourceFiles = ["logo.png", "signature.jpg"] ``` -------------------------------- ### Define Custom JavaScript Function for MarkupEditor Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Define a JavaScript function within your custom script that can be invoked from the Swift side. This example shows how to add a word count function using the MarkupEditor API. ```javascript import { MU } from "./markup-editor.js" /** * A public method that can be invoked from MarkupWKWebView to return * the number of words in the HTML document using a simpleminded approach. * Invoking this method requires an extension to MarkupWKWebView. */ MU.wordCount = function() { const text = MU.activeView()?.state.doc.textContent return text ? text.trim().split(/\s+/).filter(Boolean).length : 0 }; ``` -------------------------------- ### Index MarkupEditor Document with CoreSpotlight Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Add a model object to the Spotlight index. Ensure the `contentType` is set to `UTType.html` and `htmlContentData` is populated with the document's content. The `contentDescription` is derived from the document's text for search snippets. ```swift /// Add this instance of MyModelObject to the Spotlight index func index() { let attributeSet = CSSearchableItemAttributeSet(contentType: UTType.html) attributeSet.kind = "" let contentData = contents.data(using: .utf8) // Set the htmlContentData based on the entire document contents attributeSet.htmlContentData = contentData if let data = contentData { if let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) { // Put a snippet of content in the contentDescription that will show up in Spotlight searches if attributedString.length > 30 { attributeSet.contentDescription = "\(attributedString.string.prefix(30))..." } else { attributeSet.contentDescription = attributedString.string } } } // Now create the CSSearchableItem with the attributeSet we just created, using MyModelObject's unique id let item = CSSearchableItem(uniqueIdentifier: , domainIdentifier: , attributeSet: attributeSet) item.expirationDate = Date.distantFuture CSSearchableIndex.default().indexSearchableItems([item]) { error in if let error = error { print("Indexing error: \(error.localizedDescription)") } else { print("Search item successfully indexed!") } } } ``` -------------------------------- ### Configure MarkupEditor Settings Source: https://context7.com/stevengharris/markupeditor/llms.txt Set global configuration options for MarkupEditor before initializing any editor views. This includes toolbar location, local image support, and debugging features. ```swift import MarkupEditor // Configure before creating any MarkupEditorView/UIView @MainActor func configureMarkupEditor() { // Toolbar location: .top, .bottom, .keyboard, .none MarkupEditor.toolbarLocation = .top // Enable local image selection (adds Select button to image dialog) MarkupEditor.allowLocalImages = true // Enable Web Inspector for debugging (iOS 16.4+) #if DEBUG MarkupEditor.isInspectable = true #endif // Customize toolbar contents let customContents = ToolbarContents( correction: true, // Show undo/redo buttons insert: true, // Show link/image/table buttons style: true, // Show paragraph style picker format: true, // Show formatting buttons formatContents: FormatContents( code: true, strike: true, subSuper: false // Hide sub/superscript ) ) ToolbarContents.custom = customContents } ``` -------------------------------- ### Initialize MarkupEditor Settings (Non-Isolated) Source: https://github.com/stevengharris/markupeditor/blob/main/CHANGELOG.md This code snippet shows how to set default properties for MarkupEditor. Accessing static properties like `style` from a non-main-actor-isolated context can lead to errors in strict concurrency mode. ```swift private static func initializeMarkupEditor() { MarkupEditor.style = .compact MarkupEditor.allowLocalImages = true MarkupEditor.toolbarLocation = .keyboard #if DEBUG MarkupEditor.isInspectable = true #endif } ``` -------------------------------- ### Clone markupeditor-base Project Source: https://github.com/stevengharris/markupeditor/blob/main/markupeditor-js/README.md Clone the markupeditor-base repository to your local machine if you plan to make modifications to its code. ```bash git clone https://github.com/stevengharris/markupeditor-base.git ``` -------------------------------- ### Search MarkupEditor Documents with CSSearchQuery Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Execute a case-insensitive search query against the Spotlight index to find documents. The query string can filter by domain identifier and text content. The `foundItemsHandler` processes found items, and `completionHandler` handles post-search actions. ```swift let queryString = "domainIdentifier == '\( Void)?) { MarkupEditor.selectedWebView = view handler?() } // Called on every input (typing, formatting, etc.) func markupInput(_ view: MarkupWKWebView) { // Update UI, track changes, etc. } // Called when content height changes func markup(_ view: MarkupWKWebView, heightDidChange height: Int) { // Adjust layout if needed } // Called when editor gains focus func markupTookFocus(_ view: MarkupWKWebView) { // Update toolbar state, etc. } // Called when editor loses focus func markupLostFocus(_ view: MarkupWKWebView) { // Save draft, update UI, etc. } // Called when user clicks a followable link func markupLinkSelected(_ view: MarkupWKWebView?, selectionState: SelectionState) { guard let href = selectionState.href, let url = URL(string: href) else { return } // Open URL or handle internally } // Called when a local image is added func markupImageAdded(url: URL) { // Copy image to permanent storage if needed print("Image added at: \(url.path)") } // Called when an image is deleted func markupImageDeleted(url: URL) { // Clean up associated resources } } ``` -------------------------------- ### Enable Local Images in MarkupEditor Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Set this static property to true to allow users to select images from their local file system. This option is disabled by default. ```swift MarkupEditor.allowLocalImages = true ``` -------------------------------- ### Insert Images Source: https://context7.com/stevengharris/markupeditor/llms.txt Insert images from URLs or local files. Local images are cached and referenced relatively. Supports callback and async/await. ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Insert image from URL webView.insertImage(src: "https://example.com/image.png", alt: "Description") { print("Image inserted") } // Insert local image (copied to cache, returns new URL) let localImageURL = URL(fileURLWithPath: "/path/to/image.png") webView.insertLocalImage(url: localImageURL) { cachedURL in print("Image cached at: \(cachedURL)") } // Using async/await Task { await webView.insertImage(src: "https://example.com/photo.jpg", alt: "Photo") } ``` -------------------------------- ### MarkupDelegate Protocol Source: https://context7.com/stevengharris/markupeditor/llms.txt The delegate protocol for receiving callbacks about editor state changes. All methods have default implementations, so only override what you need. ```APIDOC ## MarkupDelegate Protocol ### Description The delegate protocol for receiving callbacks about editor state changes. All methods have default implementations, so only override what you need. ### Methods - `markupDidLoad(_:handler:)`: Called when the editor finishes loading. - `markupInput(_:)`: Called on every input (typing, formatting, etc.). - `markup(_:heightDidChange:)`: Called when content height changes. - `markupTookFocus(_:)`: Called when the editor gains focus. - `markupLostFocus(_:)`: Called when the editor loses focus. - `markupLinkSelected(_:selectionState:)`: Called when a user clicks a followable link. - `markupImageAdded(url:)`: Called when a local image is added. - `markupImageDeleted(url:)`: Called when an image is deleted. ### Parameters - **view** (MarkupWKWebView) - The web view instance. - **handler** (Void?) - A completion handler to be called after the editor is loaded. - **height** (Int) - The new height of the content. - **selectionState** (SelectionState) - The current selection state when a link is selected. - **url** (URL) - The URL of the added or deleted image. ### Request Example ```swift import MarkupEditor class MyViewController: UIViewController, MarkupDelegate { // Called when the editor finishes loading func markupDidLoad(_ view: MarkupWKWebView, handler: (() -> Void)?) { MarkupEditor.selectedWebView = view handler?() } // Called on every input (typing, formatting, etc.) func markupInput(_ view: MarkupWKWebView) { // Update UI, track changes, etc. } // Called when content height changes func markup(_ view: MarkupWKWebView, heightDidChange height: Int) { // Adjust layout if needed } // Called when editor gains focus func markupTookFocus(_ view: MarkupWKWebView) { // Update toolbar state, etc. } // Called when editor loses focus func markupLostFocus(_ view: MarkupWKWebView) { // Save draft, update UI, etc. } // Called when user clicks a followable link func markupLinkSelected(_ view: MarkupWKWebView?, selectionState: SelectionState) { guard let href = selectionState.href, let url = URL(string: href) else { return } // Open URL or handle internally } // Called when a local image is added func markupImageAdded(url: URL) { // Copy image to permanent storage if needed print("Image added at: \(url.path)") } // Called when an image is deleted func markupImageDeleted(url: URL) { // Clean up associated resources } } ``` ### Response #### Success Response (200) Callbacks are invoked based on editor events. #### Response Example No direct response body, but delegate methods are executed. ``` -------------------------------- ### Toggle Text Formatting Source: https://context7.com/stevengharris/markupeditor/llms.txt Apply or toggle text formatting like bold, italic, underline, code, strikethrough, subscript, and superscript. Supports callback and async/await patterns. ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Toggle formatting with callbacks webView.bold { print("Bold toggled") } webView.italic { print("Italic toggled") } webView.underline { print("Underline toggled") } webView.code { print("Code toggled") } webView.strike { print("Strikethrough toggled") } webView.subscriptText { print("Subscript toggled") } webView.superscript { print("Superscript toggled") } // Using async/await Task { try await webView.bold() try await webView.italic() } ``` -------------------------------- ### Specify Custom CSS File for MarkupEditor Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Assign a custom CSS file to MarkupWKWebViewConfiguration to override default styles. The specified CSS file is loaded after the default ones, following standard CSS cascading rules. ```swift markupConfiguration.userCssFile = "custom.css" ``` -------------------------------- ### SelectionState - Query Selection Context Source: https://context7.com/stevengharris/markupeditor/llms.txt An observable object that tracks the current selection state including formatting, styles, links, images, and tables. Automatically updated as the user interacts with the document. ```APIDOC ## SelectionState - Query Selection Context ### Description An observable object that tracks the current selection state including formatting, styles, links, images, and tables. Automatically updated as the user interacts with the document. ### Method Access the global selection state via `MarkupEditor.selectionState`. ### Properties - **bold** (Bool) - Indicates if the selection is bold. - **italic** (Bool) - Indicates if the selection is italic. - **underline** (Bool) - Indicates if the selection is underlined. - **code** (Bool) - Indicates if the selection is code formatted. - **style** (ParagraphStyle) - The current paragraph style (e.g., P, H1, H2). - **isInList** (Bool) - Indicates if the selection is within a list. - **list** (ListStyle) - The type of list (UL or OL) if `isInList` is true. - **isInLink** (Bool) - Indicates if the selection is within a link. - **href** (String?) - The URL of the link if `isInLink` is true. - **link** (String?) - The text content of the link if `isInLink` is true. - **isInImage** (Bool) - Indicates if the selection is within an image. - **src** (String?) - The source URL of the image if `isInImage` is true. - **alt** (String?) - The alt text of the image if `isInImage` is true. - **width** (Int?) - The width of the image if `isInImage` is true. - **height** (Int?) - The height of the image if `isInImage` is true. - **isInTable** (Bool) - Indicates if the selection is within a table. - **rows** (Int) - The total number of rows in the table if `isInTable` is true. - **cols** (Int) - The total number of columns in the table if `isInTable` is true. - **row** (Int) - The current row index if `isInTable` is true. - **col** (Int) - The current column index if `isInTable` is true. - **canUndo** (Bool) - Indicates if undo is available. - **canRedo** (Bool) - Indicates if redo is available. ### Request Example ```swift // Access the global selection state let state = MarkupEditor.selectionState // Query formatting state if state.bold { print("Selection is bold") } if state.italic { print("Selection is italic") } if state.underline { print("Selection is underlined") } if state.code { print("Selection is code") } // Query paragraph style print("Current style: \(state.style.tag)") // P, H1, H2, etc. // Query list context if state.isInList { print("In \(state.list.tag) list") // UL or OL } // Query link information if state.isInLink { print("Link href: \(state.href ?? "")") print("Link text: \(state.link ?? "")") } // Query image information if state.isInImage { print("Image src: \(state.src ?? "")") print("Image alt: \(state.alt ?? "")") print("Dimensions: \(state.width ?? 0)x\(state.height ?? 0)") } // Query table context if state.isInTable { print("Table: \(state.rows)x\(state.cols)") print("Current cell: row \(state.row), col \(state.col)") } // Check undo/redo availability if state.canUndo { print("Undo available") } if state.canRedo { print("Redo available") } ``` ### Response #### Success Response (200) Properties of the `SelectionState` object are directly accessible. #### Response Example ```json { "bold": true, "italic": false, "underline": false, "code": false, "style": {"tag": "P"}, "isInList": false, "isInLink": false, "isInImage": false, "isInTable": false, "canUndo": true, "canRedo": true } ``` ``` -------------------------------- ### Table Operations Source: https://context7.com/stevengharris/markupeditor/llms.txt Insert and manipulate tables, including adding/removing rows/columns, adding headers, and controlling borders. Supports callback and async/await. ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Insert a new table webView.insertTable(rows: 3, cols: 4) { print("3x4 table inserted") } // Add rows and columns webView.addRow(.before) { print("Row added above") } webView.addRow(.after) { print("Row added below") } webView.addCol(.before) { print("Column added left") } webView.addCol(.after) { print("Column added right") } // Delete rows, columns, or entire table webView.deleteRow { print("Row deleted") } webView.deleteCol { print("Column deleted") } webView.deleteTable { print("Table deleted") } // Add spanning header webView.addHeader(colspan: true) { print("Header added") } // Set table border style webView.borderTable(.cell) { print("All cells bordered") } webView.borderTable(.outer) { print("Outer border only") } webView.borderTable(.header) { print("Header border only") } webView.borderTable(.none) { print("No borders") } // Using async/await Task { await webView.insertTable(rows: 2, cols: 3) await webView.addHeader() } ``` -------------------------------- ### Image Operations Source: https://context7.com/stevengharris/markupeditor/llms.txt Methods to insert images from URLs or local files. Local images are copied to a cache directory and referenced relatively, enabling document portability. ```APIDOC ## Image Operations ### Description Methods to insert images from URLs or local files. Local images are copied to a cache directory and referenced relatively, enabling document portability. ### Methods - `insertImage(src: String, alt: String?)` - `insertLocalImage(url: URL)` ### Endpoint N/A (Direct method calls on a WebView instance) ### Parameters - **src** (String) - Required for `insertImage` - The URL of the image. - **alt** (String?) - Optional for `insertImage` - Alternative text for the image. - **url** (URL) - Required for `insertLocalImage` - The local file URL of the image. ### Request Example ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Insert image from URL webView.insertImage(src: "https://example.com/image.png", alt: "Description") { print("Image inserted") } // Insert local image (copied to cache, returns new URL) let localImageURL = URL(fileURLWithPath: "/path/to/image.png") webView.insertLocalImage(url: localImageURL) { cachedURL in print("Image cached at: \(cachedURL)") } // Using async/await Task { await webView.insertImage(src: "https://example.com/photo.jpg", alt: "Photo") } ``` ### Response Callbacks or async operations indicate completion or success. `insertLocalImage` callback provides the cached URL. ``` -------------------------------- ### Table Operations Source: https://context7.com/stevengharris/markupeditor/llms.txt Methods to insert and manipulate tables including adding/removing rows and columns, adding headers, and controlling table borders. ```APIDOC ## Table Operations ### Description Methods to insert and manipulate tables including adding/removing rows and columns, adding headers, and controlling table borders. ### Methods - `insertTable(rows: Int, cols: Int)` - `addRow(position: RowPosition)` - `addCol(position: ColumnPosition)` - `deleteRow()` - `deleteCol()` - `deleteTable()` - `addHeader(colspan: Bool)` - `borderTable(style: BorderStyle)` ### Endpoint N/A (Direct method calls on a WebView instance) ### Parameters - **rows** (Int) - Required for `insertTable` - Number of rows. - **cols** (Int) - Required for `insertTable` - Number of columns. - **position** (RowPosition or ColumnPosition) - Required for `addRow`/`addCol` - Position relative to the current selection (`.before` or `.after`). - **colspan** (Bool) - Optional for `addHeader` - If true, adds a header cell spanning columns. - **style** (BorderStyle) - Required for `borderTable` - The border style to apply (`.cell`, `.outer`, `.header`, `.none`). ### Request Example ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Insert a new table webView.insertTable(rows: 3, cols: 4) { print("3x4 table inserted") } // Add rows and columns webView.addRow(.before) { print("Row added above") } webView.addCol(.after) { print("Column added right") } // Delete rows, columns, or entire table webView.deleteRow { print("Row deleted") } webView.deleteTable { print("Table deleted") } // Add spanning header webView.addHeader(colspan: true) { print("Header added") } // Set table border style webView.borderTable(.cell) { print("All cells bordered") } webView.borderTable(.none) { print("No borders") } // Using async/await Task { await webView.insertTable(rows: 2, cols: 3) await webView.addHeader() } ``` ### Response Callbacks or async operations indicate completion or success. ``` -------------------------------- ### Core Editor API: MarkupWKWebView Operations Source: https://context7.com/stevengharris/markupeditor/llms.txt Interact with the core MarkupWKWebView to retrieve, set, or clear HTML content. Use `MarkupEditor.selectedWebView` to access the currently active editor instance. ```swift import MarkupEditor // Get the currently selected editor guard let webView = MarkupEditor.selectedWebView else { return } // Retrieve the edited HTML content webView.getHtml { html in guard let html = html else { return } // Save or process the HTML try? html.write(to: fileURL, atomically: true, encoding: .utf8) } // Set new HTML content webView.setHtml("

New Document

Fresh content.

") { print("Content loaded") } // Clear the document webView.emptyDocument { print("Document cleared") } ``` -------------------------------- ### MarkupWKWebView Search Function Signature Source: https://github.com/stevengharris/markupeditor/blob/main/README.md This is the function signature for initiating a search within the MarkupWKWebView. It allows specifying the text to search for, the direction of the search, whether to activate search mode, and an optional completion handler. ```swift func search( for text: String, direction: FindDirection, activate: Bool = false, handler: (() -> Void)? = nil ) ``` -------------------------------- ### SwiftUI Integration with MarkupEditorView Source: https://context7.com/stevengharris/markupeditor/llms.txt Use MarkupEditorView for a complete WYSIWYG editing experience in SwiftUI applications. It automatically manages the toolbar and supports HTML binding, placeholder text, and delegate callbacks. ```swift import SwiftUI import MarkupEditor struct ContentView: View { @State private var documentHtml: String = "

Welcome

Start editing...

" var body: some View { MarkupEditorView( markupDelegate: self, html: $documentHtml, placeholder: "Enter your content here...", selectAfterLoad: true, id: "MainDocument" ) } } extension ContentView: MarkupDelegate { func markupDidLoad(_ view: MarkupWKWebView, handler: (() -> Void)?) { MarkupEditor.selectedWebView = view handler?() } func markupInput(_ view: MarkupWKWebView) { // Called on every edit - use sparingly for performance view.getHtml { html in print("Document changed: \(html?.prefix(100) ?? "")") } } } ``` -------------------------------- ### Set Paragraph Styles Source: https://context7.com/stevengharris/markupeditor/llms.txt Change paragraph styles to headers (H1-H6), normal paragraphs, or code blocks. The style applies to the entire paragraph containing the selection. Supports callback and async/await. ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Set paragraph style with callback webView.setStyle(to: .H1) { print("Changed to Header 1") } webView.setStyle(to: .H2) { print("Changed to Header 2") } webView.setStyle(to: .P) { print("Changed to Normal paragraph") } webView.setStyle(to: .PRE) { print("Changed to Code block") } // Using async/await Task { await webView.setStyle(to: .H3) } // Available StyleContext values: // .P (Normal), .H1, .H2, .H3, .H4, .H5, .H6, .PRE (Code block) ``` -------------------------------- ### Insert or Remove Hyperlinks Source: https://context7.com/stevengharris/markupeditor/llms.txt Insert, modify, or remove hyperlinks at the current selection. Links wrap selected text or insert at the cursor. Supports callback and async/await. ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Insert a link at current selection webView.insertLink("https://example.com") { print("Link inserted") } // Remove a link (pass nil) webView.insertLink(nil) { print("Link removed") } // Using async/await Task { await webView.insertLink("https://apple.com") } ``` -------------------------------- ### Undo/Redo Operations in MarkupEditor Source: https://context7.com/stevengharris/markupeditor/llms.txt Programmatically check and perform undo/redo operations. The undo stack is managed automatically by ProseMirror. Supports both completion handlers and async/await. ```swift guard let webView = MarkupEditor.selectedWebView else { return } // Check undo/redo availability webView.canUndo { canUndo in print("Can undo: \(canUndo)") } webView.canRedo { canRedo in print("Can redo: \(canRedo)") } // Perform undo/redo webView.undo { print("Undo performed") } webView.redo { print("Redo performed") } // Using async/await Task { let canUndo = await webView.canUndo() if canUndo { await webView.undo() } } ``` -------------------------------- ### Basic UIKit Integration of MarkupEditor Source: https://github.com/stevengharris/markupeditor/blob/main/README.md Integrate `MarkupEditorUIView` into your `UIViewController` by adding it as a subview. Ensure to set its frame and autoresizing mask for proper layout. The view acts as its own delegate if none is provided. ```swift import UIKit import MarkupEditor class SimplestViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let markupEditorUIView = MarkupEditorUIView(html: "

Hello World

") markupEditorUIView.frame = view.frame markupEditorUIView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(markupEditorUIView) } } ```