package bonsai

  1. Overview
  2. Docs
A library for building dynamic webapps, using Js_of_ocaml

Install

dune-project
 Dependency

Authors

Maintainers

Sources

v0.17.0.tar.gz
sha256=c78c4476ee6b856846e2d0941e5965009d5e1b853e564b2b1bee61202f0b1ebb

doc/src/bonsai.web_ui_view/bonsai_web_ui_view.ml.html

Source file bonsai_web_ui_view.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
open! Core
open! Import
module Constants = Constants
module Fg_bg = Constants.Fg_bg
module Intent = Constants.Intent
module Card_title_kind = Constants.Card_title_kind
module Font_style = Constants.Font_style
module Font_size = Constants.Font_size
module Table = Table
include Layout

let primary_colors ((module T) : Theme.t) = T.singleton#constants.primary
let extreme_colors ((module T) : Theme.t) = T.singleton#constants.extreme

let extreme_primary_border_color ((module T) : Theme.t) =
  T.singleton#constants.extreme_primary_border
;;

let intent_colors ((module T) : Theme.t) (intent : Intent.t) =
  let { Intent.info; success; warning; error } = T.singleton#constants.intent in
  match intent with
  | Info -> info
  | Success -> success
  | Warning -> warning
  | Error -> error
;;

let button
  ((module T) : Theme.t)
  ?(attrs = [])
  ?(disabled = false)
  ?intent
  ?tooltip
  ~on_click
  text
  =
  T.singleton#button ~attrs ~disabled ~intent ~tooltip ~on_click [ Vdom.Node.text text ]
;;

let button'
  ((module T) : Theme.t)
  ?(attrs = [])
  ?(disabled = false)
  ?intent
  ?tooltip
  ~on_click
  content
  =
  T.singleton#button ~attrs ~disabled ~intent ~tooltip ~on_click content
;;

let badge ((module T) : Theme.t) ?(attrs = []) ?intent ?on_dismiss text =
  T.singleton#badge ~attrs ~intent ~on_dismiss [ Vdom.Node.text text ]
;;

let badge' ((module T) : Theme.t) ?(attrs = []) ?intent ?on_dismiss content =
  T.singleton#badge ~attrs ~intent ~on_dismiss content
;;

let tabs
  ((module T) : Theme.t)
  ?(attrs = [])
  ?(per_tab_attrs = fun _ ~is_active:_ -> [])
  ~equal
  ~on_change
  ~active
  tabs
  =
  T.singleton#tabs ~attrs ~per_tab_attrs ~on_change ~equal ~active tabs
;;

module type Enum = sig
  type t [@@deriving enumerate, equal, sexp_of]
end

