@moontra/moonui 2.0.7 → 2.0.9

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 (94) hide show
  1. package/package.json +26 -19
  2. package/src/__tests__/use-intersection-observer.test.tsx +216 -0
  3. package/src/__tests__/use-local-storage.test.tsx +174 -0
  4. package/src/__tests__/use-pro-access.test.tsx +183 -0
  5. package/src/components/ui/__tests__/accordion.test.tsx +571 -0
  6. package/src/components/ui/__tests__/alert.test.tsx +484 -0
  7. package/src/components/ui/__tests__/aspect-ratio.test.tsx +492 -0
  8. package/src/components/ui/__tests__/avatar.test.tsx +382 -0
  9. package/src/components/ui/__tests__/badge.test.tsx +364 -0
  10. package/src/components/ui/__tests__/breadcrumb.test.tsx +687 -0
  11. package/src/components/ui/__tests__/button.test.tsx +91 -0
  12. package/src/components/ui/__tests__/card.test.tsx +104 -0
  13. package/src/components/ui/__tests__/checkbox.test.tsx +591 -0
  14. package/src/components/ui/__tests__/collapsible.test.tsx +592 -0
  15. package/src/components/ui/__tests__/color-picker.test.tsx +365 -0
  16. package/src/components/ui/__tests__/command.test.tsx +677 -0
  17. package/src/components/ui/__tests__/data-table.test.tsx +256 -0
  18. package/src/components/ui/__tests__/date-picker.test.tsx +320 -0
  19. package/src/components/ui/__tests__/dialog.test.tsx +764 -0
  20. package/src/components/ui/__tests__/input.test.tsx +318 -0
  21. package/src/components/ui/__tests__/label.test.tsx +103 -0
  22. package/src/components/ui/__tests__/popover.test.tsx +637 -0
  23. package/src/components/ui/__tests__/progress.test.tsx +382 -0
  24. package/src/components/ui/__tests__/radio-group.test.tsx +555 -0
  25. package/src/components/ui/__tests__/select.test.tsx +705 -0
  26. package/src/components/ui/__tests__/skeleton.test.tsx +253 -0
  27. package/src/components/ui/__tests__/slider.test.tsx +493 -0
  28. package/src/components/ui/__tests__/switch.test.tsx +372 -0
  29. package/src/components/ui/__tests__/table.test.tsx +824 -0
  30. package/src/components/ui/__tests__/tabs.test.tsx +887 -0
  31. package/src/components/ui/__tests__/toast.test.tsx +458 -0
  32. package/src/components/ui/__tests__/tooltip.test.tsx +583 -0
  33. package/src/components/ui/accordion.tsx +63 -0
  34. package/src/components/ui/alert.tsx +130 -0
  35. package/src/components/ui/aspect-ratio.tsx +72 -0
  36. package/src/components/ui/avatar.tsx +135 -0
  37. package/src/components/ui/badge.tsx +225 -0
  38. package/src/components/ui/breadcrumb.tsx +207 -0
  39. package/src/components/ui/button.stories.tsx +162 -0
  40. package/src/components/ui/button.tsx +221 -0
  41. package/src/components/ui/calendar.tsx +262 -0
  42. package/src/components/ui/card.stories.tsx +208 -0
  43. package/src/components/ui/card.tsx +141 -0
  44. package/src/components/ui/checkbox.tsx +256 -0
  45. package/src/components/ui/collapsible.tsx +129 -0
  46. package/src/components/ui/color-picker.tsx +664 -0
  47. package/src/components/ui/command.tsx +218 -0
  48. package/src/components/ui/data-table.stories.tsx +509 -0
  49. package/src/components/ui/data-table.tsx +623 -0
  50. package/src/components/ui/date-picker.stories.tsx +321 -0
  51. package/src/components/ui/date-picker.tsx +603 -0
  52. package/src/components/ui/dialog.tsx +332 -0
  53. package/src/components/ui/dropdown-menu.tsx +200 -0
  54. package/src/components/ui/file-upload.tsx +400 -0
  55. package/src/components/ui/github-stars.tsx +201 -0
  56. package/src/components/ui/index.ts +12 -0
  57. package/src/components/ui/input.stories.tsx +255 -0
  58. package/src/components/ui/input.tsx +219 -0
  59. package/src/components/ui/label.tsx +26 -0
  60. package/src/components/ui/locked-component.tsx +215 -0
  61. package/src/components/ui/moon-logo.tsx +97 -0
  62. package/src/components/ui/pagination.tsx +116 -0
  63. package/src/components/ui/popover.tsx +183 -0
  64. package/src/components/ui/progress.tsx +182 -0
  65. package/src/components/ui/radio-group.tsx +243 -0
  66. package/src/components/ui/select.tsx +273 -0
  67. package/src/components/ui/separator.tsx +140 -0
  68. package/src/components/ui/simple-editor.tsx +652 -0
  69. package/src/components/ui/skeleton.tsx +351 -0
  70. package/src/components/ui/slider.tsx +351 -0
  71. package/src/components/ui/switch.tsx +83 -0
  72. package/src/components/ui/table.tsx +322 -0
  73. package/src/components/ui/tabs.tsx +195 -0
  74. package/src/components/ui/textarea.tsx +46 -0
  75. package/src/components/ui/toast.tsx +313 -0
  76. package/src/components/ui/toggle.tsx +47 -0
  77. package/src/components/ui/tooltip.tsx +152 -0
  78. package/src/docs/theme-system.md +1194 -0
  79. package/src/index.tsx +39 -0
  80. package/src/lib/micro-interactions.ts +255 -0
  81. package/src/lib/theme.tsx +398 -0
  82. package/src/lib/utils.ts +69 -0
  83. package/src/styles/design-system.css +365 -0
  84. package/src/styles/index.css +4 -0
  85. package/src/styles/tailwind.css +6 -0
  86. package/src/styles/tokens.css +453 -0
  87. package/src/use-intersection-observer.tsx +154 -0
  88. package/src/use-local-storage.tsx +71 -0
  89. package/src/use-paddle.ts +138 -0
  90. package/src/use-performance-optimizer.ts +379 -0
  91. package/src/use-pro-access.ts +141 -0
  92. package/src/use-scroll-animation.ts +221 -0
  93. package/src/use-subscription.ts +37 -0
  94. package/src/use-toast.ts +32 -0
