Seth commited on
Commit
48529af
·
1 Parent(s): 8d2acd1
frontend/src/components/ui/select.jsx CHANGED
@@ -1,4 +1,5 @@
1
  import * as React from "react"
 
2
  import { cn } from "@/lib/utils"
3
  import { ChevronDown } from "lucide-react"
4
 
@@ -7,7 +8,11 @@ const SelectContext = React.createContext(null)
7
  const Select = ({ value, onValueChange, children, ...props }) => {
8
  const [isOpen, setIsOpen] = React.useState(false)
9
  const [internalValue, setInternalValue] = React.useState("")
 
 
 
10
  const currentValue = value !== undefined ? value : internalValue
 
11
  const handleValueChange = (newValue) => {
12
  if (onValueChange) {
13
  onValueChange(newValue)
@@ -17,8 +22,51 @@ const Select = ({ value, onValueChange, children, ...props }) => {
17
  setIsOpen(false)
18
  }
19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  return (
21
- <SelectContext.Provider value={{ value: currentValue, onValueChange: handleValueChange, isOpen, setIsOpen }}>
 
 
 
 
 
 
 
 
 
 
22
  <div className="relative" {...props}>
23
  {children}
24
  </div>
@@ -28,9 +76,14 @@ const Select = ({ value, onValueChange, children, ...props }) => {
28
 
29
  const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => {
30
  const context = React.useContext(SelectContext)
 
 
 
 
 
31
  return (
32
  <button
33
- ref={ref}
34
  type="button"
35
  onClick={() => context?.setIsOpen(!context.isOpen)}
36
  className={cn(
@@ -54,19 +107,43 @@ const SelectValue = ({ placeholder, ...props }) => {
54
 
55
  const SelectContent = React.forwardRef(({ className, children, ...props }, ref) => {
56
  const context = React.useContext(SelectContext)
57
- if (!context?.isOpen) return null
58
 
59
- return (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  <div
61
- ref={ref}
 
62
  className={cn(
63
- "absolute z-50 min-w-[8rem] overflow-hidden rounded-md border bg-white text-slate-950 shadow-md",
 
64
  className
65
  )}
66
  {...props}
67
  >
68
  <div className="p-1">{children}</div>
69
- </div>
 
70
  )
71
  })
72
  SelectContent.displayName = "SelectContent"
 
1
  import * as React from "react"
2
+ import { createPortal } from "react-dom"
3
  import { cn } from "@/lib/utils"
4
  import { ChevronDown } from "lucide-react"
5
 
 
8
  const Select = ({ value, onValueChange, children, ...props }) => {
9
  const [isOpen, setIsOpen] = React.useState(false)
10
  const [internalValue, setInternalValue] = React.useState("")
11
+ const [menuPos, setMenuPos] = React.useState({ top: 0, left: 0, width: 0 })
12
+ const triggerRef = React.useRef(null)
13
+ const menuRef = React.useRef(null)
14
  const currentValue = value !== undefined ? value : internalValue
15
+
16
  const handleValueChange = (newValue) => {
17
  if (onValueChange) {
18
  onValueChange(newValue)
 
22
  setIsOpen(false)
23
  }
24
 
25
+ React.useLayoutEffect(() => {
26
+ if (!isOpen || !triggerRef.current) return
27
+ const r = triggerRef.current.getBoundingClientRect()
28
+ setMenuPos({ top: r.bottom + 4, left: r.left, width: r.width })
29
+ }, [isOpen])
30
+
31
+ React.useEffect(() => {
32
+ if (!isOpen) return
33
+ const reposition = () => {
34
+ if (!triggerRef.current) return
35
+ const r = triggerRef.current.getBoundingClientRect()
36
+ setMenuPos({ top: r.bottom + 4, left: r.left, width: r.width })
37
+ }
38
+ window.addEventListener("scroll", reposition, true)
39
+ window.addEventListener("resize", reposition)
40
+ return () => {
41
+ window.removeEventListener("scroll", reposition, true)
42
+ window.removeEventListener("resize", reposition)
43
+ }
44
+ }, [isOpen])
45
+
46
+ React.useEffect(() => {
47
+ if (!isOpen) return
48
+ const onPointerDown = (e) => {
49
+ const t = triggerRef.current
50
+ const m = menuRef.current
51
+ if (t?.contains(e.target) || m?.contains(e.target)) return
52
+ setIsOpen(false)
53
+ }
54
+ document.addEventListener("pointerdown", onPointerDown)
55
+ return () => document.removeEventListener("pointerdown", onPointerDown)
56
+ }, [isOpen])
57
+
58
  return (
59
+ <SelectContext.Provider
60
+ value={{
61
+ value: currentValue,
62
+ onValueChange: handleValueChange,
63
+ isOpen,
64
+ setIsOpen,
65
+ triggerRef,
66
+ menuRef,
67
+ menuPos,
68
+ }}
69
+ >
70
  <div className="relative" {...props}>
71
  {children}
72
  </div>
 
76
 
77
  const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => {
78
  const context = React.useContext(SelectContext)
79
+ const setRefs = (node) => {
80
+ if (context?.triggerRef) context.triggerRef.current = node
81
+ if (typeof ref === "function") ref(node)
82
+ else if (ref) ref.current = node
83
+ }
84
  return (
85
  <button
86
+ ref={setRefs}
87
  type="button"
88
  onClick={() => context?.setIsOpen(!context.isOpen)}
89
  className={cn(
 
107
 
108
  const SelectContent = React.forwardRef(({ className, children, ...props }, ref) => {
109
  const context = React.useContext(SelectContext)
110
+ const [mounted, setMounted] = React.useState(false)
111
 
112
+ React.useEffect(() => {
113
+ setMounted(true)
114
+ }, [])
115
+
116
+ if (!context?.isOpen || !mounted) return null
117
+
118
+ const { top, left, width } = context.menuPos
119
+ const style = {
120
+ position: "fixed",
121
+ top,
122
+ left,
123
+ minWidth: width > 0 ? width : undefined,
124
+ zIndex: 10050,
125
+ }
126
+
127
+ const setRefs = (node) => {
128
+ if (context?.menuRef) context.menuRef.current = node
129
+ if (typeof ref === "function") ref(node)
130
+ else if (ref) ref.current = node
131
+ }
132
+
133
+ return createPortal(
134
  <div
135
+ ref={setRefs}
136
+ style={style}
137
  className={cn(
138
+ "rounded-md border border-slate-200 bg-white text-slate-950 shadow-lg",
139
+ "max-h-[min(70vh,22rem)] overflow-y-auto overflow-x-hidden",
140
  className
141
  )}
142
  {...props}
143
  >
144
  <div className="p-1">{children}</div>
145
+ </div>,
146
+ document.body
147
  )
148
  })
149
  SelectContent.displayName = "SelectContent"
frontend/src/pages/Deals.jsx CHANGED
@@ -147,7 +147,7 @@ export default function Deals() {
147
  </div>
148
  </div>
149
 
150
- <div className="border border-slate-200 rounded-xl bg-white shadow-sm overflow-hidden">
151
  <button
152
  type="button"
153
  onClick={() => setSectionOpen(!sectionOpen)}
 
147
  </div>
148
  </div>
149
 
150
+ <div className="border border-slate-200 rounded-xl bg-white shadow-sm overflow-visible">
151
  <button
152
  type="button"
153
  onClick={() => setSectionOpen(!sectionOpen)}
frontend/src/pages/Leads.jsx CHANGED
@@ -307,7 +307,7 @@ export default function Leads() {
307
  </div>
308
  </div>
309
 
310
- <div className="border border-slate-200 rounded-xl bg-white shadow-sm overflow-hidden">
311
  <button
312
  type="button"
313
  onClick={() => setSectionOpen(!sectionOpen)}
 
307
  </div>
308
  </div>
309
 
310
+ <div className="border border-slate-200 rounded-xl bg-white shadow-sm overflow-visible">
311
  <button
312
  type="button"
313
  onClick={() => setSectionOpen(!sectionOpen)}