@eggspot/ui 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/eslint.config.js +4 -0
  2. package/package.json +66 -0
  3. package/postcss.config.mjs +1 -0
  4. package/src/components/Button.machine.tsx +50 -0
  5. package/src/components/Button.tsx +249 -0
  6. package/src/components/Button.variants.tsx +186 -0
  7. package/src/components/ButtonGroup.tsx +56 -0
  8. package/src/components/Calendar.tsx +275 -0
  9. package/src/components/Calendar.utils.tsx +22 -0
  10. package/src/components/Checkbox.tsx +199 -0
  11. package/src/components/ConfirmDialog.tsx +183 -0
  12. package/src/components/DashboardLayout/DashboardLayout.tsx +348 -0
  13. package/src/components/DashboardLayout/SidebarNav.tsx +509 -0
  14. package/src/components/DashboardLayout/index.ts +33 -0
  15. package/src/components/DataTable/DataTable.tsx +557 -0
  16. package/src/components/DataTable/DataTableColumnHeader.tsx +122 -0
  17. package/src/components/DataTable/DataTableDisplaySettings.tsx +265 -0
  18. package/src/components/DataTable/DataTableFloatingBar.tsx +44 -0
  19. package/src/components/DataTable/DataTablePagination.tsx +168 -0
  20. package/src/components/DataTable/DataTableStates.tsx +69 -0
  21. package/src/components/DataTable/DataTableToolbarContainer.tsx +47 -0
  22. package/src/components/DataTable/hooks/use-data-table-settings.ts +101 -0
  23. package/src/components/DataTable/index.ts +7 -0
  24. package/src/components/DataTable/types/data-table.ts +97 -0
  25. package/src/components/DatePicker.tsx +213 -0
  26. package/src/components/DatePicker.utils.tsx +38 -0
  27. package/src/components/Datefield.tsx +109 -0
  28. package/src/components/Datefield.utils.ts +10 -0
  29. package/src/components/Dialog.tsx +167 -0
  30. package/src/components/Field.tsx +49 -0
  31. package/src/components/Filter/Filter.store.tsx +122 -0
  32. package/src/components/Filter/Filter.tsx +11 -0
  33. package/src/components/Filter/Filter.types.ts +107 -0
  34. package/src/components/Filter/FilterBar.tsx +38 -0
  35. package/src/components/Filter/FilterBuilder.tsx +158 -0
  36. package/src/components/Filter/FilterField/DateModeRowValue.tsx +250 -0
  37. package/src/components/Filter/FilterField/FilterAsyncSelect.tsx +191 -0
  38. package/src/components/Filter/FilterField/FilterDateMode.tsx +241 -0
  39. package/src/components/Filter/FilterField/FilterDateRange.tsx +169 -0
  40. package/src/components/Filter/FilterField/FilterSelect.tsx +208 -0
  41. package/src/components/Filter/FilterField/FilterSingleDate.tsx +277 -0
  42. package/src/components/Filter/FilterField/OptionItem.tsx +112 -0
  43. package/src/components/Filter/FilterField/index.ts +6 -0
  44. package/src/components/Filter/FilterRow.tsx +527 -0
  45. package/src/components/Filter/index.ts +17 -0
  46. package/src/components/Form.tsx +195 -0
  47. package/src/components/Heading.tsx +41 -0
  48. package/src/components/Input.tsx +221 -0
  49. package/src/components/InputOTP.tsx +78 -0
  50. package/src/components/Label.tsx +65 -0
  51. package/src/components/Layout.tsx +129 -0
  52. package/src/components/ListBox.tsx +97 -0
  53. package/src/components/Menu.tsx +152 -0
  54. package/src/components/NativeSelect.tsx +77 -0
  55. package/src/components/NumberInput.tsx +114 -0
  56. package/src/components/Popover.tsx +44 -0
  57. package/src/components/Provider.tsx +22 -0
  58. package/src/components/RadioGroup.tsx +191 -0
  59. package/src/components/Resizable.tsx +71 -0
  60. package/src/components/ScrollArea.tsx +57 -0
  61. package/src/components/Select.tsx +626 -0
  62. package/src/components/Select.utils.tsx +64 -0
  63. package/src/components/Separator.tsx +25 -0
  64. package/src/components/Sheet.tsx +147 -0
  65. package/src/components/Sonner.tsx +96 -0
  66. package/src/components/Spinner.tsx +30 -0
  67. package/src/components/Switch.tsx +51 -0
  68. package/src/components/Text.tsx +35 -0
  69. package/src/components/Tooltip.tsx +58 -0
  70. package/src/consts/config.ts +2 -0
  71. package/src/hooks/.gitkeep +0 -0
  72. package/src/lib/utils.ts +10 -0
  73. package/tsconfig.json +11 -0
  74. package/tsconfig.lint.json +8 -0
