@moontra/moonui-pro 2.0.22 → 2.1.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.
- package/dist/index.mjs +215 -214
- package/package.json +4 -2
- 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/advanced-chart/advanced-chart.test.tsx +281 -0
- package/src/components/advanced-chart/index.tsx +412 -0
- package/src/components/advanced-forms/index.tsx +431 -0
- package/src/components/animated-button/index.tsx +202 -0
- package/src/components/calendar/event-dialog.tsx +372 -0
- package/src/components/calendar/index.tsx +557 -0
- package/src/components/color-picker/index.tsx +434 -0
- package/src/components/dashboard/index.tsx +334 -0
- package/src/components/data-table/data-table.test.tsx +187 -0
- package/src/components/data-table/index.tsx +368 -0
- package/src/components/draggable-list/index.tsx +100 -0
- package/src/components/enhanced/button.tsx +360 -0
- package/src/components/enhanced/card.tsx +272 -0
- package/src/components/enhanced/dialog.tsx +248 -0
- package/src/components/enhanced/index.ts +3 -0
- package/src/components/error-boundary/index.tsx +111 -0
- package/src/components/file-upload/file-upload.test.tsx +242 -0
- package/src/components/file-upload/index.tsx +362 -0
- package/src/components/floating-action-button/index.tsx +209 -0
- package/src/components/github-stars/index.tsx +414 -0
- package/src/components/health-check/index.tsx +441 -0
- package/src/components/hover-card-3d/index.tsx +170 -0
- package/src/components/index.ts +76 -0
- package/src/components/kanban/index.tsx +436 -0
- package/src/components/lazy-component/index.tsx +342 -0
- package/src/components/magnetic-button/index.tsx +170 -0
- package/src/components/memory-efficient-data/index.tsx +352 -0
- package/src/components/optimized-image/index.tsx +427 -0
- package/src/components/performance-debugger/index.tsx +591 -0
- package/src/components/performance-monitor/index.tsx +775 -0
- package/src/components/pinch-zoom/index.tsx +172 -0
- package/src/components/rich-text-editor/index-old-backup.tsx +443 -0
- package/src/components/rich-text-editor/index.tsx +1537 -0
- package/src/components/rich-text-editor/slash-commands-extension.ts +220 -0
- package/src/components/rich-text-editor/slash-commands.css +35 -0
- package/src/components/rich-text-editor/table-styles.css +65 -0
- package/src/components/spotlight-card/index.tsx +194 -0
- package/src/components/swipeable-card/index.tsx +100 -0
- package/src/components/timeline/index.tsx +333 -0
- package/src/components/ui/animated-button.tsx +185 -0
- package/src/components/ui/avatar.tsx +135 -0
- package/src/components/ui/badge.tsx +225 -0
- package/src/components/ui/button.tsx +221 -0
- package/src/components/ui/card.tsx +141 -0
- package/src/components/ui/checkbox.tsx +256 -0
- package/src/components/ui/color-picker.tsx +95 -0
- package/src/components/ui/dialog.tsx +332 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/hover-card-3d.tsx +103 -0
- package/src/components/ui/index.ts +33 -0
- package/src/components/ui/input.tsx +219 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/magnetic-button.tsx +129 -0
- package/src/components/ui/popover.tsx +183 -0
- package/src/components/ui/select.tsx +273 -0
- package/src/components/ui/separator.tsx +140 -0
- package/src/components/ui/slider.tsx +351 -0
- package/src/components/ui/spotlight-card.tsx +119 -0
- package/src/components/ui/switch.tsx +83 -0
- package/src/components/ui/tabs.tsx +195 -0
- package/src/components/ui/textarea.tsx +25 -0
- package/src/components/ui/toast.tsx +313 -0
- package/src/components/ui/tooltip.tsx +152 -0
- package/src/components/virtual-list/index.tsx +369 -0
- package/src/hooks/use-chart.ts +205 -0
- package/src/hooks/use-data-table.ts +182 -0
- package/src/hooks/use-docs-pro-access.ts +13 -0
- package/src/hooks/use-license-check.ts +65 -0
- package/src/hooks/use-subscription.ts +19 -0
- package/src/index.ts +14 -0
- package/src/lib/micro-interactions.ts +255 -0
- package/src/lib/utils.ts +6 -0
- package/src/patterns/login-form/index.tsx +276 -0
- package/src/patterns/login-form/types.ts +67 -0
- package/src/setupTests.ts +41 -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/types/moonui.d.ts +22 -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
- package/src/utils/chart-helpers.ts +257 -0
- package/src/utils/cn.ts +69 -0
- package/src/utils/data-processing.ts +151 -0
- package/src/utils/license-guard.tsx +177 -0
- package/src/utils/license-validator.tsx +183 -0
- package/src/utils/package-guard.ts +60 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { ColumnDef } from '@tanstack/react-table'
|
|
5
|
+
|
|
6
|
+
export interface UseDataTableOptions<TData> {
|
|
7
|
+
data: TData[]
|
|
8
|
+
columns: ColumnDef<TData, any>[]
|
|
9
|
+
searchable?: boolean
|
|
10
|
+
filterable?: boolean
|
|
11
|
+
sortable?: boolean
|
|
12
|
+
pagination?: boolean
|
|
13
|
+
pageSize?: number
|
|
14
|
+
enableRowSelection?: boolean
|
|
15
|
+
enableMultiRowSelection?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UseDataTableReturn<TData> {
|
|
19
|
+
// Table state
|
|
20
|
+
filteredData: TData[]
|
|
21
|
+
selectedRows: TData[]
|
|
22
|
+
searchQuery: string
|
|
23
|
+
currentPage: number
|
|
24
|
+
totalPages: number
|
|
25
|
+
|
|
26
|
+
// Actions
|
|
27
|
+
setSearchQuery: (query: string) => void
|
|
28
|
+
setCurrentPage: (page: number) => void
|
|
29
|
+
selectRow: (row: TData) => void
|
|
30
|
+
selectAllRows: () => void
|
|
31
|
+
clearSelection: () => void
|
|
32
|
+
exportData: (format?: 'csv' | 'json') => void
|
|
33
|
+
|
|
34
|
+
// Utilities
|
|
35
|
+
getRowCount: () => number
|
|
36
|
+
getSelectedCount: () => number
|
|
37
|
+
isRowSelected: (row: TData) => boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function useDataTable<TData extends Record<string, any>>(
|
|
41
|
+
options: UseDataTableOptions<TData>
|
|
42
|
+
): UseDataTableReturn<TData> {
|
|
43
|
+
const {
|
|
44
|
+
data,
|
|
45
|
+
searchable = true,
|
|
46
|
+
pageSize = 10,
|
|
47
|
+
enableRowSelection = false,
|
|
48
|
+
enableMultiRowSelection = true,
|
|
49
|
+
} = options
|
|
50
|
+
|
|
51
|
+
const [searchQuery, setSearchQuery] = React.useState('')
|
|
52
|
+
const [currentPage, setCurrentPage] = React.useState(1)
|
|
53
|
+
const [selectedRows, setSelectedRows] = React.useState<TData[]>([])
|
|
54
|
+
|
|
55
|
+
// Filter data based on search query
|
|
56
|
+
const filteredData = React.useMemo(() => {
|
|
57
|
+
if (!searchable || !searchQuery.trim()) {
|
|
58
|
+
return data
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return data.filter((row) => {
|
|
62
|
+
return Object.values(row).some((value) => {
|
|
63
|
+
if (value == null) return false
|
|
64
|
+
return String(value).toLowerCase().includes(searchQuery.toLowerCase())
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
}, [data, searchQuery, searchable])
|
|
68
|
+
|
|
69
|
+
// Calculate pagination
|
|
70
|
+
const totalPages = Math.ceil(filteredData.length / pageSize)
|
|
71
|
+
const paginatedData = React.useMemo(() => {
|
|
72
|
+
const startIndex = (currentPage - 1) * pageSize
|
|
73
|
+
const endIndex = startIndex + pageSize
|
|
74
|
+
return filteredData.slice(startIndex, endIndex)
|
|
75
|
+
}, [filteredData, currentPage, pageSize])
|
|
76
|
+
|
|
77
|
+
// Row selection handlers
|
|
78
|
+
const selectRow = React.useCallback((row: TData) => {
|
|
79
|
+
if (!enableRowSelection) return
|
|
80
|
+
|
|
81
|
+
setSelectedRows((prev) => {
|
|
82
|
+
if (!enableMultiRowSelection) {
|
|
83
|
+
return [row]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const isSelected = prev.some((selectedRow) =>
|
|
87
|
+
JSON.stringify(selectedRow) === JSON.stringify(row)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if (isSelected) {
|
|
91
|
+
return prev.filter((selectedRow) =>
|
|
92
|
+
JSON.stringify(selectedRow) !== JSON.stringify(row)
|
|
93
|
+
)
|
|
94
|
+
} else {
|
|
95
|
+
return [...prev, row]
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
}, [enableRowSelection, enableMultiRowSelection])
|
|
99
|
+
|
|
100
|
+
const selectAllRows = React.useCallback(() => {
|
|
101
|
+
if (!enableRowSelection) return
|
|
102
|
+
|
|
103
|
+
setSelectedRows((prev) => {
|
|
104
|
+
if (prev.length === filteredData.length) {
|
|
105
|
+
return []
|
|
106
|
+
} else {
|
|
107
|
+
return [...filteredData]
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
}, [enableRowSelection, filteredData])
|
|
111
|
+
|
|
112
|
+
const clearSelection = React.useCallback(() => {
|
|
113
|
+
setSelectedRows([])
|
|
114
|
+
}, [])
|
|
115
|
+
|
|
116
|
+
const isRowSelected = React.useCallback((row: TData) => {
|
|
117
|
+
return selectedRows.some((selectedRow) =>
|
|
118
|
+
JSON.stringify(selectedRow) === JSON.stringify(row)
|
|
119
|
+
)
|
|
120
|
+
}, [selectedRows])
|
|
121
|
+
|
|
122
|
+
// Export functionality
|
|
123
|
+
const exportData = React.useCallback((format: 'csv' | 'json' = 'csv') => {
|
|
124
|
+
const dataToExport = selectedRows.length > 0 ? selectedRows : filteredData
|
|
125
|
+
|
|
126
|
+
if (format === 'csv') {
|
|
127
|
+
const headers = Object.keys(dataToExport[0] || {})
|
|
128
|
+
const csvContent = [
|
|
129
|
+
headers.join(','),
|
|
130
|
+
...dataToExport.map(row =>
|
|
131
|
+
headers.map(header => {
|
|
132
|
+
const value = row[header]
|
|
133
|
+
// Escape commas and quotes in CSV
|
|
134
|
+
if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) {
|
|
135
|
+
return `"${value.replace(/"/g, '""')}"`
|
|
136
|
+
}
|
|
137
|
+
return value
|
|
138
|
+
}).join(',')
|
|
139
|
+
)
|
|
140
|
+
].join('\n')
|
|
141
|
+
|
|
142
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
|
|
143
|
+
const link = document.createElement('a')
|
|
144
|
+
link.href = URL.createObjectURL(blob)
|
|
145
|
+
link.download = 'data.csv'
|
|
146
|
+
link.click()
|
|
147
|
+
} else if (format === 'json') {
|
|
148
|
+
const jsonContent = JSON.stringify(dataToExport, null, 2)
|
|
149
|
+
const blob = new Blob([jsonContent], { type: 'application/json;charset=utf-8;' })
|
|
150
|
+
const link = document.createElement('a')
|
|
151
|
+
link.href = URL.createObjectURL(blob)
|
|
152
|
+
link.download = 'data.json'
|
|
153
|
+
link.click()
|
|
154
|
+
}
|
|
155
|
+
}, [selectedRows, filteredData])
|
|
156
|
+
|
|
157
|
+
// Utility functions
|
|
158
|
+
const getRowCount = React.useCallback(() => filteredData.length, [filteredData])
|
|
159
|
+
const getSelectedCount = React.useCallback(() => selectedRows.length, [selectedRows])
|
|
160
|
+
|
|
161
|
+
// Reset page when search changes
|
|
162
|
+
React.useEffect(() => {
|
|
163
|
+
setCurrentPage(1)
|
|
164
|
+
}, [searchQuery])
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
filteredData: paginatedData,
|
|
168
|
+
selectedRows,
|
|
169
|
+
searchQuery,
|
|
170
|
+
currentPage,
|
|
171
|
+
totalPages,
|
|
172
|
+
setSearchQuery,
|
|
173
|
+
setCurrentPage,
|
|
174
|
+
selectRow,
|
|
175
|
+
selectAllRows,
|
|
176
|
+
clearSelection,
|
|
177
|
+
exportData,
|
|
178
|
+
getRowCount,
|
|
179
|
+
getSelectedCount,
|
|
180
|
+
isRowSelected,
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Mock docs pro access hook for standalone moonui-pro package
|
|
2
|
+
// Bu hook, moonui-pro'nun bağımsız çalışması için basit bir mock'tur
|
|
3
|
+
|
|
4
|
+
export function useDocsProAccess() {
|
|
5
|
+
// Production ortamında her zaman pro erişim verilir
|
|
6
|
+
// Gerçek uygulamada bu hook uygulamanın kendi auth sistemiyle değiştirilmelidir
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
hasProAccess: true,
|
|
10
|
+
isLoading: false,
|
|
11
|
+
isDocsMode: false, // Standalone package'da docs mode yok
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
interface LicenseCheckResult {
|
|
4
|
+
isValid: boolean
|
|
5
|
+
isLoading: boolean
|
|
6
|
+
error?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// License kontrolü için hook
|
|
10
|
+
export function useLicenseCheck(): LicenseCheckResult {
|
|
11
|
+
const [isValid, setIsValid] = useState(false)
|
|
12
|
+
const [isLoading, setIsLoading] = useState(true)
|
|
13
|
+
const [error, setError] = useState<string>()
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
async function checkLicense() {
|
|
17
|
+
try {
|
|
18
|
+
// Önce localStorage'dan kontrol et
|
|
19
|
+
const cachedLicense = localStorage.getItem('moonui_pro_license')
|
|
20
|
+
if (cachedLicense) {
|
|
21
|
+
const parsed = JSON.parse(cachedLicense)
|
|
22
|
+
if (parsed.expiresAt && new Date(parsed.expiresAt) > new Date()) {
|
|
23
|
+
setIsValid(true)
|
|
24
|
+
setIsLoading(false)
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// API'den kontrol et
|
|
30
|
+
const response = await fetch('/api/license/verify', {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
headers: { 'Content-Type': 'application/json' },
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
key: process.env.NEXT_PUBLIC_MOONUI_LICENSE_KEY || localStorage.getItem('moonui_license_key')
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if (response.ok) {
|
|
39
|
+
const data = await response.json()
|
|
40
|
+
if (data.valid) {
|
|
41
|
+
// Cache'e kaydet
|
|
42
|
+
localStorage.setItem('moonui_pro_license', JSON.stringify({
|
|
43
|
+
valid: true,
|
|
44
|
+
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 saat
|
|
45
|
+
}))
|
|
46
|
+
setIsValid(true)
|
|
47
|
+
} else {
|
|
48
|
+
setError('Invalid license key')
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
setError('License verification failed')
|
|
52
|
+
}
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error('License check error:', err)
|
|
55
|
+
setError('License verification error')
|
|
56
|
+
} finally {
|
|
57
|
+
setIsLoading(false)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
checkLicense()
|
|
62
|
+
}, [])
|
|
63
|
+
|
|
64
|
+
return { isValid, isLoading, error }
|
|
65
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Mock subscription hook for standalone moonui-pro package
|
|
2
|
+
// Bu hook, moonui-pro'nun bağımsız çalışması için basit bir mock'tur
|
|
3
|
+
|
|
4
|
+
export function useSubscription() {
|
|
5
|
+
// Production ortamında her zaman pro erişim verilir
|
|
6
|
+
// Gerçek uygulamada bu hook uygulamanın kendi auth sistemiyle değiştirilmelidir
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
isLoading: false,
|
|
10
|
+
isAuthenticated: true,
|
|
11
|
+
isAdmin: false,
|
|
12
|
+
hasProAccess: true, // Pro package kullanıcıları varsayılan olarak pro erişime sahip
|
|
13
|
+
subscriptionPlan: "pro" as const,
|
|
14
|
+
subscription: {
|
|
15
|
+
status: "active" as const,
|
|
16
|
+
plan: "pro" as const,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Pro Components Export - Source of Truth: packages/moonui-pro
|
|
2
|
+
// Development environment imports from local packages
|
|
3
|
+
|
|
4
|
+
// Package access guard - ensures CLI usage
|
|
5
|
+
import "./utils/package-guard"
|
|
6
|
+
|
|
7
|
+
// Import CSS for auto-loading
|
|
8
|
+
import "./styles/index.css"
|
|
9
|
+
|
|
10
|
+
// Pro Components (Commercial License) - from packages/moonui-pro
|
|
11
|
+
export * from "./components"
|
|
12
|
+
|
|
13
|
+
// Enhanced Components - Premium animations and effects
|
|
14
|
+
export * as Enhanced from "./components/enhanced"
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// MoonUI Micro-interactions System
|
|
2
|
+
// Provides consistent hover, focus, and active states across all components
|
|
3
|
+
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Micro-interaction variants for consistent component behavior
|
|
8
|
+
*/
|
|
9
|
+
export const microInteractionVariants = cva("", {
|
|
10
|
+
variants: {
|
|
11
|
+
hover: {
|
|
12
|
+
lift: [
|
|
13
|
+
"transition-all duration-200 ease-out",
|
|
14
|
+
"hover:-translate-y-0.5",
|
|
15
|
+
"hover:shadow-md",
|
|
16
|
+
],
|
|
17
|
+
glow: [
|
|
18
|
+
"transition-all duration-300 ease-out",
|
|
19
|
+
"hover:shadow-lg",
|
|
20
|
+
"hover:shadow-primary/20",
|
|
21
|
+
],
|
|
22
|
+
scale: [
|
|
23
|
+
"transition-transform duration-200 ease-out",
|
|
24
|
+
"hover:scale-105",
|
|
25
|
+
"active:scale-95",
|
|
26
|
+
],
|
|
27
|
+
brightness: [
|
|
28
|
+
"transition-all duration-200 ease-out",
|
|
29
|
+
"hover:brightness-110",
|
|
30
|
+
"active:brightness-95",
|
|
31
|
+
],
|
|
32
|
+
border: [
|
|
33
|
+
"transition-all duration-200 ease-out",
|
|
34
|
+
"hover:border-primary/50",
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
focus: {
|
|
38
|
+
ring: [
|
|
39
|
+
"focus:outline-none",
|
|
40
|
+
"focus-visible:ring-2",
|
|
41
|
+
"focus-visible:ring-primary/50",
|
|
42
|
+
"focus-visible:ring-offset-2",
|
|
43
|
+
],
|
|
44
|
+
glow: [
|
|
45
|
+
"focus:outline-none",
|
|
46
|
+
"focus-visible:shadow-lg",
|
|
47
|
+
"focus-visible:shadow-primary/30",
|
|
48
|
+
],
|
|
49
|
+
border: [
|
|
50
|
+
"focus:outline-none",
|
|
51
|
+
"focus-visible:border-primary",
|
|
52
|
+
"focus-visible:border-2",
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
active: {
|
|
56
|
+
scale: [
|
|
57
|
+
"active:scale-95",
|
|
58
|
+
"transition-transform duration-100",
|
|
59
|
+
],
|
|
60
|
+
darken: [
|
|
61
|
+
"active:brightness-90",
|
|
62
|
+
"transition-all duration-100",
|
|
63
|
+
],
|
|
64
|
+
depress: [
|
|
65
|
+
"active:translate-y-0.5",
|
|
66
|
+
"active:shadow-sm",
|
|
67
|
+
"transition-all duration-100",
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
cursor: {
|
|
71
|
+
pointer: "cursor-pointer",
|
|
72
|
+
grab: "cursor-grab active:cursor-grabbing",
|
|
73
|
+
text: "cursor-text",
|
|
74
|
+
wait: "cursor-wait",
|
|
75
|
+
help: "cursor-help",
|
|
76
|
+
notAllowed: "cursor-not-allowed",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
defaultVariants: {
|
|
80
|
+
hover: "lift",
|
|
81
|
+
focus: "ring",
|
|
82
|
+
active: "scale",
|
|
83
|
+
cursor: "pointer",
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Spring animation configurations
|
|
89
|
+
*/
|
|
90
|
+
export const springAnimations = {
|
|
91
|
+
// Smooth spring for general use
|
|
92
|
+
smooth: {
|
|
93
|
+
type: "spring",
|
|
94
|
+
stiffness: 260,
|
|
95
|
+
damping: 20,
|
|
96
|
+
},
|
|
97
|
+
// Bouncy spring for playful interactions
|
|
98
|
+
bouncy: {
|
|
99
|
+
type: "spring",
|
|
100
|
+
stiffness: 300,
|
|
101
|
+
damping: 15,
|
|
102
|
+
},
|
|
103
|
+
// Stiff spring for quick responses
|
|
104
|
+
stiff: {
|
|
105
|
+
type: "spring",
|
|
106
|
+
stiffness: 400,
|
|
107
|
+
damping: 25,
|
|
108
|
+
},
|
|
109
|
+
// Gentle spring for subtle movements
|
|
110
|
+
gentle: {
|
|
111
|
+
type: "spring",
|
|
112
|
+
stiffness: 150,
|
|
113
|
+
damping: 15,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Hover animation presets
|
|
119
|
+
*/
|
|
120
|
+
export const hoverAnimations = {
|
|
121
|
+
lift: {
|
|
122
|
+
y: -2,
|
|
123
|
+
transition: springAnimations.smooth,
|
|
124
|
+
},
|
|
125
|
+
scale: {
|
|
126
|
+
scale: 1.05,
|
|
127
|
+
transition: springAnimations.smooth,
|
|
128
|
+
},
|
|
129
|
+
glow: {
|
|
130
|
+
boxShadow: "0 0 20px rgba(var(--primary), 0.3)",
|
|
131
|
+
transition: springAnimations.smooth,
|
|
132
|
+
},
|
|
133
|
+
rotate: {
|
|
134
|
+
rotate: 2,
|
|
135
|
+
transition: springAnimations.bouncy,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Tap/Click animation presets
|
|
141
|
+
*/
|
|
142
|
+
export const tapAnimations = {
|
|
143
|
+
scale: {
|
|
144
|
+
scale: 0.95,
|
|
145
|
+
transition: { duration: 0.1 },
|
|
146
|
+
},
|
|
147
|
+
depress: {
|
|
148
|
+
y: 1,
|
|
149
|
+
transition: { duration: 0.1 },
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Focus animation presets
|
|
155
|
+
*/
|
|
156
|
+
export const focusAnimations = {
|
|
157
|
+
ring: {
|
|
158
|
+
boxShadow: "0 0 0 2px var(--background), 0 0 0 4px var(--primary)",
|
|
159
|
+
transition: springAnimations.smooth,
|
|
160
|
+
},
|
|
161
|
+
glow: {
|
|
162
|
+
boxShadow: "0 0 0 3px rgba(var(--primary), 0.3)",
|
|
163
|
+
transition: springAnimations.smooth,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Stagger animation for lists
|
|
169
|
+
*/
|
|
170
|
+
export const staggerAnimation = {
|
|
171
|
+
container: {
|
|
172
|
+
hidden: { opacity: 0 },
|
|
173
|
+
show: {
|
|
174
|
+
opacity: 1,
|
|
175
|
+
transition: {
|
|
176
|
+
staggerChildren: 0.05,
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
item: {
|
|
181
|
+
hidden: { opacity: 0, y: 20 },
|
|
182
|
+
show: {
|
|
183
|
+
opacity: 1,
|
|
184
|
+
y: 0,
|
|
185
|
+
transition: springAnimations.smooth,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Page transition animations
|
|
192
|
+
*/
|
|
193
|
+
export const pageTransitions = {
|
|
194
|
+
fadeIn: {
|
|
195
|
+
initial: { opacity: 0 },
|
|
196
|
+
animate: { opacity: 1 },
|
|
197
|
+
exit: { opacity: 0 },
|
|
198
|
+
transition: { duration: 0.3 },
|
|
199
|
+
},
|
|
200
|
+
slideUp: {
|
|
201
|
+
initial: { opacity: 0, y: 20 },
|
|
202
|
+
animate: { opacity: 1, y: 0 },
|
|
203
|
+
exit: { opacity: 0, y: -20 },
|
|
204
|
+
transition: springAnimations.smooth,
|
|
205
|
+
},
|
|
206
|
+
slideRight: {
|
|
207
|
+
initial: { opacity: 0, x: -20 },
|
|
208
|
+
animate: { opacity: 1, x: 0 },
|
|
209
|
+
exit: { opacity: 0, x: 20 },
|
|
210
|
+
transition: springAnimations.smooth,
|
|
211
|
+
},
|
|
212
|
+
scale: {
|
|
213
|
+
initial: { opacity: 0, scale: 0.95 },
|
|
214
|
+
animate: { opacity: 1, scale: 1 },
|
|
215
|
+
exit: { opacity: 0, scale: 1.05 },
|
|
216
|
+
transition: springAnimations.smooth,
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Skeleton loading animation
|
|
222
|
+
*/
|
|
223
|
+
export const skeletonAnimation = {
|
|
224
|
+
initial: { opacity: 0.5 },
|
|
225
|
+
animate: {
|
|
226
|
+
opacity: [0.5, 0.8, 0.5],
|
|
227
|
+
transition: {
|
|
228
|
+
duration: 1.5,
|
|
229
|
+
repeat: Infinity,
|
|
230
|
+
ease: "easeInOut",
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Tooltip animation
|
|
237
|
+
*/
|
|
238
|
+
export const tooltipAnimation = {
|
|
239
|
+
initial: { opacity: 0, scale: 0.95 },
|
|
240
|
+
animate: { opacity: 1, scale: 1 },
|
|
241
|
+
exit: { opacity: 0, scale: 0.95 },
|
|
242
|
+
transition: { duration: 0.15 },
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Notification animation
|
|
247
|
+
*/
|
|
248
|
+
export const notificationAnimation = {
|
|
249
|
+
initial: { opacity: 0, y: -20, scale: 0.95 },
|
|
250
|
+
animate: { opacity: 1, y: 0, scale: 1 },
|
|
251
|
+
exit: { opacity: 0, scale: 0.95, transition: { duration: 0.15 } },
|
|
252
|
+
transition: springAnimations.bouncy,
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
export type MicroInteractionProps = VariantProps<typeof microInteractionVariants>;
|