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"