Source file combobox_popover.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
open! Core
open! Private_skyline_prelude
module Toplayer = Bonsai_web_toplayer
module Js = Js_of_ocaml.Js

let popover_attrs =
  [ [%css
      {|
        display: grid;
        grid-auto-flow: row;
        padding: 0;
        border: none;
        background: none;
      |}]
  ]
;;

let anchor_data_attr = "data-combobox-input-anchor"

let target_is_inside_anchor ~anchor_id ~target =
  let selector = Js.string [%string "[%{anchor_data_attr}=\"%{anchor_id}\"]"] in
  match Js.Opt.to_option target with
  | None -> false
  | Some element -> Js.Opt.test (element##closest selector)
;;

let component ~is_open ~close ~content (local_ graph) =
  let anchor_id = Bonsai.path_id graph in
  let close_on_click_outside =
    let%arr anchor_id in
    Toplayer.Close_on_click_outside.Custom
      (fun ~target ->
        let inside_popover =
          Toplayer.Close_on_click_outside.is_target_inside_a_popover ~target
        in
        let inside_anchor = target_is_inside_anchor ~anchor_id ~target in
        if inside_popover || inside_anchor then `Don't_close else `Close)
  in
  let autoclose =
    Toplayer.Autoclose.create
      ~close
      ~close_on_click_outside
      ~close_on_right_click_outside:close_on_click_outside
      ~close_on_esc:(return true)
      graph
  in
  let popover_anchor_attr =
    match%sub is_open with
    | true ->
      Toplayer.Popover.always_open
        ~attrs:(return popover_attrs)
        ~autoclose
        ~position:(return Toplayer.Position.Bottom)
        ~alignment:(return Toplayer.Alignment.Start)
        ~match_anchor_side_length:(return (Some Toplayer.Match_anchor_side.Match_exactly))
        ~focus_on_open:(return false)
        ~overflow_auto_wrapper:(return false)
        ~content
        graph
    | false -> return Attr.empty
  in
  let%arr popover_anchor_attr and anchor_id in
  Attr.many [ popover_anchor_attr; Attr.create anchor_data_attr anchor_id ]
;;