Source file skyline_modal_v2.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
open! Core
open! Private_skyline_prelude
let close_on_click_outside_toplayer close_on_click_outside =
let%arr close_on_click_outside in
if close_on_click_outside
then
Bonsai_web_toplayer.Close_on_click_outside.Yes_unless_target_is_popover
else No
;;
let always_open
?(close_on_click_outside = return false)
?(close_on_esc = return true)
?(attrs = return [])
content
~close
(local_ graph)
=
let close_on_click_outside = close_on_click_outside_toplayer close_on_click_outside in
let autoclose =
Bonsai_web_toplayer.Autoclose.create
~close_on_click_outside
~close_on_esc
~close
graph
in
let attrs =
let%arr attrs in
[%css
{|
margin: auto;
border: none;
max-width: 90%;
max-height: 95%;
background-color: transparent;
&::backdrop {
background-color: rgba(0, 0, 0, .4);
}
&:focus-visible, &.for-testing--force-focus-visible {
outline: none;
& > div > [role="dialog"], & > div > dialog {
outline: auto;
}
}
|}]
:: Classes.data_skyline_component "modal"
:: attrs
in
Bonsai_web_toplayer.Modal.always_open
~attrs
~autoclose
~overflow_auto_wrapper:(return false)
~content
graph
;;
let component ?close_on_click_outside ?close_on_esc ?attrs ?state content (local_ graph) =
let state = Option.value_or_thunk state ~default:(fun () -> Bonsai.state false graph) in
let is_open, set_is_open = state in
let%sub () =
if%sub is_open
then (
let close =
let%arr set_is_open in
set_is_open false
in
always_open
?close_on_click_outside
?close_on_esc
?attrs
(content ~close)
~close
graph;
Bonsai.return ())
else Bonsai.return ()
in
let%arr set_is_open in
set_is_open true
;;
let effect ?close_on_click_outside ?close_on_esc ?attrs content graph =
let state, action =
Bonsai.actor
~default_model:Fqueue.empty
~recv:(fun _ model action ->
match action with
| `Open input ->
let ivar = Async_kernel.Ivar.create () in
Fqueue.enqueue model (~input, ~ivar), Some ivar
| `Resolve resolution ->
(match Fqueue.dequeue model with
| None -> Fqueue.empty, None
| Some ((~input:_, ~ivar), tl) ->
Async_kernel.Ivar.fill_exn ivar resolution;
tl, None))
graph
in
let input =
let%arr state in
let%map.Option ~input, ~ivar:_ = Fqueue.peek state in
input
in
let resolve =
let%arr action in
fun a -> action (`Resolve (Some a)) |> Effect.ignore_m
in
let close =
let%arr action in
action (`Resolve None) |> Effect.ignore_m
in
let%sub () =
match%sub input with
| None -> Bonsai.return ()
| Some input ->
always_open
?close_on_click_outside
?close_on_esc
?attrs
(content input ~close ~resolve)
~close
graph;
Bonsai.return ()
in
let%arr action in
fun input ->
match%bind.Effect action (`Open input) with
| Some ivar -> Effect.of_deferred_fun Async_kernel.Ivar.read ivar
| None -> Effect.return None
;;
module Deprecated = struct
let always_open = always_open
end
module For_docs = struct
let ml_filepath = [%here].pos_fname
end