srcdev-nuxt-components 6.1.42 → 6.2.1

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.
@@ -9,7 +9,7 @@
9
9
  </template>
10
10
 
11
11
  <script setup lang="ts">
12
- import { useBreakpoints, useElementSize, useResizeObserver } from "@vueuse/core"
12
+ import { useElementSize, useResizeObserver } from "@vueuse/core"
13
13
 
14
14
  const props = defineProps({
15
15
  gridData: {
@@ -0,0 +1,178 @@
1
+ <template>
2
+ <component
3
+ :is="tag"
4
+ class="wipe-away-vertical"
5
+ :class="[elementClasses]"
6
+ :style="{ 'timeline-scope': timelineScope }"
7
+ ref="scrollContainerRef"
8
+ >
9
+ <div ref="stickyItemsContainerRef" class="sticky-items-container">
10
+ <div
11
+ class="sticky-item"
12
+ v-for="(item, key) in itemCount"
13
+ :key="key"
14
+ :style="{
15
+ 'animation-timeline': key === itemCount - 1 ? 'none' : `--section-${timelineId}-${key}`,
16
+ 'z-index': itemCount - key,
17
+ }"
18
+ ref="stickyItemsRef"
19
+ >
20
+ <slot :name="`stickyItem-${key}`"></slot>
21
+ </div>
22
+ </div>
23
+
24
+ <section
25
+ v-for="(item, key) in itemCount"
26
+ :key="key"
27
+ class="scrolling-section"
28
+ :style="{
29
+ 'view-timeline-name': `--section-${timelineId}-${key}`,
30
+ }"
31
+ ref="scrollingItemsRef"
32
+ >
33
+ <slot :name="`scrollingItem-${key}`"></slot>
34
+ </section>
35
+ </component>
36
+ </template>
37
+
38
+ <script setup lang="ts">
39
+ const props = defineProps({
40
+ tag: {
41
+ type: String as PropType<"div" | "section" | "main" | "article" | "aside">,
42
+ default: "div",
43
+ validator: (val: string) => ["div", "section", "main", "article", "aside"].includes(val),
44
+ },
45
+ itemCount: {
46
+ type: Number as PropType<number>,
47
+ default: 0,
48
+ },
49
+ styleClassPassthrough: {
50
+ type: [String, Array] as PropType<string | string[]>,
51
+ default: () => [],
52
+ },
53
+ })
54
+
55
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
56
+
57
+ const timelineId = useId()
58
+ const stickyItemsContainerRef = useTemplateRef<HTMLElement | null>("stickyItemsContainerRef")
59
+ const stickyItemsRef = useTemplateRef<HTMLElement[] | null>("stickyItemsRef")
60
+ const scrollContainerRef = useTemplateRef<HTMLElement | null>("scrollContainerRef")
61
+ const scrollingItemsRef = useTemplateRef<HTMLElement[] | null>("scrollingItemsRef")
62
+ const timelineInset = ref("35% 35%")
63
+ const topPercent = ref("0")
64
+ const bottomPercent = ref("0")
65
+
66
+ const timelineScope = computed(() =>
67
+ Array.from({ length: props.itemCount }, (_, i) => `--section-${timelineId}-${i}`).join(", ")
68
+ )
69
+
70
+ const calculateInset = () => {
71
+ if (!stickyItemsContainerRef.value) return
72
+
73
+ const rect = stickyItemsContainerRef.value.getBoundingClientRect()
74
+ const innerHeight = window.innerHeight
75
+
76
+ topPercent.value = ((rect.top / innerHeight) * 100).toFixed(2)
77
+ bottomPercent.value = (((innerHeight - rect.bottom) / innerHeight) * 100).toFixed(2)
78
+
79
+ timelineInset.value = `${topPercent.value}% ${bottomPercent.value}%`
80
+
81
+ if (!scrollContainerRef.value) return
82
+ scrollContainerRef.value.style.setProperty("--calculated-inset", timelineInset.value)
83
+ }
84
+
85
+ let requestAnimationFrameId: number | null = null
86
+ const onScrollDebounce = () => {
87
+ if (requestAnimationFrameId !== null) return
88
+ requestAnimationFrameId = requestAnimationFrame(() => {
89
+ calculateInset()
90
+ requestAnimationFrameId = null
91
+ })
92
+ }
93
+
94
+ watch(
95
+ () => props.styleClassPassthrough,
96
+ () => {
97
+ resetElementClasses(props.styleClassPassthrough)
98
+ }
99
+ )
100
+
101
+ const fallbackScrollHandler = () => {
102
+ const sections = scrollingItemsRef.value || []
103
+ const layers = stickyItemsRef.value || []
104
+
105
+ const mid = window.innerHeight / 2
106
+
107
+ sections.forEach((section, i) => {
108
+ const rect = section.getBoundingClientRect()
109
+ const active = rect.top <= mid && rect.bottom >= mid
110
+ if (layers[i]) layers[i].style.opacity = active ? "1" : "0"
111
+ })
112
+ }
113
+
114
+ const supportsScrollTimeline = import.meta.client ? CSS.supports("animation-timeline: view()") : false
115
+
116
+ onMounted(() => {
117
+ calculateInset()
118
+ if (supportsScrollTimeline) {
119
+ window.addEventListener("scroll", onScrollDebounce)
120
+ } else {
121
+ window.addEventListener("scroll", fallbackScrollHandler)
122
+ }
123
+ })
124
+
125
+ onUnmounted(() => {
126
+ if (supportsScrollTimeline) {
127
+ window.removeEventListener("scroll", onScrollDebounce)
128
+ } else {
129
+ window.removeEventListener("scroll", fallbackScrollHandler)
130
+ }
131
+ })
132
+ </script>
133
+
134
+ <style lang="css">
135
+ .wipe-away-vertical {
136
+ .sticky-items-container {
137
+ position: sticky;
138
+ top: 50%;
139
+ left: 100%;
140
+ transform: translateY(-50%);
141
+
142
+ .sticky-item {
143
+ position: absolute;
144
+ inset: 0;
145
+ border-radius: 0.5rem;
146
+ width: 100%;
147
+ }
148
+ }
149
+
150
+ .scrolling-section {
151
+ view-timeline-axis: block;
152
+ view-timeline-inset: var(--calculated-inset);
153
+ }
154
+ }
155
+
156
+ @supports (animation-timeline: view()) {
157
+ @keyframes wipe-out {
158
+ 0% {
159
+ clip-path: inset(0 0 0% 0);
160
+ }
161
+ 100% {
162
+ clip-path: inset(0 0 100% 0);
163
+ }
164
+ }
165
+
166
+ .sticky-item {
167
+ animation: wipe-out 1s linear both;
168
+ animation-range: entry 0% entry 100%;
169
+ }
170
+ }
171
+
172
+ @supports not (animation-timeline: view()) {
173
+ .sticky-item {
174
+ opacity: 0;
175
+ transition: opacity 0.4s ease-in-out;
176
+ }
177
+ }
178
+ </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "6.1.42",
4
+ "version": "6.2.1",
5
5
  "main": "nuxt.config.ts",
6
6
  "scripts": {
7
7
  "clean": "rm -rf .nuxt && rm -rf .output && rm -rf .playground/.nuxt && rm -rf .playground/.output",