Preact.res

  1// Preact.res
  2/* Below is a number of aliases to the common `Jsx` module */
  3type element = Jsx.element
  4
  5type component<'props> = Jsx.component<'props>
  6
  7type ref<'value> = {mutable current: 'value}
  8
  9type componentLike<'props, 'return> = Jsx.componentLike<'props, 'return>
 10@module("preact")
 11external render: (Jsx.element, Dom.element) => unit = "render"
 12
 13@module("preact/jsx-runtime")
 14external jsx: (component<'props>, 'props) => element = "jsx"
 15
 16@module("preact/jsx-runtime")
 17external jsxKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsx"
 18
 19@module("preact/jsx-runtime")
 20external jsxs: (component<'props>, 'props) => element = "jsxs"
 21
 22@module("preact/jsx-runtime")
 23external jsxsKeyed: (component<'props>, 'props, ~key: string=?, @ignore unit) => element = "jsxs"
 24
 25/* These identity functions and static values below are optional, but lets
 26you move things easily to the `element` type. The only required thing to
 27define though is `array`, which the JSX transform will output. */
 28external array: array<element> => element = "%identity"
 29@val external null: element = "null"
 30
 31/* option for when you want to conditionally render Some(element) or null */
 32let option = (elem: option<element>): element => {
 33  switch elem {
 34  | Some(elem) => elem
 35  | None => null
 36  }
 37}
 38
 39external float: float => element = "%identity"
 40external int: int => element = "%identity"
 41external string: string => element = "%identity"
 42
 43module ClassList = {
 44  @scope("classList") @send
 45  external add: (Dom.element, string) => unit = "add"
 46
 47  @scope("classList") @send
 48  external remove: (Dom.element, string) => unit = "remove"
 49}
 50
 51/* These are needed for Fragment (<> </>) support */
 52type fragmentProps = {children?: element}
 53
 54@module("preact/jsx-runtime") external jsxFragment: component<fragmentProps> = "Fragment"
 55
 56@module("preact/compat") external createPortal: (element, Dom.element) => unit = "createPortal"
 57
 58/* The Elements module is the equivalent to the ReactDOM module in React. This holds things relevant to _lowercase_ JSX elements. */
 59module Elements = {
 60  /* Here you can control what props lowercase JSX elements should have.
 61  A base that the React JSX transform uses is provided via JsxDOM.domProps,
 62  but you can make this anything. The editor tooling will support
 63  autocompletion etc for your specific type. */
 64  type props = JsxDOM.domProps
 65
 66  @module("preact/jsx-runtime")
 67  external jsx: (string, props) => Jsx.element = "jsx"
 68
 69  @module("preact/jsx-runtime")
 70  external div: (string, props) => Jsx.element = "jsx"
 71
 72  @module("preact/jsx-runtime")
 73  external jsxKeyed: (string, props, ~key: string=?, @ignore unit) => Jsx.element = "jsx"
 74
 75  @module("preact/jsx-runtime")
 76  external jsxs: (string, props) => Jsx.element = "jsxs"
 77
 78  @module("preact/jsx-runtime")
 79  external jsxsKeyed: (string, props, ~key: string=?, @ignore unit) => Jsx.element = "jsxs"
 80
 81  external someElement: element => option<element> = "%identity"
 82}
 83
 84// @module("preact/hooks")
 85// external render: (element, Dom.element) => unit = "render"
 86
 87/* HOOKS */
 88
 89/*
 90 * Yeah, we know this api isn't great. tl;dr: useReducer instead.
 91 * It's because useState can take functions or non-function values and treats
 92 * them differently. Lazy initializer + callback which returns state is the
 93 * only way to safely have any type of state and be able to update it correctly.
 94 */
 95@module("preact/hooks")
 96external useState: (@uncurry (unit => 'state)) => ('state, ('state => 'state) => unit) = "useState"
 97
 98@module("preact/hooks")
 99external useReducer: (@uncurry ('state, 'action) => 'state, 'state) => ('state, 'action => unit) =
100  "useReducer"
101
102@module("preact/hooks")
103external useReducerWithMapState: (
104  @uncurry ('state, 'action) => 'state,
105  'initialState,
106  @uncurry ('initialState => 'state),
107) => ('state, 'action => unit) = "useReducer"
108
109@module("preact/hooks")
110external useEffectOnEveryRender: (@uncurry (unit => option<unit => unit>)) => unit = "useEffect"
111@module("preact/hooks")
112external useEffect: (@uncurry (unit => option<unit => unit>), 'deps) => unit = "useEffect"
113@module("preact/hooks")
114external useEffect0: (@uncurry (unit => option<unit => unit>), @as(json`[]`) _) => unit =
115  "useEffect"
116@module("preact/hooks")
117external useEffect1: (@uncurry (unit => option<unit => unit>), array<'a>) => unit = "useEffect"
118@module("preact/hooks")
119external useEffect2: (@uncurry (unit => option<unit => unit>), ('a, 'b)) => unit = "useEffect"
120@module("preact/hooks")
121external useEffect3: (@uncurry (unit => option<unit => unit>), ('a, 'b, 'c)) => unit = "useEffect"
122@module("preact/hooks")
123external useEffect4: (@uncurry (unit => option<unit => unit>), ('a, 'b, 'c, 'd)) => unit =
124  "useEffect"
125@module("preact/hooks")
126external useEffect5: (@uncurry (unit => option<unit => unit>), ('a, 'b, 'c, 'd, 'e)) => unit =
127  "useEffect"
128@module("preact/hooks")
129external useEffect6: (@uncurry (unit => option<unit => unit>), ('a, 'b, 'c, 'd, 'e, 'f)) => unit =
130  "useEffect"
131@module("preact/hooks")
132external useEffect7: (
133  @uncurry (unit => option<unit => unit>),
134  ('a, 'b, 'c, 'd, 'e, 'f, 'g),
135) => unit = "useEffect"
136
137@module("preact/hooks")
138external useLayoutEffectOnEveryRender: (@uncurry (unit => option<unit => unit>)) => unit =
139  "useLayoutEffect"
140@module("preact/hooks")
141external useLayoutEffect: (@uncurry (unit => option<unit => unit>), 'deps) => unit =
142  "useLayoutEffect"
143@module("preact/hooks")
144external useLayoutEffect0: (@uncurry (unit => option<unit => unit>), @as(json`[]`) _) => unit =
145  "useLayoutEffect"
146@module("preact/hooks")
147external useLayoutEffect1: (@uncurry (unit => option<unit => unit>), array<'a>) => unit =
148  "useLayoutEffect"
149@module("preact/hooks")
150external useLayoutEffect2: (@uncurry (unit => option<unit => unit>), ('a, 'b)) => unit =
151  "useLayoutEffect"
152@module("preact/hooks")
153external useLayoutEffect3: (@uncurry (unit => option<unit => unit>), ('a, 'b, 'c)) => unit =
154  "useLayoutEffect"
155@module("preact/hooks")
156external useLayoutEffect4: (@uncurry (unit => option<unit => unit>), ('a, 'b, 'c, 'd)) => unit =
157  "useLayoutEffect"
158@module("preact/hooks")
159external useLayoutEffect5: (@uncurry (unit => option<unit => unit>), ('a, 'b, 'c, 'd, 'e)) => unit =
160  "useLayoutEffect"
161@module("preact/hooks")
162external useLayoutEffect6: (
163  @uncurry (unit => option<unit => unit>),
164  ('a, 'b, 'c, 'd, 'e, 'f),
165) => unit = "useLayoutEffect"
166@module("preact/hooks")
167external useLayoutEffect7: (
168  @uncurry (unit => option<unit => unit>),
169  ('a, 'b, 'c, 'd, 'e, 'f, 'g),
170) => unit = "useLayoutEffect"
171
172@module("preact/hooks")
173external useMemo: (@uncurry (unit => 'any), 'deps) => 'any = "useMemo"
174
175@module("preact/hooks")
176external useMemo0: (@uncurry (unit => 'any), @as(json`[]`) _) => 'any = "useMemo"
177
178@module("preact/hooks")
179external useMemo1: (@uncurry (unit => 'any), array<'a>) => 'any = "useMemo"
180
181@module("preact/hooks")
182external useMemo2: (@uncurry (unit => 'any), ('a, 'b)) => 'any = "useMemo"
183
184@module("preact/hooks")
185external useMemo3: (@uncurry (unit => 'any), ('a, 'b, 'c)) => 'any = "useMemo"
186
187@module("preact/hooks")
188external useMemo4: (@uncurry (unit => 'any), ('a, 'b, 'c, 'd)) => 'any = "useMemo"
189
190@module("preact/hooks")
191external useMemo5: (@uncurry (unit => 'any), ('a, 'b, 'c, 'd, 'e)) => 'any = "useMemo"
192
193@module("preact/hooks")
194external useMemo6: (@uncurry (unit => 'any), ('a, 'b, 'c, 'd, 'e, 'f)) => 'any = "useMemo"
195
196@module("preact/hooks")
197external useMemo7: (@uncurry (unit => 'any), ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any = "useMemo"
198
199@module("preact/hooks")
200external useCallback: ('f, 'deps) => 'f = "useCallback"
201
202@module("preact/hooks")
203external useCallback0: ('f, @as(json`[]`) _) => 'f = "useCallback"
204
205@module("preact/hooks")
206external useCallback1: ('f, array<'a>) => 'f = "useCallback"
207
208@module("preact/hooks")
209external useCallback2: ('f, ('a, 'b)) => 'f = "useCallback"
210
211@module("preact/hooks")
212external useCallback3: ('f, ('a, 'b, 'c)) => 'f = "useCallback"
213
214@module("preact/hooks")
215external useCallback4: ('f, ('a, 'b, 'c, 'd)) => 'f = "useCallback"
216
217@module("preact/hooks")
218external useCallback5: ('f, ('a, 'b, 'c, 'd, 'e)) => 'f = "useCallback"
219
220@module("preact/hooks")
221external useCallback6: ('callback, ('a, 'b, 'c, 'd, 'e, 'f)) => 'callback = "useCallback"
222
223@module("preact/hooks")
224external useCallback7: ('callback, ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'callback = "useCallback"
225
226// @module("preact/hooks")
227// external useContext: Context.t<'any> => 'any = "useContext"
228
229@module("preact/hooks") external useRef: 'value => ref<'value> = "useRef"
230
231module Signal = {
232  type t<'value>
233
234  @set external set: (t<'value>, 'value) => unit = "value"
235
236  @get external get: t<'value> => 'value = "value"
237  @send external peek: t<'value> => 'value = "peek"
238
239  @module("@preact/signals")
240  external make: 'value => t<'value> = "signal"
241
242  @module("@preact/signals")
243  external computed: (@uncurry (unit => 'value)) => t<'value> = "computed"
244
245  @module("@preact/signals")
246  external effect: (@uncurry (unit => unit)) => unit = "effect"
247
248  @module("@preact/signals")
249  external effectWithCleanup: (@uncurry (unit => option<unit => unit>)) => unit = "effect"
250
251  @module("@preact/signals")
252  external batch: (@uncurry (unit => unit)) => unit = "batch"
253
254  @module("@preact/signals-react")
255  external useSignal: 'value => t<'value> = "useSignal"
256
257  @module("@preact/signals-react")
258  external useComputed: (@uncurry (unit => 'value)) => t<'value> = "useComputed"
259
260  @module("@preact/signals-react/runtime")
261  external useSignals: unit => unit = "useSignals"
262}
263
264//////////////////////////////////////////////////////////
265// Utilities
266//////////////////////////////////////////////////////////
267
268// Helper to conditionally add classes to a base class string
269let cls = (base: string, kv: Dict.t<bool>): string => {
270  Dict.keysToArray(kv)->Array.reduce(base, (out, key) => {
271    if Dict.getUnsafe(kv, key) {
272      out ++ ` ${key}`
273    } else {
274      out
275    }
276  })
277}