package bonsai

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file table_header.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
open! Core
open! Bonsai_web
open! Js_of_ocaml
open! Incr_map_collate
open! Bonsai.Let_syntax


let attr_colspan i =
  match i with
  | 0 -> Vdom.Attr.style (Css_gen.display `None)
  | 1 -> Vdom.Attr.empty
  | i -> Vdom.Attr.create_float "colspan" (Int.to_float i)
;;

module Acc = struct
  type t =
    { level_map : Vdom.Node.t list Int.Map.t
    ; leaf_index : int
    }

  let empty = { level_map = Int.Map.empty; leaf_index = 0 }

  let visit_leaf { level_map; leaf_index } ~level ~node =
    let idx = leaf_index in
    let leaf_index = leaf_index + 1 in
    let level_map = Map.add_multi (level_map : _ Int.Map.t) ~key:level ~data:(node idx) in
    { leaf_index; level_map }
  ;;

  let visit_non_leaf { level_map; leaf_index } ~level ~node =
    let level_map = Map.add_multi (level_map : _ Int.Map.t) ~key:level ~data:node in
    { leaf_index; level_map }
  ;;

  let finalize { level_map; leaf_index = _ } =
    level_map |> Map.data |> List.map ~f:(fun seq -> Vdom.Node.tr (List.rev seq))
  ;;
end

let rec render_header header ~level ~acc ~column_widths ~set_column_width =
  let recurse = render_header ~level:(level + 1) ~column_widths ~set_column_width in
  let recurse_no_level_change = render_header ~level ~column_widths ~set_column_width in
  let colspan = attr_colspan (Header_tree.colspan header) in
  match header with
  | Leaf { visible; leaf_label; initial_width } ->
    let node index =
      let column_width =
        match Map.find column_widths index with
        | Some (Column_size.Visible { width_px = width })
        | Some (Hidden { prev_width_px = Some width }) -> `Px_float width
        | None | Some (Hidden { prev_width_px = None }) -> initial_width
      in
      Vdom.Node.td
        ~attrs:
          [ Bonsai_web_ui_element_size_hooks.Size_tracker.on_change
              (fun ~width ~height:_ -> set_column_width ~index (`Px_float width))
          ; Vdom.Attr.colspan 1
          ; Style.header_label
          ; Style.leaf_header
          ; Vdom.Attr.style
              Css_gen.(width column_width @> if visible then empty else display `None)
          ]
        [ leaf_label ]
    in
    Acc.visit_leaf acc ~level ~node
  | Spacer inside ->
    let node = Vdom.Node.td ~attrs:[ colspan ] [] in
    let acc = Acc.visit_non_leaf acc ~level ~node in
    recurse inside ~acc
  | Group { children; group_label } ->
    let attrs = Vdom.Attr.many [ colspan; Style.header_label ] in
    let node = Vdom.Node.td ~attrs:[ attrs ] [ group_label ] in
    let acc = Acc.visit_non_leaf acc ~level ~node in
    List.fold children ~init:acc ~f:(fun acc -> recurse ~acc)
  | Organizational_group children ->
    List.fold children ~init:acc ~f:(fun acc -> recurse_no_level_change ~acc)
;;

let render_header headers ~column_widths ~set_column_width =
  headers
  |> render_header ~acc:Acc.empty ~level:0 ~column_widths ~set_column_width
  |> Acc.finalize
;;

let component
      (headers : Header_tree.t Value.t)
      ~column_widths
      ~set_column_width
      ~set_header_client_rect
  =
  let%arr set_column_width = set_column_width
  and set_header_client_rect = set_header_client_rect
  and headers = headers
  and column_widths = column_widths in
  let rows = render_header headers ~set_column_width ~column_widths in
  Vdom.Node.table
    ~attrs:
      [ Bonsai_web_ui_element_size_hooks.Visibility_tracker.detect
          ()
          ~client_rect_changed:set_header_client_rect
      ; Style.partial_render_table_header
      ; Vdom.Attr.class_ "prt-table-header"
      ]
    [ Vdom.Node.tbody rows ]
;;
OCaml

Innovation. Community. Security.