PreactDOM.res

  1module Client = {
  2  module Root = {
  3    type t
  4
  5    @send external render: (t, Preact.element) => unit = "render"
  6
  7    @send external unmount: (t, unit) => unit = "unmount"
  8  }
  9
 10  @module("preact/compat")
 11  external createRoot: Dom.element => Root.t = "createRoot"
 12
 13  @module("preact/compat")
 14  external hydrateRoot: (Dom.element, Preact.element) => Root.t = "hydrateRoot"
 15}
 16
 17// Very rudimentary form data bindings
 18module FormData = {
 19  type t
 20  type file
 21
 22  type formValue =
 23    | String(string)
 24    | File(file)
 25
 26  @new external make: unit => t = "FormData"
 27
 28  @send external append: (t, string, ~filename: string=?) => unit = "append"
 29  @send external delete: (t, string) => unit = "delete"
 30  @return(nullable) @send external getUnsafe: (t, string) => option<'a> = "get"
 31  @send external getAllUnsafe: (t, string) => array<'a> = "getAll"
 32
 33  let getString = (formData, name) => {
 34    switch formData->getUnsafe(name) {
 35    | Some(value) => typeof(value) === #string ? Some(value) : None
 36    | _ => None
 37    }
 38  }
 39
 40  external _asFile: 'a => file = "%identity"
 41
 42  let getFile = (formData, name) => {
 43    switch formData->getUnsafe(name) {
 44    | Some(value) => typeof(value) === #string ? None : Some(value->_asFile)
 45    | _ => None
 46    }
 47  }
 48
 49  let getAll = (t, string) => {
 50    t
 51    ->getAllUnsafe(string)
 52    ->Array.map(value => {
 53      typeof(value) === #string ? String(value) : File(value->_asFile)
 54    })
 55  }
 56
 57  @send external set: (string, string) => unit = "set"
 58  @send external has: string => bool = "has"
 59  // @send external keys: t => Iterator.t<string> = "keys";
 60  // @send external values: t => Iterator.t<value> = "values";
 61}
 62
 63@module("preact/compat")
 64external createPortal: (Preact.element, Dom.element) => Preact.element = "createPortal"
 65
 66external domElementToObj: Dom.element => {..} = "%identity"
 67
 68type domRef = JsxDOM.domRef
 69
 70module Ref = {
 71  type t = domRef
 72  type currentDomRef = Preact.ref<nullable<Dom.element>>
 73  type callbackDomRef = nullable<Dom.element> => option<unit => unit>
 74
 75  external domRef: currentDomRef => domRef = "%identity"
 76  external callbackDomRef: callbackDomRef => domRef = "%identity"
 77}
 78
 79// Raw DOM event listener bindings for internal use
 80@send
 81external _addEventListener: (Dom.element, string, 'event => unit) => unit = "addEventListener"
 82
 83@send
 84external _removeEventListener: (Dom.element, string, 'event => unit) => unit = "removeEventListener"
 85
 86/**
 87 * Helper to add event listener to a DOM element.
 88 * Caller must handle null checking before calling.
 89 * Returns cleanup function to remove the listener.
 90 */
 91let addEventListener = (element: Dom.element, eventName: string, handler: 'event => unit): (
 92  unit => unit
 93) => {
 94  element->_addEventListener(eventName, handler)
 95  () => element->_removeEventListener(eventName, handler)
 96}
 97
 98// HTMLElement focus method binding
 99@send external focus: (Dom.element, unit) => unit = "focus"
100
101// Native DOM KeyboardEvent bindings for document-level handlers
102module KeyboardEvent = {
103  type t
104
105  @get external key: t => string = "key"
106  @get external code: t => string = "code"
107  @get external ctrlKey: t => bool = "ctrlKey"
108  @get external shiftKey: t => bool = "shiftKey"
109  @get external altKey: t => bool = "altKey"
110  @get external metaKey: t => bool = "metaKey"
111  @send external preventDefault: t => unit = "preventDefault"
112  @send external stopPropagation: t => unit = "stopPropagation"
113}
114
115// Native DOM MouseEvent bindings for document-level handlers
116module MouseEvent = {
117  type t
118
119  @get external target: t => Dom.element = "target"
120  @get external clientX: t => int = "clientX"
121  @get external clientY: t => int = "clientY"
122  @send external preventDefault: t => unit = "preventDefault"
123  @send external stopPropagation: t => unit = "stopPropagation"
124}
125
126// HTMLInputElement bindings for form inputs
127module InputElement = {
128  // Type for HTMLInputElement, extends Dom.element
129  type t = Dom.element
130
131  @get external value: t => string = "value"
132  @set external setValue: (t, string) => unit = "value"
133  @get external checked: t => bool = "checked"
134  @set external setChecked: (t, bool) => unit = "checked"
135}
136
137// Form event target accessor - returns the input element from form events
138@get external formTarget: JsxEvent.Form.t => Dom.element = "target"