### 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)
}
}
```