@wyxos/vibe 1.6.21 → 1.6.23
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/lib/index.js +1252 -1024
- package/lib/vibe.css +1 -1
- package/package.json +1 -1
- package/src/Masonry.vue +973 -1622
- package/src/components/MasonryItem.vue +4 -1
- package/src/useMasonryDimensions.ts +59 -0
- package/src/useMasonryItems.ts +218 -0
- package/src/useMasonryLayout.ts +160 -0
- package/src/useMasonryPagination.ts +342 -0
- package/src/useMasonryScroll.ts +60 -60
- package/src/useMasonryTransitions.ts +39 -1
- package/src/useMasonryVirtualization.ts +140 -0
- package/src/useSwipeMode.ts +233 -0
- package/src/utils/errorHandler.ts +8 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { computed, ref, type Ref, type ComputedRef } from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface UseSwipeModeOptions {
|
|
4
|
+
useSwipeMode: ComputedRef<boolean>
|
|
5
|
+
masonry: Ref<any[]>
|
|
6
|
+
isLoading: Ref<boolean>
|
|
7
|
+
loadNext: () => Promise<any>
|
|
8
|
+
loadPage: (page: any) => Promise<any>
|
|
9
|
+
paginationHistory: Ref<any[]>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UseSwipeModeReturn {
|
|
13
|
+
// State
|
|
14
|
+
currentSwipeIndex: Ref<number>
|
|
15
|
+
swipeOffset: Ref<number>
|
|
16
|
+
isDragging: Ref<boolean>
|
|
17
|
+
swipeContainer: Ref<HTMLElement | null>
|
|
18
|
+
|
|
19
|
+
// Computed
|
|
20
|
+
currentItem: ComputedRef<any | null>
|
|
21
|
+
nextItem: ComputedRef<any | null>
|
|
22
|
+
previousItem: ComputedRef<any | null>
|
|
23
|
+
|
|
24
|
+
// Functions
|
|
25
|
+
handleTouchStart: (e: TouchEvent) => void
|
|
26
|
+
handleTouchMove: (e: TouchEvent) => void
|
|
27
|
+
handleTouchEnd: (e: TouchEvent) => void
|
|
28
|
+
handleMouseDown: (e: MouseEvent) => void
|
|
29
|
+
handleMouseMove: (e: MouseEvent) => void
|
|
30
|
+
handleMouseUp: (e: MouseEvent) => void
|
|
31
|
+
goToNextItem: () => void
|
|
32
|
+
goToPreviousItem: () => void
|
|
33
|
+
snapToCurrentItem: () => void
|
|
34
|
+
handleWindowResize: () => void
|
|
35
|
+
reset: () => void
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function useSwipeMode(options: UseSwipeModeOptions): UseSwipeModeReturn {
|
|
39
|
+
const { useSwipeMode, masonry, isLoading, loadNext, loadPage, paginationHistory } = options
|
|
40
|
+
|
|
41
|
+
// Swipe mode state
|
|
42
|
+
const currentSwipeIndex = ref<number>(0)
|
|
43
|
+
const swipeOffset = ref<number>(0)
|
|
44
|
+
const isDragging = ref<boolean>(false)
|
|
45
|
+
const dragStartY = ref<number>(0)
|
|
46
|
+
const dragStartOffset = ref<number>(0)
|
|
47
|
+
const swipeContainer = ref<HTMLElement | null>(null)
|
|
48
|
+
|
|
49
|
+
// Get current item index for swipe mode
|
|
50
|
+
const currentItem = computed(() => {
|
|
51
|
+
if (!useSwipeMode.value || masonry.value.length === 0) return null
|
|
52
|
+
const index = Math.max(0, Math.min(currentSwipeIndex.value, masonry.value.length - 1))
|
|
53
|
+
return masonry.value[index] || null
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// Get next/previous items for preloading in swipe mode
|
|
57
|
+
const nextItem = computed(() => {
|
|
58
|
+
if (!useSwipeMode.value || !currentItem.value) return null
|
|
59
|
+
const nextIndex = currentSwipeIndex.value + 1
|
|
60
|
+
if (nextIndex >= masonry.value.length) return null
|
|
61
|
+
return masonry.value[nextIndex] || null
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const previousItem = computed(() => {
|
|
65
|
+
if (!useSwipeMode.value || !currentItem.value) return null
|
|
66
|
+
const prevIndex = currentSwipeIndex.value - 1
|
|
67
|
+
if (prevIndex < 0) return null
|
|
68
|
+
return masonry.value[prevIndex] || null
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
function snapToCurrentItem() {
|
|
72
|
+
if (!swipeContainer.value) return
|
|
73
|
+
|
|
74
|
+
// Use container height for swipe mode instead of window height
|
|
75
|
+
const viewportHeight = swipeContainer.value.clientHeight
|
|
76
|
+
swipeOffset.value = -currentSwipeIndex.value * viewportHeight
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function goToNextItem() {
|
|
80
|
+
if (!nextItem.value) {
|
|
81
|
+
// Try to load next page
|
|
82
|
+
loadNext()
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
currentSwipeIndex.value++
|
|
87
|
+
snapToCurrentItem()
|
|
88
|
+
|
|
89
|
+
// Preload next item if we're near the end
|
|
90
|
+
if (currentSwipeIndex.value >= masonry.value.length - 5) {
|
|
91
|
+
loadNext()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function goToPreviousItem() {
|
|
96
|
+
if (!previousItem.value) return
|
|
97
|
+
|
|
98
|
+
currentSwipeIndex.value--
|
|
99
|
+
snapToCurrentItem()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Swipe gesture handlers
|
|
103
|
+
function handleTouchStart(e: TouchEvent) {
|
|
104
|
+
if (!useSwipeMode.value) return
|
|
105
|
+
isDragging.value = true
|
|
106
|
+
dragStartY.value = e.touches[0].clientY
|
|
107
|
+
dragStartOffset.value = swipeOffset.value
|
|
108
|
+
e.preventDefault()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function handleTouchMove(e: TouchEvent) {
|
|
112
|
+
if (!useSwipeMode.value || !isDragging.value) return
|
|
113
|
+
const deltaY = e.touches[0].clientY - dragStartY.value
|
|
114
|
+
swipeOffset.value = dragStartOffset.value + deltaY
|
|
115
|
+
e.preventDefault()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function handleTouchEnd(e: TouchEvent) {
|
|
119
|
+
if (!useSwipeMode.value || !isDragging.value) return
|
|
120
|
+
isDragging.value = false
|
|
121
|
+
|
|
122
|
+
const deltaY = swipeOffset.value - dragStartOffset.value
|
|
123
|
+
const threshold = 100 // Minimum swipe distance to trigger navigation
|
|
124
|
+
|
|
125
|
+
if (Math.abs(deltaY) > threshold) {
|
|
126
|
+
if (deltaY > 0 && previousItem.value) {
|
|
127
|
+
// Swipe down - go to previous
|
|
128
|
+
goToPreviousItem()
|
|
129
|
+
} else if (deltaY < 0 && nextItem.value) {
|
|
130
|
+
// Swipe up - go to next
|
|
131
|
+
goToNextItem()
|
|
132
|
+
} else {
|
|
133
|
+
// Snap back
|
|
134
|
+
snapToCurrentItem()
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
// Snap back if swipe wasn't far enough
|
|
138
|
+
snapToCurrentItem()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
e.preventDefault()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Mouse drag handlers for desktop testing
|
|
145
|
+
function handleMouseDown(e: MouseEvent) {
|
|
146
|
+
if (!useSwipeMode.value) return
|
|
147
|
+
isDragging.value = true
|
|
148
|
+
dragStartY.value = e.clientY
|
|
149
|
+
dragStartOffset.value = swipeOffset.value
|
|
150
|
+
e.preventDefault()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function handleMouseMove(e: MouseEvent) {
|
|
154
|
+
if (!useSwipeMode.value || !isDragging.value) return
|
|
155
|
+
const deltaY = e.clientY - dragStartY.value
|
|
156
|
+
swipeOffset.value = dragStartOffset.value + deltaY
|
|
157
|
+
e.preventDefault()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function handleMouseUp(e: MouseEvent) {
|
|
161
|
+
if (!useSwipeMode.value || !isDragging.value) return
|
|
162
|
+
isDragging.value = false
|
|
163
|
+
|
|
164
|
+
const deltaY = swipeOffset.value - dragStartOffset.value
|
|
165
|
+
const threshold = 100
|
|
166
|
+
|
|
167
|
+
if (Math.abs(deltaY) > threshold) {
|
|
168
|
+
if (deltaY > 0 && previousItem.value) {
|
|
169
|
+
goToPreviousItem()
|
|
170
|
+
} else if (deltaY < 0 && nextItem.value) {
|
|
171
|
+
goToNextItem()
|
|
172
|
+
} else {
|
|
173
|
+
snapToCurrentItem()
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
snapToCurrentItem()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
e.preventDefault()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Watch for container/window resize to update swipe mode
|
|
183
|
+
function handleWindowResize() {
|
|
184
|
+
// If switching from swipe to masonry, reset swipe state
|
|
185
|
+
if (!useSwipeMode.value && currentSwipeIndex.value > 0) {
|
|
186
|
+
currentSwipeIndex.value = 0
|
|
187
|
+
swipeOffset.value = 0
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// If switching to swipe mode, ensure we have items loaded
|
|
191
|
+
if (useSwipeMode.value && masonry.value.length === 0 && !isLoading.value) {
|
|
192
|
+
loadPage(paginationHistory.value[0] as any)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Re-snap to current item on resize to adjust offset
|
|
196
|
+
if (useSwipeMode.value) {
|
|
197
|
+
snapToCurrentItem()
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function reset() {
|
|
202
|
+
currentSwipeIndex.value = 0
|
|
203
|
+
swipeOffset.value = 0
|
|
204
|
+
isDragging.value = false
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
// State
|
|
209
|
+
currentSwipeIndex,
|
|
210
|
+
swipeOffset,
|
|
211
|
+
isDragging,
|
|
212
|
+
swipeContainer,
|
|
213
|
+
|
|
214
|
+
// Computed
|
|
215
|
+
currentItem,
|
|
216
|
+
nextItem,
|
|
217
|
+
previousItem,
|
|
218
|
+
|
|
219
|
+
// Functions
|
|
220
|
+
handleTouchStart,
|
|
221
|
+
handleTouchMove,
|
|
222
|
+
handleTouchEnd,
|
|
223
|
+
handleMouseDown,
|
|
224
|
+
handleMouseMove,
|
|
225
|
+
handleMouseUp,
|
|
226
|
+
goToNextItem,
|
|
227
|
+
goToPreviousItem,
|
|
228
|
+
snapToCurrentItem,
|
|
229
|
+
handleWindowResize,
|
|
230
|
+
reset
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|