@@ -0,0 +1,764 @@
1
+ import React from 'react'
2
+ import { render, screen, fireEvent } from '@testing-library/react'
3
+ import '@testing-library/jest-dom'
4
+ import {
5
+ Dialog,
6
+ DialogTrigger,
7
+ DialogContent,
8
+ DialogHeader,
9
+ DialogFooter,
10
+ DialogTitle,
11
+ DialogDescription,
12
+ DialogClose,
13
+ DialogForm,
14
+ } from '../dialog'
15
+
16
+ // Mock Radix UI Dialog components
17
+ /* eslint-disable @typescript-eslint/no-explicit-any */
18
+ jest.mock('@radix-ui/react-dialog', () => {
19
+ const mockForwardRef = (component: any) => {
20
+ const forwardedComponent = (props: any, ref: any) => component({ ...props, ref })
21
+ forwardedComponent.displayName = component.displayName || component.name
22
+ return forwardedComponent
23
+ }
24
+
25
+ return {
26
+ Root: ({ children, open, ...props }: any) => (
27
+ <div data-testid="dialog-root" data-open={open} {...props}>
28
+ {children}
29
+ </div>
30
+ ),
31
+ Trigger: ({ children, ...props }: any) => (
32
+ <button data-testid="dialog-trigger" {...props}>
33
+ {children}
34
+ </button>
35
+ ),
36
+ Portal: ({ children }: any) => (
37
+ <div data-testid="dialog-portal">{children}</div>
38
+ ),
39
+ Overlay: mockForwardRef(({ className, ref, ...props }: any) => (
40
+ <div
41
+ ref={ref}
42
+ data-testid="dialog-overlay"
43
+ className={className}
44
+ {...props}
45
+ />
46
+ )),
47
+ Content: mockForwardRef(({ className, children, ref, ...props }: any) => (
48
+ <div
49
+ ref={ref}
50
+ data-testid="dialog-content"
51
+ className={className}
52
+ {...props}
53
+ >
54
+ {children}
55
+ </div>
56
+ )),
57
+ Close: ({ children, onClick, ...props }: any) => (
58
+ <button data-testid="dialog-close" onClick={onClick} {...props}>
59
+ {children}
60
+ </button>
61
+ ),
62
+ Title: mockForwardRef(({ className, children, ref, ...props }: any) => (
63
+ <h2 ref={ref} data-testid="dialog-title" className={className} {...props}>
64
+ {children}
65
+ </h2>
66
+ )),
67
+ Description: mockForwardRef(({ className, children, ref, ...props }: any) => (
68
+ <p ref={ref} data-testid="dialog-description" className={className} {...props}>
69
+ {children}
70
+ </p>
71
+ )),
72
+ }
73
+ })
74
+
75
+ // Mock Lucide React icons
76
+ jest.mock('lucide-react', () => ({
77
+ X: ({ className, ...props }: any) => (
78
+ <svg data-testid="x-icon" className={className} {...props}>
79
+ <path d="x" />
80
+ </svg>
81
+ ),
82
+ Check: ({ className, ...props }: any) => (
83
+ <svg data-testid="check-icon" className={className} {...props}>
84
+ <path d="check" />
85
+ </svg>
86
+ ),
87
+ Loader2: ({ className, ...props }: any) => (
88
+ <svg data-testid="loader-icon" className={className} {...props}>
89
+ <path d="loader" />
90
+ </svg>
91
+ ),
92
+ }))
93
+
94
+ describe('Dialog Components', () => {
95
+ describe('Dialog Root Component', () => {
96
+ it('renders correctly', () => {
97
+ render(
98
+ <Dialog>
99
+ <DialogTrigger>Open Dialog</DialogTrigger>
100
+ <DialogContent>Dialog Content</DialogContent>
101
+ </Dialog>
102
+ )
103
+
104
+ expect(screen.getByTestId('dialog-root')).toBeInTheDocument()
105
+ expect(screen.getByTestId('dialog-trigger')).toBeInTheDocument()
106
+ })
107
+
108
+ it('handles open state', () => {
109
+ render(
110
+ <Dialog open={true}>
111
+ <DialogContent>Dialog Content</DialogContent>
112
+ </Dialog>
113
+ )
114
+
115
+ const root = screen.getByTestId('dialog-root')
116
+ expect(root).toHaveAttribute('data-open', 'true')
117
+ })
118
+
119
+ it('handles onOpenChange callback', () => {
120
+ const onOpenChange = jest.fn()
121
+ render(
122
+ <Dialog onOpenChange={onOpenChange}>
123
+ <DialogTrigger>Open Dialog</DialogTrigger>
124
+ </Dialog>
125
+ )
126
+
127
+ expect(screen.getByTestId('dialog-root')).toBeInTheDocument()
128
+ })
129
+ })
130
+
131
+ describe('DialogTrigger Component', () => {
132
+ it('renders correctly', () => {
133
+ render(
134
+ <Dialog>
135
+ <DialogTrigger>Open Dialog</DialogTrigger>
136
+ </Dialog>
137
+ )
138
+
139
+ const trigger = screen.getByTestId('dialog-trigger')
140
+ expect(trigger).toBeInTheDocument()
141
+ expect(trigger).toHaveTextContent('Open Dialog')
142
+ })
143
+
144
+ it('passes through HTML attributes', () => {
145
+ render(
146
+ <Dialog>
147
+ <DialogTrigger id="trigger-1" className="custom-trigger">
148
+ Open Dialog
149
+ </DialogTrigger>
150
+ </Dialog>
151
+ )
152
+
153
+ const trigger = screen.getByTestId('dialog-trigger')
154
+ expect(trigger).toHaveAttribute('id', 'trigger-1')
155
+ expect(trigger).toHaveClass('custom-trigger')
156
+ })
157
+ })
158
+
159
+ describe('DialogContent Component', () => {
160
+ it('renders correctly with default props', () => {
161
+ render(
162
+ <Dialog>
163
+ <DialogContent data-testid="content">Dialog Content</DialogContent>
164
+ </Dialog>
165
+ )
166
+
167
+ const content = screen.getByTestId('content')
168
+ expect(content).toBeInTheDocument()
169
+ expect(content).toHaveTextContent('Dialog Content')
170
+ })
171
+
172
+ it('applies custom className', () => {
173
+ render(
174
+ <Dialog>
175
+ <DialogContent className="custom-dialog" data-testid="content">
176
+ Content
177
+ </DialogContent>
178
+ </Dialog>
179
+ )
180
+
181
+ const content = screen.getByTestId('content')
182
+ expect(content).toHaveClass('custom-dialog')
183
+ })
184
+
185
+ it('forwards ref correctly', () => {
186
+ const ref = React.createRef<HTMLDivElement>()
187
+ render(
188
+ <Dialog>
189
+ <DialogContent ref={ref} data-testid="content">
190
+ Content
191
+ </DialogContent>
192
+ </Dialog>
193
+ )
194
+
195
+ const content = screen.getByTestId('content')
196
+ expect(content).toBeInTheDocument()
197
+ })
198
+
199
+ it('renders default variant correctly', () => {
200
+ render(
201
+ <Dialog>
202
+ <DialogContent data-testid="content">Content</DialogContent>
203
+ </Dialog>
204
+ )
205
+
206
+ const content = screen.getByTestId('content')
207
+ expect(content).toHaveClass('border-gray-200 dark:border-gray-700')
208
+ })
209
+
210
+ it('renders primary variant correctly', () => {
211
+ render(
212
+ <Dialog>
213
+ <DialogContent variant="primary" data-testid="content">
214
+ Content
215
+ </DialogContent>
216
+ </Dialog>
217
+ )
218
+
219
+ const content = screen.getByTestId('content')
220
+ expect(content).toHaveClass('border-primary/20 dark:border-primary/30')
221
+ })
222
+
223
+ it('renders ghost variant correctly', () => {
224
+ render(
225
+ <Dialog>
226
+ <DialogContent variant="ghost" data-testid="content">
227
+ Content
228
+ </DialogContent>
229
+ </Dialog>
230
+ )
231
+
232
+ const content = screen.getByTestId('content')
233
+ expect(content).toHaveClass('border-transparent shadow-xl')
234
+ })
235
+
236
+ it('renders different sizes correctly', () => {
237
+ const { rerender } = render(
238
+ <Dialog>
239
+ <DialogContent size="sm" data-testid="content">
240
+ Content
241
+ </DialogContent>
242
+ </Dialog>
243
+ )
244
+
245
+ expect(screen.getByTestId('content')).toHaveClass('max-w-sm p-5')
246
+
247
+ rerender(
248
+ <Dialog>
249
+ <DialogContent size="lg" data-testid="content">
250
+ Content
251
+ </DialogContent>
252
+ </Dialog>
253
+ )
254
+
255
+ expect(screen.getByTestId('content')).toHaveClass('max-w-2xl p-7')
256
+ })
257
+
258
+ it('renders different radius variants', () => {
259
+ render(
260
+ <Dialog>
261
+ <DialogContent radius="xl" data-testid="content">
262
+ Content
263
+ </DialogContent>
264
+ </Dialog>
265
+ )
266
+
267
+ const content = screen.getByTestId('content')
268
+ expect(content).toHaveClass('rounded-2xl')
269
+ })
270
+
271
+ it('renders with title and description', () => {
272
+ render(
273
+ <Dialog>
274
+ <DialogContent title="Dialog Title" description="Dialog Description">
275
+ Content
276
+ </DialogContent>
277
+ </Dialog>
278
+ )
279
+
280
+ expect(screen.getByTestId('dialog-title')).toHaveTextContent('Dialog Title')
281
+ expect(screen.getByTestId('dialog-description')).toHaveTextContent('Dialog Description')
282
+ })
283
+
284
+ it('renders with custom icon', () => {
285
+ const CustomIcon = () => <span data-testid="custom-icon">Icon</span>
286
+ render(
287
+ <Dialog>
288
+ <DialogContent icon={<CustomIcon />} title="Title">
289
+ Content
290
+ </DialogContent>
291
+ </Dialog>
292
+ )
293
+
294
+ expect(screen.getByTestId('custom-icon')).toBeInTheDocument()
295
+ })
296
+
297
+ it('renders loading state', () => {
298
+ render(
299
+ <Dialog>
300
+ <DialogContent loading={true} title="Loading">
301
+ Content
302
+ </DialogContent>
303
+ </Dialog>
304
+ )
305
+
306
+ expect(screen.getByTestId('loader-icon')).toBeInTheDocument()
307
+ })
308
+
309
+ it('renders success state', () => {
310
+ render(
311
+ <Dialog>
312
+ <DialogContent success={true} title="Success">
313
+ Content
314
+ </DialogContent>
315
+ </Dialog>
316
+ )
317
+
318
+ expect(screen.getByTestId('check-icon')).toBeInTheDocument()
319
+ })
320
+
321
+ it('hides close button when hideCloseButton is true', () => {
322
+ render(
323
+ <Dialog>
324
+ <DialogContent hideCloseButton={true}>
325
+ Content
326
+ </DialogContent>
327
+ </Dialog>
328
+ )
329
+
330
+ expect(screen.queryByTestId('dialog-close')).not.toBeInTheDocument()
331
+ })
332
+
333
+ it('shows close button by default', () => {
334
+ render(
335
+ <Dialog>
336
+ <DialogContent>Content</DialogContent>
337
+ </Dialog>
338
+ )
339
+
340
+ expect(screen.getByTestId('dialog-close')).toBeInTheDocument()
341
+ expect(screen.getByTestId('x-icon')).toBeInTheDocument()
342
+ })
343
+
344
+ it('calls onClose when close button is clicked', () => {
345
+ const onClose = jest.fn()
346
+ render(
347
+ <Dialog>
348
+ <DialogContent onClose={onClose}>Content</DialogContent>
349
+ </Dialog>
350
+ )
351
+
352
+ const closeButton = screen.getByTestId('dialog-close')
353
+ fireEvent.click(closeButton)
354
+ expect(onClose).toHaveBeenCalledTimes(1)
355
+ })
356
+
357
+ it('renders different positions correctly', () => {
358
+ render(
359
+ <Dialog>
360
+ <DialogContent position="top" data-testid="content">
361
+ Content
362
+ </DialogContent>
363
+ </Dialog>
364
+ )
365
+
366
+ const content = screen.getByTestId('content')
367
+ expect(content).toHaveClass('top-[5%]')
368
+ })
369
+
370
+ it('passes through HTML attributes', () => {
371
+ render(
372
+ <Dialog>
373
+ <DialogContent id="dialog-1" data-custom="value" data-testid="content">
374
+ Content
375
+ </DialogContent>
376
+ </Dialog>
377
+ )
378
+
379
+ const content = screen.getByTestId('content')
380
+ expect(content).toHaveAttribute('id', 'dialog-1')
381
+ expect(content).toHaveAttribute('data-custom', 'value')
382
+ })
383
+ })
384
+
385
+ describe('DialogHeader Component', () => {
386
+ it('renders correctly', () => {
387
+ render(<DialogHeader data-testid="dialog-header">Header Content</DialogHeader>)
388
+
389
+ const header = screen.getByTestId('dialog-header')
390
+ expect(header).toBeInTheDocument()
391
+ expect(header).toHaveTextContent('Header Content')
392
+ expect(header).toHaveClass('flex flex-col space-y-2 text-center sm:text-left')
393
+ })
394
+
395
+ it('applies custom className', () => {
396
+ render(
397
+ <DialogHeader className="custom-header" data-testid="dialog-header">
398
+ Header
399
+ </DialogHeader>
400
+ )
401
+
402
+ const header = screen.getByTestId('dialog-header')
403
+ expect(header).toHaveClass('custom-header')
404
+ })
405
+
406
+ it('passes through HTML attributes', () => {
407
+ render(
408
+ <DialogHeader id="header-1" data-testid="dialog-header">
409
+ Header
410
+ </DialogHeader>
411
+ )
412
+
413
+ const header = screen.getByTestId('dialog-header')
414
+ expect(header).toHaveAttribute('id', 'header-1')
415
+ })
416
+
417
+ it('maintains displayName', () => {
418
+ expect(DialogHeader.displayName).toBe('DialogHeader')
419
+ })
420
+ })
421
+
422
+ describe('DialogFooter Component', () => {
423
+ it('renders correctly', () => {
424
+ render(<DialogFooter data-testid="dialog-footer">Footer Content</DialogFooter>)
425
+
426
+ const footer = screen.getByTestId('dialog-footer')
427
+ expect(footer).toBeInTheDocument()
428
+ expect(footer).toHaveTextContent('Footer Content')
429
+ expect(footer).toHaveClass('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:space-x-2 mt-6')
430
+ })
431
+
432
+ it('applies custom className', () => {
433
+ render(
434
+ <DialogFooter className="custom-footer" data-testid="dialog-footer">
435
+ Footer
436
+ </DialogFooter>
437
+ )
438
+
439
+ const footer = screen.getByTestId('dialog-footer')
440
+ expect(footer).toHaveClass('custom-footer')
441
+ })
442
+
443
+ it('passes through HTML attributes', () => {
444
+ render(
445
+ <DialogFooter id="footer-1" data-testid="dialog-footer">
446
+ Footer
447
+ </DialogFooter>
448
+ )
449
+
450
+ const footer = screen.getByTestId('dialog-footer')
451
+ expect(footer).toHaveAttribute('id', 'footer-1')
452
+ })
453
+
454
+ it('maintains displayName', () => {
455
+ expect(DialogFooter.displayName).toBe('DialogFooter')
456
+ })
457
+ })
458
+
459
+ describe('DialogTitle Component', () => {
460
+ it('renders correctly', () => {
461
+ render(<DialogTitle data-testid="title">Dialog Title</DialogTitle>)
462
+
463
+ const title = screen.getByTestId('title')
464
+ expect(title).toBeInTheDocument()
465
+ expect(title).toHaveTextContent('Dialog Title')
466
+ expect(title).toHaveClass('text-xl font-semibold leading-snug tracking-tight dark:text-white')
467
+ })
468
+
469
+ it('applies custom className', () => {
470
+ render(
471
+ <DialogTitle className="custom-title" data-testid="title">
472
+ Title
473
+ </DialogTitle>
474
+ )
475
+
476
+ const title = screen.getByTestId('title')
477
+ expect(title).toHaveClass('custom-title')
478
+ })
479
+
480
+ it('forwards ref correctly', () => {
481
+ const ref = React.createRef<HTMLHeadingElement>()
482
+ render(<DialogTitle ref={ref} data-testid="title-ref">Title</DialogTitle>)
483
+
484
+ const title = screen.getByTestId('title-ref')
485
+ expect(title).toBeInTheDocument()
486
+ })
487
+
488
+ it('passes through HTML attributes', () => {
489
+ render(
490
+ <DialogTitle id="title-1" data-testid="title">
491
+ Title
492
+ </DialogTitle>
493
+ )
494
+
495
+ const title = screen.getByTestId('title')
496
+ expect(title).toHaveAttribute('id', 'title-1')
497
+ })
498
+ })
499
+
500
+ describe('DialogDescription Component', () => {
501
+ it('renders correctly', () => {
502
+ render(<DialogDescription data-testid="description">Dialog Description</DialogDescription>)
503
+
504
+ const description = screen.getByTestId('description')
505
+ expect(description).toBeInTheDocument()
506
+ expect(description).toHaveTextContent('Dialog Description')
507
+ expect(description).toHaveClass('text-sm text-muted-foreground leading-normal dark:text-gray-400')
508
+ })
509
+
510
+ it('applies custom className', () => {
511
+ render(
512
+ <DialogDescription className="custom-description" data-testid="description">
513
+ Description
514
+ </DialogDescription>
515
+ )
516
+
517
+ const description = screen.getByTestId('description')
518
+ expect(description).toHaveClass('custom-description')
519
+ })
520
+
521
+ it('forwards ref correctly', () => {
522
+ const ref = React.createRef<HTMLParagraphElement>()
523
+ render(<DialogDescription ref={ref} data-testid="desc-ref">Description</DialogDescription>)
524
+
525
+ const description = screen.getByTestId('desc-ref')
526
+ expect(description).toBeInTheDocument()
527
+ })
528
+
529
+ it('passes through HTML attributes', () => {
530
+ render(
531
+ <DialogDescription id="desc-1" data-testid="description">
532
+ Description
533
+ </DialogDescription>
534
+ )
535
+
536
+ const description = screen.getByTestId('description')
537
+ expect(description).toHaveAttribute('id', 'desc-1')
538
+ })
539
+ })
540
+
541
+ describe('DialogClose Component', () => {
542
+ it('renders correctly', () => {
543
+ render(<DialogClose data-testid="close">Close</DialogClose>)
544
+
545
+ const close = screen.getByTestId('close')
546
+ expect(close).toBeInTheDocument()
547
+ expect(close).toHaveTextContent('Close')
548
+ })
549
+
550
+ it('handles click events', () => {
551
+ const onClick = jest.fn()
552
+ render(<DialogClose onClick={onClick}>Close</DialogClose>)
553
+
554
+ const close = screen.getByTestId('dialog-close')
555
+ fireEvent.click(close)
556
+ expect(onClick).toHaveBeenCalledTimes(1)
557
+ })
558
+ })
559
+
560
+ describe('DialogForm Component', () => {
561
+ it('renders correctly', () => {
562
+ render(<DialogForm data-testid="dialog-form">Form Content</DialogForm>)
563
+
564
+ const form = screen.getByTestId('dialog-form')
565
+ expect(form).toBeInTheDocument()
566
+ expect(form).toHaveTextContent('Form Content')
567
+ expect(form).toHaveClass('flex flex-col gap-4')
568
+ })
569
+
570
+ it('applies custom className', () => {
571
+ render(
572
+ <DialogForm className="custom-form" data-testid="dialog-form">
573
+ Form
574
+ </DialogForm>
575
+ )
576
+
577
+ const form = screen.getByTestId('dialog-form')
578
+ expect(form).toHaveClass('custom-form')
579
+ })
580
+
581
+ it('forwards ref correctly', () => {
582
+ const ref = React.createRef<HTMLFormElement>()
583
+ render(<DialogForm ref={ref}>Form</DialogForm>)
584
+
585
+ expect(ref.current).toBeInstanceOf(HTMLFormElement)
586
+ })
587
+
588
+ it('handles form submission', () => {
589
+ const onSubmit = jest.fn((e) => e.preventDefault())
590
+ render(
591
+ <DialogForm onSubmit={onSubmit} data-testid="dialog-form">
592
+ <button type="submit">Submit</button>
593
+ </DialogForm>
594
+ )
595
+
596
+ const form = screen.getByTestId('dialog-form')
597
+ fireEvent.submit(form)
598
+ expect(onSubmit).toHaveBeenCalledTimes(1)
599
+ })
600
+
601
+ it('passes through HTML attributes', () => {
602
+ render(
603
+ <DialogForm id="form-1" data-testid="dialog-form">
604
+ Form
605
+ </DialogForm>
606
+ )
607
+
608
+ const form = screen.getByTestId('dialog-form')
609
+ expect(form).toHaveAttribute('id', 'form-1')
610
+ })
611
+
612
+ it('maintains displayName', () => {
613
+ expect(DialogForm.displayName).toBe('DialogForm')
614
+ })
615
+ })
616
+
617
+ describe('Complex Dialog Combinations', () => {
618
+ it('renders complete dialog with all components', () => {
619
+ render(
620
+ <Dialog>
621
+ <DialogTrigger>Open Dialog</DialogTrigger>
622
+ <DialogContent>
623
+ <DialogHeader>
624
+ <DialogTitle>Complete Dialog</DialogTitle>
625
+ <DialogDescription>This is a complete dialog example</DialogDescription>
626
+ </DialogHeader>
627
+ <div>Main content goes here</div>
628
+ <DialogFooter>
629
+ <DialogClose>Cancel</DialogClose>
630
+ <button>Confirm</button>
631
+ </DialogFooter>
632
+ </DialogContent>
633
+ </Dialog>
634
+ )
635
+
636
+ expect(screen.getByTestId('dialog-trigger')).toBeInTheDocument()
637
+ expect(screen.getByTestId('dialog-content')).toBeInTheDocument()
638
+ expect(screen.getByTestId('dialog-title')).toHaveTextContent('Complete Dialog')
639
+ expect(screen.getByTestId('dialog-description')).toHaveTextContent('This is a complete dialog example')
640
+ expect(screen.getByText('Main content goes here')).toBeInTheDocument()
641
+ expect(screen.getByText('Cancel')).toBeInTheDocument()
642
+ expect(screen.getByText('Confirm')).toBeInTheDocument()
643
+ })
644
+
645
+ it('renders dialog with form integration', () => {
646
+ render(
647
+ <Dialog>
648
+ <DialogContent>
649
+ <DialogHeader>
650
+ <DialogTitle>Form Dialog</DialogTitle>
651
+ </DialogHeader>
652
+ <DialogForm data-testid="dialog-form">
653
+ <input type="text" placeholder="Enter text" />
654
+ <button type="submit">Submit</button>
655
+ </DialogForm>
656
+ </DialogContent>
657
+ </Dialog>
658
+ )
659
+
660
+ expect(screen.getByTestId('dialog-form')).toBeInTheDocument()
661
+ expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument()
662
+ expect(screen.getByText('Submit')).toBeInTheDocument()
663
+ })
664
+
665
+ it('handles all variants and props together', () => {
666
+ render(
667
+ <Dialog open={true}>
668
+ <DialogContent
669
+ variant="primary"
670
+ size="lg"
671
+ radius="xl"
672
+ position="top"
673
+ title="Advanced Dialog"
674
+ description="With all features"
675
+ loading={false}
676
+ success={false}
677
+ hideCloseButton={false}
678
+ className="custom-dialog"
679
+ >
680
+ Advanced content
681
+ </DialogContent>
682
+ </Dialog>
683
+ )
684
+
685
+ const content = screen.getByTestId('dialog-content')
686
+ expect(content).toHaveClass('custom-dialog')
687
+ expect(content).toHaveClass('border-primary/20 dark:border-primary/30')
688
+ expect(content).toHaveClass('max-w-2xl p-7')
689
+ expect(content).toHaveClass('rounded-2xl')
690
+ expect(content).toHaveClass('top-[5%]')
691
+ expect(screen.getByTestId('dialog-title')).toHaveTextContent('Advanced Dialog')
692
+ expect(screen.getByTestId('dialog-description')).toHaveTextContent('With all features')
693
+ })
694
+ })
695
+
696
+ describe('Edge Cases', () => {
697
+ it('handles empty dialog content', () => {
698
+ render(
699
+ <Dialog>
700
+ <DialogContent hideCloseButton={true} data-testid="content" />
701
+ </Dialog>
702
+ )
703
+
704
+ const content = screen.getByTestId('content')
705
+ expect(content).toBeInTheDocument()
706
+ // Content should only contain the overlay and content wrapper
707
+ expect(content.children.length).toBeGreaterThanOrEqual(0)
708
+ })
709
+
710
+ it('handles null and undefined children', () => {
711
+ render(
712
+ <Dialog>
713
+ <DialogContent>
714
+ {null}
715
+ {undefined}
716
+ <div>Valid content</div>
717
+ </DialogContent>
718
+ </Dialog>
719
+ )
720
+
721
+ expect(screen.getByText('Valid content')).toBeInTheDocument()
722
+ })
723
+
724
+ it('handles dialog without trigger', () => {
725
+ render(
726
+ <Dialog>
727
+ <DialogContent>Content without trigger</DialogContent>
728
+ </Dialog>
729
+ )
730
+
731
+ expect(screen.getByTestId('dialog-content')).toBeInTheDocument()
732
+ })
733
+
734
+ it('handles multiple dialogs', () => {
735
+ render(
736
+ <div>
737
+ <Dialog>
738
+ <DialogContent data-testid="dialog-1">Dialog 1</DialogContent>
739
+ </Dialog>
740
+ <Dialog>
741
+ <DialogContent data-testid="dialog-2">Dialog 2</DialogContent>
742
+ </Dialog>
743
+ </div>
744
+ )
745
+
746
+ expect(screen.getByTestId('dialog-1')).toBeInTheDocument()
747
+ expect(screen.getByTestId('dialog-2')).toBeInTheDocument()
748
+ })
749
+
750
+ it('handles loading and success states together', () => {
751
+ render(
752
+ <Dialog>
753
+ <DialogContent loading={true} success={true} title="Conflicting States">
754
+ Content
755
+ </DialogContent>
756
+ </Dialog>
757
+ )
758
+
759
+ // Both icons should be present as they are rendered conditionally
760
+ expect(screen.getByTestId('loader-icon')).toBeInTheDocument()
761
+ expect(screen.getByTestId('check-icon')).toBeInTheDocument()
762
+ })
763
+ })
764
+ })