let tabs_enum
  (type a)
  ((module T) : Theme.t)
  ?(attrs = [])
  ?(per_tab_attrs = fun _ ~is_active:_ -> [])
  ?tab_to_vdom
  (module A : Enum with type t = a)
  ~on_change
  ~active
  =
  let tab_to_vdom =
    Option.value tab_to_vdom ~default:(fun tab ->
      Vdom.Node.text (T.singleton#humanize_sexp (A.sexp_of_t tab)))
  in
  let tabs = List.map A.all ~f:(fun tab -> tab, tab_to_vdom tab) in
  T.singleton#tabs ~attrs ~per_tab_attrs ~on_change ~equal:A.equal ~active tabs
;;

let devbar ((module T) : Theme.t) ?(attrs = []) ?(count = 100) ?intent text =
  T.singleton#devbar ~attrs ~count ~intent text
;;

let constants ((module T) : Theme.t) = T.singleton#constants
let text ?attrs s = Vdom.Node.span ?attrs [ Vdom.Node.text s ]
let textf ?attrs format = Printf.ksprintf (text ?attrs) format

let themed_text ((module T) : Theme.t) ?(attrs = []) ?intent ?style ?size text =
  T.singleton#themed_text ~attrs ~intent ~style ~size text
;;

let themed_textf theme ?attrs ?intent ?style ?size format =
  Printf.ksprintf (themed_text theme ?attrs ?intent ?style ?size) format
;;

module Tooltip_direction = Tooltip.Direction

let tooltip'
  ((module T) : Theme.t)
  ?(container_attrs = [])
  ?(tooltip_attrs = [])
  ?(direction = Tooltip.Direction.Top)
  ~tooltip
  tipped
  =
  T.singleton#tooltip ~container_attrs ~tooltip_attrs ~direction ~tipped ~tooltip
;;

let tooltip theme ?container_attrs ?tooltip_attrs ?direction ~tooltip tipped =
  let tipped = Vdom.Node.text tipped in
  let tooltip = Vdom.Node.text tooltip in
  tooltip' theme ?container_attrs ?tooltip_attrs ?direction ~tooltip tipped
;;

let card'
  ((module T) : Theme.t)
  ?(container_attrs = [])
  ?(title_attrs = [])
  ?(content_attrs = [])
  ?intent
  ?(title = [])
  ?(title_kind = Card_title_kind.Prominent)
  ?(on_click = Effect.Ignore)
  content
  =
  T.singleton#card
    ~container_attrs
    ~title_attrs
    ~content_attrs
    ~intent
    ~on_click
    ~title
    ~title_kind
    ~content
;;

let card
  theme
  ?container_attrs
  ?title_attrs
  ?content_attrs
  ?intent
  ?title
  ?title_kind
  ?on_click
  content
  =
  card'
    theme
    ?container_attrs
    ?title_attrs
    ?content_attrs
    ?intent
    ?title:(Option.map title ~f:(fun title -> [ Vdom.Node.text title ]))
    ?title_kind
    ?on_click
    [ Vdom.Node.text content ]
;;

module App = struct
  let top_attr ((module T) : Theme.t) = T.singleton#app_attr
end

let theme_dyn_var =
  Bonsai.Dynamic_scope.create ~name:"web-ui theme" ~fallback:Expert.default_theme ()
;;

let current_theme = Bonsai.Dynamic_scope.lookup theme_dyn_var

module Form_inputs = struct
  let textbox
    ((module T) : Theme.t)
    ?attrs
    ?placeholder
    ?key
    ~allow_updates_when_focused
    ~disabled
    ~value
    ~set_value
    ()
    =
    T.singleton#textbox
      ?attrs
      ?placeholder
      ?key
      ~allow_updates_when_focused
      ~disabled
      ~value
      ~set_value
      ()
  ;;

  let password
    ((module T) : Theme.t)
    ?attrs
    ?placeholder
    ?key
    ~allow_updates_when_focused
    ~disabled
    ~value
    ~set_value
    ()
    =
    T.singleton#password
      ?attrs
      ?placeholder
      ?key
      ~allow_updates_when_focused
      ~disabled
      ~value
      ~set_value
      ()
  ;;

  let textarea
    ((module T) : Theme.t)
    ?attrs
    ?placeholder
    ?key
    ~allow_updates_when_focused
    ~disabled
    ~value
    ~set_value
    ()
    =
    T.singleton#textarea
      ?attrs
      ?placeholder
      ?key
      ~allow_updates_when_focused
      ~disabled
      ~value
      ~set_value
      ()
  ;;

  let number
    ((module T) : Theme.t)
    ?attrs
    ?placeholder
    ?min
    ?max
    ?key
    ~allow_updates_when_focused
    ~disabled
    ~step
    ~value
    ~set_value
    ()
    =
    T.singleton#number
      ?attrs
      ?placeholder
      ?min
      ?max
      ?key
      ~allow_updates_when_focused
      ~disabled
      ~step
      ~value
      ~set_value
      ()
  ;;

  let range
    ((module T) : Theme.t)
    ?attrs
    ?min
    ?max
    ?key
    ~allow_updates_when_focused
    ~disabled
    ~step
    ~value
    ~set_value
    ()
    =
    T.singleton#range
      ?attrs
      ?min
      ?max
      ?key
      ~allow_updates_when_focused
      ~disabled
      ~step
      ~value
      ~set_value
      ()
  ;;
end

module For_components = struct
  module Codemirror = struct
    let theme ((module T) : Theme.t) = T.singleton#codemirror_theme
  end

  module Forms = struct
    let to_vdom ((module T) : Theme.t) ?on_submit ?(editable = `Yes_always) =
      T.singleton#form_to_vdom ?on_submit ~eval_context:(Form_context.default ~editable)
    ;;

    let to_vdom_plain ((module T) : Theme.t) ?(editable = `Yes_always) =
      Form.to_vdom_plain T.singleton ~eval_context:(Form_context.default ~editable)
    ;;

    let view_error ((module T) : Theme.t) = T.singleton#form_view_error

    let append_item ((module T) : Theme.t) ?(editable = `Yes_always) =
      T.singleton#form_append_item ~eval_context:(Form_context.default ~editable)
    ;;

    let remove_item ((module T) : Theme.t) ?(editable = `Yes_always) =
      T.singleton#form_remove_item ~eval_context:(Form_context.default ~editable)
    ;;
  end

  module Prt = struct
    let styling ((module T) : Theme.t) = T.singleton#prt_styling
  end
end

module Expert = struct
  open Bonsai.Let_syntax
  include Expert

  let set_theme_for_computation theme inside =
    Bonsai.Dynamic_scope.set theme_dyn_var theme ~inside
  ;;

  let override_theme_for_computation ~f inside =
    let%sub current_theme = current_theme in
    let%sub new_theme =
      let%arr current_theme = current_theme in
      override_theme current_theme ~f
    in
    set_theme_for_computation new_theme inside
  ;;

  let override_constants = Theme.override_constants

  module For_codemirror = For_codemirror
  module Form_context = Form_context
end

module Theme = struct
  open Bonsai.Let_syntax

  type t = Theme.t

  let name = Theme.name
  let current = current_theme
  let set_for_computation theme inside = Expert.set_theme_for_computation theme inside

  let rec with_attr attrs (vdom : Vdom.Node.t) =
    match vdom with
    | None -> Vdom.Node.div ~attrs []
    | Fragment children -> Vdom.Node.div ~attrs children
    | Text _ -> Vdom.Node.span ~attrs [ vdom ]
    | Element e ->
      Element
        (Vdom.Node.Element.map_attrs e ~f:(fun xs -> Vdom.Attr.many (attrs @ [ xs ])))
    | Widget _ -> Vdom.Node.div ~attrs [ vdom ]
    | Lazy { key; t } -> Lazy { key; t = Lazy.map t ~f:(with_attr attrs) }
  ;;

  let set_for_app theme app =
    let%sub app_vdom = set_for_computation theme app in
    let%arr app_vdom = app_vdom
    and theme = theme in
    with_attr [ force (App.top_attr theme) ] app_vdom
  ;;

  let set_for_app' theme app =
    let%sub result_and_vdom = set_for_computation theme app in
    let%arr result, app_vdom = result_and_vdom
    and theme = theme in
    result, with_attr [ force (App.top_attr theme) ] app_vdom
  ;;

  let override_constants_for_computation ~f inside =
    let%sub current_theme = current_theme in
    let%sub new_theme =
      let%arr current_theme = current_theme in
      Theme.override_constants current_theme ~f
    in
    Expert.set_theme_for_computation new_theme inside
  ;;
end

module Raw = struct
  module Table = Table.Raw
end