Tiptap.res

  1// src/ffi/Tiptap.res
  2// FFI bindings for TipTap Editor (@tiptap/core)
  3
  4// Import the extensions array from JavaScript
  5// Extensions are opaque - configured once in TiptapExtensions.js
  6@module("./extensions.js") external extensions: (Y.Doc.t, string) => array<unknown> = "extensions"
  7
  8// Opaque type for the Editor instance
  9type t
 10
 11// Range type for insertContentAt with range
 12// Uses object syntax for JavaScript interop
 13type range = {"from": int, "to": int}
 14
 15// Callback types for lifecycle events
 16type editorCallback = t => unit
 17// Transaction callback receives an object with editor and transaction properties
 18// Transaction type is opaque - use unknown if you need to access it
 19type editorTransactionCallback = {"editor": t, "transaction": unknown} => unit
 20
 21// Axis values for scrollThreshold and scrollMargin
 22// Single number or per-axis object
 23type scrollAxes = {
 24  top?: int,
 25  bottom?: int,
 26  left?: int,
 27  right?: int,
 28}
 29
 30// Editor options type
 31// Note: autofocus uses boolean only (simplified from string/boolean/number/null)
 32// Content uses JSON.t directly from stdlib for interoperability
 33type editorOptions = {
 34  editorProps?: {
 35    attributes: {class: string},
 36    scrollThreshold?: scrollAxes,
 37    scrollMargin?: scrollAxes,
 38  },
 39  element?: nullable<Dom.element>,
 40  extensions: array<unknown>,
 41  content?: JSON.t,
 42  editable?: bool,
 43  autofocus?: bool,
 44  enableInputRules?: bool,
 45  enablePasteRules?: bool,
 46  injectCSS?: bool,
 47  // Callbacks
 48  onCreate?: editorCallback,
 49  onUpdate?: editorCallback,
 50  onSelectionUpdate?: editorCallback,
 51  onTransaction?: editorTransactionCallback,
 52  onFocus?: editorCallback,
 53  onBlur?: editorCallback,
 54  onDestroy?: editorCallback,
 55}
 56
 57// Editor constructor
 58@module("@tiptap/core") @new
 59external make: editorOptions => t = "Editor"
 60
 61// Mount the editor to a DOM element
 62@send
 63external mount: (t, Dom.element) => unit = "mount"
 64
 65// Unmount the editor from its current element
 66@send
 67external unmount: t => unit = "unmount"
 68
 69// Destroy the editor and clean up all resources
 70@send
 71external destroy: t => unit = "destroy"
 72
 73// Get the editor content as JSON
 74// Returns JSON.t directly for use with stdlib functions
 75@send
 76external getJSON: t => JSON.t = "getJSON"
 77
 78// Check if editor is editable
 79@get
 80external isEditable: t => bool = "isEditable"
 81
 82// Check if editor is empty
 83@get
 84external isEmpty: t => bool = "isEmpty"
 85
 86// Check if editor is focused
 87@get
 88external isFocused: t => bool = "isFocused"
 89
 90// Check if editor is destroyed
 91@get
 92external isDestroyed: t => bool = "isDestroyed"
 93
 94// Access editor state and current selection
 95// Used by formatting actions that need to read the live selection range
 96type selection = {
 97  from: int,
 98  to: int,
 99  empty: bool,
100}
101
102type editorState = {selection: selection}
103
104@get
105external state: t => editorState = "state"
106
107// Focus and blur commands are in the Commands module
108
109// Set the editable state
110@send
111external setEditable: (t, bool) => unit = "setEditable"
112
113// Commands module - all editor commands are accessed through editor.commands
114module Commands = {
115  // Set the editor content (replaces existing content)
116  @scope("commands") @send
117  external setContent: (t, JSON.t) => unit = "setContent"
118
119  // Insert content at the current cursor position
120  @scope("commands") @send
121  external insertContent: (t, JSON.t) => unit = "insertContent"
122
123  // Insert content at a specific position
124  @scope("commands") @send
125  external insertContentAt: (t, int, JSON.t) => unit = "insertContentAt"
126
127  // Insert content replacing a range (from..to)
128  @scope("commands") @send
129  external insertContentAtRange: (t, range, JSON.t) => unit = "insertContentAt"
130
131  // Focus the editor
132  @scope("commands") @send
133  external focus: t => unit = "focus"
134
135  // Blur the editor (remove focus)
136  @scope("commands") @send
137  external blur: t => unit = "blur"
138
139  // Set metadata on the editor instance
140  @scope("commands") @send
141  external setMeta: (t, string, string) => unit = "setMeta"
142
143  @scope("commands") @send
144  external setMark: (t, string) => unit = "setMark"
145
146  @scope("commands") @send
147  external toggleMark: (t, string) => unit = "toggleMark"
148
149  @scope("commands") @send
150  external unsetAllMarks: t => unit = "unsetAllMarks"
151
152  @scope("commands") @send
153  external setTextSelectionToPosition: (t, int) => unit = "setTextSelection"
154
155  @scope("commands") @send
156  external toggleHeading: (t, {"level": int}) => unit = "toggleHeading"
157}