Panel.res
1open Preact
2
3// add a halfway point snap only on mobile
4let snapPoints = Signal.computed(() => {
5 Window.isMobile->Signal.get ? [0., 0.06, 0.5, 1.0] : [0., 0.06, 1.0]
6})
7
8// convenience to know if sheet is minized
9let isMinimized = Signal.make(false)
10
11// control sheet height on resize
12let onResize = (ref: PreactDOM.Ref.currentDomRef) =>
13 () => {
14 Log.debug(
15 "resize",
16 ~kv={
17 "mobile": Window.isMobile->Signal.get,
18 "snap": Sheet.currentSnap(ref),
19 },
20 )
21
22 // this function is a hack, but basically prevents a transition from mobile->desktop that leaves
23 // the sheet in a half-height state before new snap points take effect
24 if !(Window.isMobile->Signal.get) && Sheet.currentSnap(ref) == 2 {
25 Sheet.snapTo(ref, 3)
26 }
27
28 // prevents a minimized sheet in desktop from disappearing on switch to mobile
29 if Window.isMobile->Signal.get && isMinimized->Signal.get {
30 Sheet.snapTo(ref, 1)
31 }
32 }
33
34@jsx.component
35let make = (
36 ~children: Jsx.element,
37 ~onMinimize: option<unit => unit>=?,
38 ~onOpen: option<unit => unit>=?,
39) => {
40 let sheetRef = useRef(Nullable.null)
41 Signal.effect(onResize(sheetRef))
42
43 <Sheet
44 ref={PreactDOM.Ref.domRef(sheetRef)}
45 isOpen={true}
46 onClose={() => Console.debug("closed")}
47 snapPoints={snapPoints->Signal.get}
48 onSnap={(~index) => {
49 if index == 1 {
50 isMinimized->Signal.set(true)
51 switch onMinimize {
52 | Some(fn) => fn()
53 | None => ()
54 }
55 } else {
56 isMinimized->Signal.set(false)
57 switch onOpen {
58 | Some(fn) => fn()
59 | None => ()
60 }
61 }
62 Log.debug("sheet position", ~kv={"from": Sheet.currentSnap(sheetRef), "to": index})
63 }}
64 initialSnap={2}
65 disableDismiss={true}
66 detent={#full}
67 >
68 <Sheet.Container>
69 {Window.isMobile->Signal.get
70 ? <Sheet.Header />
71 : <Sheet.Header>
72 <div className="flex flex-row justify-end w-full px-4">
73 <div
74 className="hover:bg-bg-2 p-2 rounded-sm"
75 onClick={_evt =>
76 if isMinimized->Signal.get {
77 Sheet.snapTo(sheetRef, 2)
78 } else {
79 Sheet.snapTo(sheetRef, 1)
80 }}
81 >
82 <Icons.ChevronDown
83 className={cls("text-ui-2", dict{"rotate-180": isMinimized->Signal.get})}
84 />
85 </div>
86 </div>
87 </Sheet.Header>}
88 <Sheet.Content> {children} </Sheet.Content>
89 </Sheet.Container>
90 </Sheet>
91}