@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.
- package/package.json +26 -19
- package/src/__tests__/use-intersection-observer.test.tsx +216 -0
- package/src/__tests__/use-local-storage.test.tsx +174 -0
- package/src/__tests__/use-pro-access.test.tsx +183 -0
- package/src/components/ui/__tests__/accordion.test.tsx +571 -0
- package/src/components/ui/__tests__/alert.test.tsx +484 -0
- package/src/components/ui/__tests__/aspect-ratio.test.tsx +492 -0
- package/src/components/ui/__tests__/avatar.test.tsx +382 -0
- package/src/components/ui/__tests__/badge.test.tsx +364 -0
- package/src/components/ui/__tests__/breadcrumb.test.tsx +687 -0
- package/src/components/ui/__tests__/button.test.tsx +91 -0
- package/src/components/ui/__tests__/card.test.tsx +104 -0
- package/src/components/ui/__tests__/checkbox.test.tsx +591 -0
- package/src/components/ui/__tests__/collapsible.test.tsx +592 -0
- package/src/components/ui/__tests__/color-picker.test.tsx +365 -0
- package/src/components/ui/__tests__/command.test.tsx +677 -0
- package/src/components/ui/__tests__/data-table.test.tsx +256 -0
- package/src/components/ui/__tests__/date-picker.test.tsx +320 -0
- package/src/components/ui/__tests__/dialog.test.tsx +764 -0
- package/src/components/ui/__tests__/input.test.tsx +318 -0
- package/src/components/ui/__tests__/label.test.tsx +103 -0
- package/src/components/ui/__tests__/popover.test.tsx +637 -0
- package/src/components/ui/__tests__/progress.test.tsx +382 -0
- package/src/components/ui/__tests__/radio-group.test.tsx +555 -0
- package/src/components/ui/__tests__/select.test.tsx +705 -0
- package/src/components/ui/__tests__/skeleton.test.tsx +253 -0
- package/src/components/ui/__tests__/slider.test.tsx +493 -0
- package/src/components/ui/__tests__/switch.test.tsx +372 -0
- package/src/components/ui/__tests__/table.test.tsx +824 -0
- package/src/components/ui/__tests__/tabs.test.tsx +887 -0
- package/src/components/ui/__tests__/toast.test.tsx +458 -0
- package/src/components/ui/__tests__/tooltip.test.tsx +583 -0
- package/src/components/ui/accordion.tsx +63 -0
- package/src/components/ui/alert.tsx +130 -0
- package/src/components/ui/aspect-ratio.tsx +72 -0
- package/src/components/ui/avatar.tsx +135 -0
- package/src/components/ui/badge.tsx +225 -0
- package/src/components/ui/breadcrumb.tsx +207 -0
- package/src/components/ui/button.stories.tsx +162 -0
- package/src/components/ui/button.tsx +221 -0
- package/src/components/ui/calendar.tsx +262 -0
- package/src/components/ui/card.stories.tsx +208 -0
- package/src/components/ui/card.tsx +141 -0
- package/src/components/ui/checkbox.tsx +256 -0
- package/src/components/ui/collapsible.tsx +129 -0
- package/src/components/ui/color-picker.tsx +664 -0
- package/src/components/ui/command.tsx +218 -0
- package/src/components/ui/data-table.stories.tsx +509 -0
- package/src/components/ui/data-table.tsx +623 -0
- package/src/components/ui/date-picker.stories.tsx +321 -0
- package/src/components/ui/date-picker.tsx +603 -0
- package/src/components/ui/dialog.tsx +332 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/file-upload.tsx +400 -0
- package/src/components/ui/github-stars.tsx +201 -0
- package/src/components/ui/index.ts +12 -0
- package/src/components/ui/input.stories.tsx +255 -0
- package/src/components/ui/input.tsx +219 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/locked-component.tsx +215 -0
- package/src/components/ui/moon-logo.tsx +97 -0
- package/src/components/ui/pagination.tsx +116 -0
- package/src/components/ui/popover.tsx +183 -0
- package/src/components/ui/progress.tsx +182 -0
- package/src/components/ui/radio-group.tsx +243 -0
- package/src/components/ui/select.tsx +273 -0
- package/src/components/ui/separator.tsx +140 -0
- package/src/components/ui/simple-editor.tsx +652 -0
- package/src/components/ui/skeleton.tsx +351 -0
- package/src/components/ui/slider.tsx +351 -0
- package/src/components/ui/switch.tsx +83 -0
- package/src/components/ui/table.tsx +322 -0
- package/src/components/ui/tabs.tsx +195 -0
- package/src/components/ui/textarea.tsx +46 -0
- package/src/components/ui/toast.tsx +313 -0
- package/src/components/ui/toggle.tsx +47 -0
- package/src/components/ui/tooltip.tsx +152 -0
- package/src/docs/theme-system.md +1194 -0
- package/src/index.tsx +39 -0
- package/src/lib/micro-interactions.ts +255 -0
- package/src/lib/theme.tsx +398 -0
- package/src/lib/utils.ts +69 -0
- package/src/styles/design-system.css +365 -0
- package/src/styles/index.css +4 -0
- package/src/styles/tailwind.css +6 -0
- package/src/styles/tokens.css +453 -0
- package/src/use-intersection-observer.tsx +154 -0
- package/src/use-local-storage.tsx +71 -0
- package/src/use-paddle.ts +138 -0
- package/src/use-performance-optimizer.ts +379 -0
- package/src/use-pro-access.ts +141 -0
- package/src/use-scroll-animation.ts +221 -0
- package/src/use-subscription.ts +37 -0
- package/src/use-toast.ts +32 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render, screen } from '@testing-library/react'
|
|
3
|
+
import '@testing-library/jest-dom'
|
|
4
|
+
import { Skeleton, SkeletonText, SkeletonAvatar, SkeletonCard } from '../skeleton'
|
|
5
|
+
|
|
6
|
+
describe('Skeleton Components', () => {
|
|
7
|
+
describe('Skeleton Component', () => {
|
|
8
|
+
it('renders correctly with default props', () => {
|
|
9
|
+
render(<Skeleton data-testid="skeleton" />)
|
|
10
|
+
const skeleton = screen.getByTestId('skeleton')
|
|
11
|
+
expect(skeleton).toBeInTheDocument()
|
|
12
|
+
expect(skeleton).toHaveClass('animate-pulse')
|
|
13
|
+
expect(skeleton).toHaveClass('rounded-md')
|
|
14
|
+
expect(skeleton).toHaveClass('bg-muted')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('applies custom className', () => {
|
|
18
|
+
render(<Skeleton className="custom-skeleton" data-testid="skeleton" />)
|
|
19
|
+
const skeleton = screen.getByTestId('skeleton')
|
|
20
|
+
expect(skeleton).toHaveClass('custom-skeleton')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('forwards ref correctly', () => {
|
|
24
|
+
const ref = React.createRef<HTMLDivElement>()
|
|
25
|
+
render(<Skeleton ref={ref} data-testid="skeleton" />)
|
|
26
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('applies custom dimensions', () => {
|
|
30
|
+
render(<Skeleton height="100px" width="200px" data-testid="skeleton" />)
|
|
31
|
+
const skeleton = screen.getByTestId('skeleton')
|
|
32
|
+
expect(skeleton).toHaveStyle({ height: '100px', width: '200px' })
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('renders primary variant', () => {
|
|
36
|
+
render(<Skeleton variant="primary" data-testid="skeleton" />)
|
|
37
|
+
const skeleton = screen.getByTestId('skeleton')
|
|
38
|
+
expect(skeleton).toHaveClass('bg-primary/10')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('renders circle shape', () => {
|
|
42
|
+
render(<Skeleton shape="circle" data-testid="skeleton" />)
|
|
43
|
+
const skeleton = screen.getByTestId('skeleton')
|
|
44
|
+
expect(skeleton).toHaveClass('rounded-full')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('shows children when loaded', () => {
|
|
48
|
+
render(<Skeleton isLoaded={true} data-testid="skeleton">Content</Skeleton>)
|
|
49
|
+
expect(screen.getByText('Content')).toBeInTheDocument()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('shows skeleton when not loaded', () => {
|
|
53
|
+
render(<Skeleton isLoaded={false} data-testid="skeleton">Content</Skeleton>)
|
|
54
|
+
const skeleton = screen.getByTestId('skeleton')
|
|
55
|
+
expect(skeleton).toHaveClass('animate-pulse')
|
|
56
|
+
expect(screen.queryByText('Content')).not.toBeInTheDocument()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('maintains displayName', () => {
|
|
60
|
+
expect(Skeleton.displayName).toBe('Skeleton')
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('SkeletonText Component', () => {
|
|
65
|
+
it('renders correctly with default props', () => {
|
|
66
|
+
render(<SkeletonText data-testid="skeleton-text" />)
|
|
67
|
+
const container = screen.getByTestId('skeleton-text')
|
|
68
|
+
expect(container).toBeInTheDocument()
|
|
69
|
+
expect(container).toHaveClass('flex')
|
|
70
|
+
|
|
71
|
+
const skeletons = container.querySelectorAll('.animate-pulse')
|
|
72
|
+
expect(skeletons).toHaveLength(3) // default lines
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('renders custom number of lines', () => {
|
|
76
|
+
render(<SkeletonText lines={5} data-testid="skeleton-text" />)
|
|
77
|
+
const container = screen.getByTestId('skeleton-text')
|
|
78
|
+
const skeletons = container.querySelectorAll('.animate-pulse')
|
|
79
|
+
expect(skeletons).toHaveLength(5)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('applies custom line height', () => {
|
|
83
|
+
render(<SkeletonText lineHeight="1rem" data-testid="skeleton-text" />)
|
|
84
|
+
const container = screen.getByTestId('skeleton-text')
|
|
85
|
+
const firstLine = container.querySelector('.animate-pulse')
|
|
86
|
+
expect(firstLine).toHaveStyle({ height: '1rem' })
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('applies custom spacing', () => {
|
|
90
|
+
render(<SkeletonText spacing="1rem" data-testid="skeleton-text" />)
|
|
91
|
+
const container = screen.getByTestId('skeleton-text')
|
|
92
|
+
expect(container).toHaveStyle({ gap: '1rem' })
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('forwards ref correctly', () => {
|
|
96
|
+
const ref = React.createRef<HTMLDivElement>()
|
|
97
|
+
render(<SkeletonText ref={ref} data-testid="skeleton-text" />)
|
|
98
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('maintains displayName', () => {
|
|
102
|
+
expect(SkeletonText.displayName).toBe('SkeletonText')
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe('SkeletonAvatar Component', () => {
|
|
107
|
+
it('renders correctly with default props', () => {
|
|
108
|
+
render(<SkeletonAvatar data-testid="skeleton-avatar" />)
|
|
109
|
+
const avatar = screen.getByTestId('skeleton-avatar')
|
|
110
|
+
expect(avatar).toBeInTheDocument()
|
|
111
|
+
expect(avatar).toHaveClass('animate-pulse')
|
|
112
|
+
expect(avatar).toHaveClass('rounded-full')
|
|
113
|
+
expect(avatar).toHaveClass('shrink-0')
|
|
114
|
+
expect(avatar).toHaveStyle({ height: '2.5rem', width: '2.5rem' })
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('applies custom size', () => {
|
|
118
|
+
render(<SkeletonAvatar size="3rem" data-testid="skeleton-avatar" />)
|
|
119
|
+
const avatar = screen.getByTestId('skeleton-avatar')
|
|
120
|
+
expect(avatar).toHaveStyle({ height: '3rem', width: '3rem' })
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('applies custom size as number', () => {
|
|
124
|
+
render(<SkeletonAvatar size={48} data-testid="skeleton-avatar" />)
|
|
125
|
+
const avatar = screen.getByTestId('skeleton-avatar')
|
|
126
|
+
expect(avatar).toHaveStyle({ height: '48px', width: '48px' })
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('forwards ref correctly', () => {
|
|
130
|
+
const ref = React.createRef<HTMLDivElement>()
|
|
131
|
+
render(<SkeletonAvatar ref={ref} data-testid="skeleton-avatar" />)
|
|
132
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('renders with custom variant', () => {
|
|
136
|
+
render(<SkeletonAvatar variant="primary" data-testid="skeleton-avatar" />)
|
|
137
|
+
const avatar = screen.getByTestId('skeleton-avatar')
|
|
138
|
+
expect(avatar).toHaveClass('bg-primary/10')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('maintains displayName', () => {
|
|
142
|
+
expect(SkeletonAvatar.displayName).toBe('SkeletonAvatar')
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
describe('SkeletonCard Component', () => {
|
|
147
|
+
it('renders correctly with default props', () => {
|
|
148
|
+
render(<SkeletonCard data-testid="skeleton-card" />)
|
|
149
|
+
const card = screen.getByTestId('skeleton-card')
|
|
150
|
+
expect(card).toBeInTheDocument()
|
|
151
|
+
expect(card).toHaveClass('overflow-hidden')
|
|
152
|
+
expect(card).toHaveClass('rounded-md')
|
|
153
|
+
expect(card).toHaveClass('border')
|
|
154
|
+
expect(card).toHaveClass('bg-background')
|
|
155
|
+
expect(card).toHaveClass('p-4')
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('shows header by default', () => {
|
|
159
|
+
render(<SkeletonCard data-testid="skeleton-card" />)
|
|
160
|
+
const card = screen.getByTestId('skeleton-card')
|
|
161
|
+
|
|
162
|
+
// Check for avatar in header
|
|
163
|
+
const avatar = card.querySelector('.shrink-0.rounded-full')
|
|
164
|
+
expect(avatar).toBeInTheDocument()
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('hides header when showHeader is false', () => {
|
|
168
|
+
render(<SkeletonCard showHeader={false} data-testid="skeleton-card" />)
|
|
169
|
+
const card = screen.getByTestId('skeleton-card')
|
|
170
|
+
|
|
171
|
+
// Avatar should not be present
|
|
172
|
+
const avatar = card.querySelector('.shrink-0.rounded-full')
|
|
173
|
+
expect(avatar).not.toBeInTheDocument()
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('renders custom number of content lines', () => {
|
|
177
|
+
render(<SkeletonCard contentLines={5} data-testid="skeleton-card" />)
|
|
178
|
+
const card = screen.getByTestId('skeleton-card')
|
|
179
|
+
|
|
180
|
+
const textContainer = card.querySelector('.flex.flex-col')
|
|
181
|
+
expect(textContainer).toBeInTheDocument()
|
|
182
|
+
|
|
183
|
+
const contentLines = textContainer?.querySelectorAll('.animate-pulse')
|
|
184
|
+
expect(contentLines).toHaveLength(5)
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('shows footer by default', () => {
|
|
188
|
+
render(<SkeletonCard data-testid="skeleton-card" />)
|
|
189
|
+
const card = screen.getByTestId('skeleton-card')
|
|
190
|
+
|
|
191
|
+
const footer = card.querySelector('.border-t')
|
|
192
|
+
expect(footer).toBeInTheDocument()
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('hides footer when showFooter is false', () => {
|
|
196
|
+
render(<SkeletonCard showFooter={false} data-testid="skeleton-card" />)
|
|
197
|
+
const card = screen.getByTestId('skeleton-card')
|
|
198
|
+
|
|
199
|
+
const footer = card.querySelector('.border-t')
|
|
200
|
+
expect(footer).not.toBeInTheDocument()
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('forwards ref correctly', () => {
|
|
204
|
+
const ref = React.createRef<HTMLDivElement>()
|
|
205
|
+
render(<SkeletonCard ref={ref} data-testid="skeleton-card" />)
|
|
206
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('maintains displayName', () => {
|
|
210
|
+
expect(SkeletonCard.displayName).toBe('SkeletonCard')
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
describe('Edge Cases', () => {
|
|
215
|
+
it('handles zero lines in SkeletonText', () => {
|
|
216
|
+
render(<SkeletonText lines={0} data-testid="skeleton-text" />)
|
|
217
|
+
const container = screen.getByTestId('skeleton-text')
|
|
218
|
+
const skeletons = container.querySelectorAll('.animate-pulse')
|
|
219
|
+
expect(skeletons).toHaveLength(0)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('handles all sections disabled in SkeletonCard', () => {
|
|
223
|
+
render(
|
|
224
|
+
<SkeletonCard
|
|
225
|
+
showHeader={false}
|
|
226
|
+
showFooter={false}
|
|
227
|
+
contentLines={1}
|
|
228
|
+
data-testid="skeleton-card"
|
|
229
|
+
/>
|
|
230
|
+
)
|
|
231
|
+
const card = screen.getByTestId('skeleton-card')
|
|
232
|
+
|
|
233
|
+
// No header avatar
|
|
234
|
+
const avatar = card.querySelector('.shrink-0.rounded-full')
|
|
235
|
+
expect(avatar).not.toBeInTheDocument()
|
|
236
|
+
|
|
237
|
+
// No footer
|
|
238
|
+
const footer = card.querySelector('.border-t')
|
|
239
|
+
expect(footer).not.toBeInTheDocument()
|
|
240
|
+
|
|
241
|
+
// Only content lines
|
|
242
|
+
const textContainer = card.querySelector('.flex.flex-col')
|
|
243
|
+
const contentLines = textContainer?.querySelectorAll('.animate-pulse')
|
|
244
|
+
expect(contentLines).toHaveLength(1)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('passes through HTML attributes', () => {
|
|
248
|
+
render(<Skeleton data-testid="skeleton-test" id="skeleton-1" />)
|
|
249
|
+
const skeleton = screen.getByTestId('skeleton-test')
|
|
250
|
+
expect(skeleton).toHaveAttribute('id', 'skeleton-1')
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
})
|