@@ -0,0 +1,348 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ ResizableHandle,
6
+ ResizablePanel,
7
+ ResizablePanelGroup,
8
+ } from "@eggspot/ui/components/Resizable"
9
+ import { ScrollArea } from "@eggspot/ui/components/ScrollArea"
10
+ import { cn } from "@eggspot/ui/lib/utils"
11
+ import type { ImperativePanelHandle } from "react-resizable-panels"
12
+
13
+ // Context for sidebar state
14
+ interface DashboardContextValue {
15
+ sidebarState: "expanded" | "collapsed"
16
+ setSidebarState: (state: "expanded" | "collapsed") => void
17
+ toggleSidebar: () => void
18
+ isMobile: boolean
19
+ expandedGroups: string[]
20
+ toggleGroup: (title: string) => void
21
+ activePath: string
22
+ setActivePath: (path: string) => void
23
+ /** Currently open flyout group (for collapsed sidebar) */
24
+ flyoutGroup: string | null
25
+ setFlyoutGroup: (group: string | null) => void
26
+ closeFlyout: () => void
27
+ /** Sidebar bounding rect for flyout positioning */
28
+ sidebarRect: DOMRect | null
29
+ /** @deprecated Use sidebarRect.width instead */
30
+ sidebarWidth: number
31
+ setSidebarRect: (rect: DOMRect | null) => void
32
+ }
33
+
34
+ const DashboardContext = React.createContext<DashboardContextValue | null>(null)
35
+
36
+ export function useDashboard() {
37
+ const context = React.useContext(DashboardContext)
38
+ if (!context) {
39
+ throw new Error("useDashboard must be used within a DashboardLayout")
40
+ }
41
+ return context
42
+ }
43
+
44
+ export interface DashboardLayoutProps {
45
+ children: React.ReactNode
46
+ /** Default sidebar size as percentage (default: 14) */
47
+ defaultSidebarSize?: number
48
+ /** Minimum sidebar size as percentage (default: 5) */
49
+ minSidebarSize?: number
50
+ /** Maximum sidebar size as percentage (default: 20) */
51
+ maxSidebarSize?: number
52
+ /** Collapsed sidebar size as percentage (default: 5) */
53
+ collapsedSidebarSize?: number
54
+ /** Size threshold to switch to collapsed mode (default: 8) */
55
+ collapseThreshold?: number
56
+ /** Default expanded nav groups */
57
+ defaultExpandedGroups?: string[]
58
+ /** Current active path for highlighting */
59
+ activePath?: string
60
+ className?: string
61
+ }
62
+
63
+ export function DashboardLayout({
64
+ children,
65
+ defaultSidebarSize = 14,
66
+ minSidebarSize = 5,
67
+ maxSidebarSize = 20,
68
+ collapsedSidebarSize = 5,
69
+ collapseThreshold = 7,
70
+ defaultExpandedGroups = [],
71
+ activePath: initialActivePath = "/",
72
+ className,
73
+ }: DashboardLayoutProps) {
74
+ const [sidebarState, setSidebarState] = React.useState<
75
+ "expanded" | "collapsed"
76
+ >("expanded")
77
+ const [isMobile, setIsMobile] = React.useState(false)
78
+ const [expandedGroups, setExpandedGroups] = React.useState<string[]>(
79
+ defaultExpandedGroups
80
+ )
81
+ const [activePath, setActivePath] = React.useState(initialActivePath)
82
+ const [flyoutGroup, setFlyoutGroup] = React.useState<string | null>(null)
83
+ const [sidebarRect, setSidebarRect] = React.useState<DOMRect | null>(null)
84
+ const sidebarPanelRef = React.useRef<ImperativePanelHandle>(null)
85
+
86
+ const closeFlyout = React.useCallback(() => setFlyoutGroup(null), [])
87
+
88
+ const toggleSidebar = React.useCallback(() => {
89
+ const panel = sidebarPanelRef.current
90
+ if (!panel) return
91
+
92
+ if (panel.isCollapsed()) {
93
+ panel.expand()
94
+ } else {
95
+ panel.collapse()
96
+ }
97
+ }, [])
98
+
99
+ const toggleGroup = React.useCallback((title: string) => {
100
+ setExpandedGroups((prev) =>
101
+ prev.includes(title) ? prev.filter((g) => g !== title) : [...prev, title]
102
+ )
103
+ }, [])
104
+
105
+ React.useEffect(() => {
106
+ const checkMobile = () => setIsMobile(window.innerWidth < 768)
107
+ checkMobile()
108
+ window.addEventListener("resize", checkMobile)
109
+ return () => window.removeEventListener("resize", checkMobile)
110
+ }, [])
111
+
112
+ const handleResize = React.useCallback(
113
+ (size: number) => {
114
+ const newState = size <= collapseThreshold ? "collapsed" : "expanded"
115
+ setSidebarState(newState)
116
+ if (newState === "expanded") {
117
+ setFlyoutGroup(null)
118
+ }
119
+ },
120
+ [collapseThreshold]
121
+ )
122
+
123
+ const sidebar = React.Children.toArray(children).find(
124
+ (child) => React.isValidElement(child) && child.type === Sidebar
125
+ )
126
+ const content = React.Children.toArray(children).find(
127
+ (child) => React.isValidElement(child) && child.type === DashboardContent
128
+ )
129
+
130
+ return (
131
+ <DashboardContext.Provider
132
+ value={{
133
+ sidebarState,
134
+ setSidebarState,
135
+ toggleSidebar,
136
+ isMobile,
137
+ expandedGroups,
138
+ toggleGroup,
139
+ activePath,
140
+ setActivePath,
141
+ flyoutGroup,
142
+ setFlyoutGroup,
143
+ closeFlyout,
144
+ sidebarRect,
145
+ sidebarWidth: sidebarRect?.width ?? 0,
146
+ setSidebarRect,
147
+ }}
148
+ >
149
+ <div className={cn("bg-gray-1 h-full", className)}>
150
+ <ResizablePanelGroup direction="horizontal" className="h-full">
151
+ <ResizablePanel
152
+ ref={sidebarPanelRef}
153
+ order={1}
154
+ defaultSize={defaultSidebarSize}
155
+ minSize={minSidebarSize}
156
+ maxSize={maxSidebarSize}
157
+ collapsible
158
+ collapsedSize={collapsedSidebarSize}
159
+ onResize={handleResize}
160
+ >
161
+ {sidebar}
162
+ </ResizablePanel>
163
+
164
+ <ResizableHandle />
165
+
166
+ <ResizablePanel
167
+ order={2}
168
+ defaultSize={100 - defaultSidebarSize}
169
+ minSize={60}
170
+ >
171
+ {content}
172
+ </ResizablePanel>
173
+ </ResizablePanelGroup>
174
+ </div>
175
+ </DashboardContext.Provider>
176
+ )
177
+ }
178
+
179
+ // Sidebar Component
180
+ export interface SidebarProps {
181
+ children: React.ReactNode
182
+ className?: string
183
+ }
184
+
185
+ export function Sidebar({ children, className }: SidebarProps) {
186
+ const { sidebarState, setSidebarRect } = useDashboard()
187
+ const sidebarRef = React.useRef<HTMLDivElement>(null)
188
+
189
+ // Update sidebar rect on resize and scroll
190
+ React.useEffect(() => {
191
+ const element = sidebarRef.current
192
+ if (!element) return
193
+
194
+ const updateRect = () => {
195
+ setSidebarRect(element.getBoundingClientRect())
196
+ }
197
+
198
+ const observer = new ResizeObserver(() => {
199
+ updateRect()
200
+ })
201
+
202
+ observer.observe(element)
203
+ updateRect()
204
+
205
+ // Also listen for scroll events in case sidebar moves
206
+ window.addEventListener("scroll", updateRect, true)
207
+
208
+ return () => {
209
+ observer.disconnect()
210
+ window.removeEventListener("scroll", updateRect, true)
211
+ }
212
+ }, [setSidebarRect])
213
+
214
+ return (
215
+ <div
216
+ ref={sidebarRef}
217
+ className={cn(
218
+ "flex h-full flex-col overflow-hidden",
219
+ "from-gray-2 to-gray-1 bg-linear-to-b",
220
+ className
221
+ )}
222
+ data-state={sidebarState}
223
+ >
224
+ {children}
225
+ </div>
226
+ )
227
+ }
228
+
229
+ // Sidebar Header (Logo area)
230
+ export interface SidebarHeaderProps {
231
+ children: React.ReactNode
232
+ className?: string
233
+ }
234
+
235
+ export function SidebarHeader({ children, className }: SidebarHeaderProps) {
236
+ const { sidebarState } = useDashboard()
237
+
238
+ return (
239
+ <div
240
+ className={cn(
241
+ "flex shrink-0 items-center p-4 pb-0",
242
+ sidebarState === "collapsed"
243
+ ? "flex-col justify-center gap-2 px-3 pt-4"
244
+ : "justify-between",
245
+ className
246
+ )}
247
+ >
248
+ {children}
249
+ </div>
250
+ )
251
+ }
252
+
253
+ // Sidebar Nav Container
254
+ export interface SidebarNavProps {
255
+ children: React.ReactNode
256
+ className?: string
257
+ }
258
+
259
+ export function SidebarNav({ children, className }: SidebarNavProps) {
260
+ return (
261
+ <ScrollArea
262
+ className={cn(
263
+ "min-h-0 flex-1 overflow-hidden",
264
+ "[&>[data-slot=scroll-area-viewport]>div]:!block",
265
+ className
266
+ )}
267
+ >
268
+ <nav className="px-3 py-2">
269
+ <div className="space-y-2">{children}</div>
270
+ </nav>
271
+ </ScrollArea>
272
+ )
273
+ }
274
+
275
+ // Sidebar Footer (pinned to bottom)
276
+ export interface SidebarFooterProps {
277
+ children: React.ReactNode
278
+ className?: string
279
+ }
280
+
281
+ export function SidebarFooter({ children, className }: SidebarFooterProps) {
282
+ const { sidebarState } = useDashboard()
283
+
284
+ return (
285
+ <div
286
+ className={cn(
287
+ "border-gray-6/50 mt-auto shrink-0 border-t p-3",
288
+ sidebarState === "collapsed" && "py-3",
289
+ className
290
+ )}
291
+ >
292
+ <div className="space-y-1.5">{children}</div>
293
+ </div>
294
+ )
295
+ }
296
+
297
+ // Dashboard Content Area
298
+ export interface DashboardContentProps {
299
+ children: React.ReactNode
300
+ className?: string
301
+ }
302
+
303
+ export function DashboardContent({
304
+ children,
305
+ className,
306
+ }: DashboardContentProps) {
307
+ return (
308
+ <div
309
+ className={cn(
310
+ "bg-gray-1 flex h-full flex-col overflow-hidden",
311
+ className
312
+ )}
313
+ >
314
+ {children}
315
+ </div>
316
+ )
317
+ }
318
+
319
+ // Dashboard Header (in main content area)
320
+ export interface DashboardHeaderProps {
321
+ children?: React.ReactNode
322
+ className?: string
323
+ }
324
+
325
+ export function DashboardHeader({ children, className }: DashboardHeaderProps) {
326
+ return (
327
+ <header
328
+ className={cn(
329
+ "border-gray-6 flex h-14 shrink-0 items-center justify-between border-b px-4",
330
+ className
331
+ )}
332
+ >
333
+ {children}
334
+ </header>
335
+ )
336
+ }
337
+
338
+ // Dashboard Main Content
339
+ export interface DashboardMainProps {
340
+ children: React.ReactNode
341
+ className?: string
342
+ }
343
+
344
+ export function DashboardMain({ children, className }: DashboardMainProps) {
345
+ return (
346
+ <main className={cn("flex-1 overflow-auto", className)}>{children}</main>
347
+ )
348
+ }