@vikeriait/vue-viewport 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vikeria Srl
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,294 @@
1
+ # @vikeriait/vue-viewport
2
+
3
+ A lightweight, high-performance Vue 3 directive and composable to detect when elements enter the viewport, featuring "Smart Presets", automatic margin compensation for smooth reveals, and seamless Tailwind CSS integration.
4
+
5
+ ## Features
6
+
7
+ - 👁 **Viewport Detection**: Track when elements enter or leave with precision.
8
+ - 🎨 **Tailwind Presets**: Ready-to-use animations like `fade-up`, `scale-up`, `slide-left`.
9
+ - 🧠 **Smart Presets**: `fade-y` and `slide-y` automatically adapt direction based on scroll.
10
+ - 📐 **Auto RootMargin**: Intelligently calculates the optimal `rootMargin` based on your applied styles (e.g., `translate-y-20` or `--viewport-distance`) to ensure animations start exactly when the element enters, preventing "late" triggers or blank spaces.
11
+ - 🧩 **Modular**: Use presets via the directive and control timing (delay, duration) via standard Tailwind classes.
12
+ - 🔀 **Conditional Logic**: Apply animations only when scrolling `down` or `up`.
13
+ - 🛠 **Customizable**: Works with custom CSS, inline styles (`style="transform:..."`), and Tailwind classes.
14
+ - 📦 **Composable**: `useInViewport` for programmatic control.
15
+ - ♿ **Accessibility**: Respects `prefers-reduced-motion` out of the box.
16
+ - 🦾 **TypeScript**: Fully typed.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pnpm add @vikeriait/vue-viewport
22
+ # or
23
+ npm install @vikeriait/vue-viewport
24
+ ```
25
+
26
+ ## Setup
27
+
28
+ ### 1. Global Plugin Registration
29
+
30
+ ```ts
31
+ import { createApp } from 'vue'
32
+ import ViewportPlugin from '@vikeriait/vue-viewport'
33
+
34
+ const app = createApp(App)
35
+
36
+ app.use(ViewportPlugin)
37
+ app.mount('#app')
38
+ ```
39
+
40
+ ### 2. Import Styles
41
+
42
+ **For Tailwind CSS (v4) users:**
43
+ Import the library's Tailwind configuration to enable the presets and custom variants (like `inviewport:`).
44
+
45
+ ```css
46
+ @import "tailwindcss";
47
+
48
+ @import "@vikeriait/vue-viewport";
49
+ /* or explicitly: @import "@vikeriait/vue-viewport/tailwind"; */
50
+ ```
51
+
52
+ **For Standard CSS users:**
53
+ If you don't use Tailwind, import the CSS bundle to enable the built-in presets.
54
+
55
+ ```ts
56
+ import '@vikeriait/vue-viewport/css'
57
+ ```
58
+
59
+ ## Usage
60
+
61
+ ### Directive `v-viewport`
62
+
63
+ #### 1. Basic Presets
64
+ Simply pass the preset name string.
65
+
66
+ ```html
67
+ <div v-viewport="'fade-up'">
68
+ I will fade up when scrolled into view!
69
+ </div>
70
+ ```
71
+
72
+ #### 2. Utility Classes
73
+ If you want to add Tailwind (or custom) utility classes like delays or durations, apply them directly to the `class` attribute. The directive handles the preset logic separately.
74
+
75
+ ```html
76
+ <!-- ✅ CORRECT: Separate preset and utility classes -->
77
+ <div v-viewport="'fade-up'" class="delay-200 duration-1000">
78
+ I appear slowly with a delay.
79
+ </div>
80
+ ```
81
+
82
+ #### 3. Smart Presets (`-y`)
83
+ These presets automatically detect the scroll direction and animate accordingly (e.g., slide up when scrolling down, slide down when scrolling up).
84
+
85
+ ```html
86
+ <div v-viewport="'fade-y'">
87
+ I enter naturally from whichever side you scroll from.
88
+ </div>
89
+ ```
90
+
91
+ #### 4. Directional Modifiers
92
+ Restrict animations to a specific scroll direction by appending `-down` (scrolling down / enter from bottom) or `-up` (scrolling up / enter from top).
93
+
94
+ ```html
95
+ <!-- Animates only when you scroll DOWN to it -->
96
+ <div v-viewport="'fade-up-down'">
97
+ I appear only on normal scroll.
98
+ </div>
99
+ ```
100
+
101
+ #### 5. Staggering
102
+ Delay animations for elements entering at the same time. The library guarantees DOM order execution.
103
+
104
+ You can pass:
105
+ - `number`: Delay in milliseconds (e.g. `100`).
106
+ - `string`: CSS time value (e.g. `'200ms'`, `'0.1s'`).
107
+ - `true`: Uses the global default `--viewport-stagger` (default: 100ms).
108
+
109
+ *Note: The stagger delay is **additive** to any existing CSS delay.*
110
+
111
+ ```html
112
+ <!-- Explicit value -->
113
+ <div v-for="i in 6" v-viewport="{ animation: 'fade-up', stagger: 100 }"></div>
114
+
115
+ <!-- Use default from CSS variable -->
116
+ <div v-for="i in 6" v-viewport="{ animation: 'fade-up', stagger: true }"></div>
117
+ ```
118
+
119
+ #### 6. Inline Timing Control
120
+ You can override the global defaults or utility classes directly via options. This is useful for dynamic values.
121
+
122
+ ```html
123
+ <div v-viewport="{ animation: 'fade-up', duration: 1000, delay: 500, easing: 'ease-in-out' }">
124
+ I have custom timing!
125
+ </div>
126
+ ```
127
+
128
+ ### Component `<VViewport />`
129
+
130
+ Prefer components over directives? We got you.
131
+
132
+ **Global Usage:**
133
+ The plugin registers the component globally as `<VViewport />`.
134
+
135
+ ```html
136
+ <VViewport preset="fade-up">
137
+ <h1>Hello World</h1>
138
+ </VViewport>
139
+ ```
140
+
141
+ **Local Import:**
142
+ You can also import it directly (exported as `Viewport`).
143
+
144
+ ```html
145
+ <script setup>
146
+ import { Viewport } from '@vikeriait/vue-viewport'
147
+ </script>
148
+
149
+ <template>
150
+ <Viewport as="section" preset="fade-up" :stagger="100">
151
+ ...
152
+ </Viewport>
153
+ </template>
154
+ ```
155
+
156
+ **Props:**
157
+ - `as`: (string) HTML tag (default: 'div').
158
+ - `preset`: (string) Animation name.
159
+ - `stagger`: (number/string/boolean) Delay logic.
160
+ - `duration`: (number/string) Custom duration.
161
+ - `delay`: (number/string) Custom delay.
162
+ - `easing`: (string) Custom easing.
163
+ - `once`: (boolean) Disconnect after first entry.
164
+ - `threshold`: (number) Intersection threshold.
165
+ - `rootMargin`: (string) Custom margin.
166
+
167
+ ### Advanced: Tailwind & Custom Styles
168
+
169
+ The library is **smart**. If you use custom transforms (via Tailwind classes or inline styles), it detects them and automatically adjusts the IntersectionObserver's `rootMargin` to ensure the animation triggers precisely when the *visual* element enters the screen.
170
+
171
+ **Example with Tailwind:**
172
+ The library sees `translate-y-20` (80px), calculates the offset, and triggers the animation 80px earlier to prevent any "blank space" or jump.
173
+
174
+ ```html
175
+ <div
176
+ v-viewport
177
+ class="opacity-0 translate-y-20 transition-all duration-700
178
+ inviewport:opacity-100 inviewport:translate-y-0"
179
+ >
180
+ I am a fully custom Tailwind animation handled perfectly.
181
+ </div>
182
+ ```
183
+
184
+ **Example with Inline Style:**
185
+
186
+ ```html
187
+ <div
188
+ v-viewport
189
+ style="opacity: 0; transform: translateY(100px); transition: 1s"
190
+ class="inviewport:opacity-100 inviewport:translate-y-0"
191
+ >
192
+ I work too!
193
+ </div>
194
+ ```
195
+
196
+ ### Composable `useInViewport`
197
+
198
+ ```vue
199
+ <script setup lang="ts">
200
+ import { ref } from 'vue'
201
+ import { useInViewport } from '@vikeriait/vue-viewport'
202
+
203
+ const target = ref(null)
204
+ const { isInView, entry } = useInViewport(target)
205
+ </script>
206
+
207
+ <template>
208
+ <div ref="target">
209
+ {{ isInView ? 'Visible' : 'Hidden' }}
210
+ </div>
211
+ </template>
212
+ ```
213
+
214
+ ## Built-in Presets
215
+
216
+ | Preset | Description |
217
+ |:-------------------|:----------------|
218
+ | `fade` | Simple fade |
219
+ | `fade-up/down` | Fade + Slide Y |
220
+ | `fade-left/right` | Fade + Slide X |
221
+ | `slide-up/down` | Slide Y |
222
+ | `slide-left/right` | Slide X |
223
+ | `scale-up/down` | Scale Transform |
224
+ | `blur-in` | Blur Reveal |
225
+
226
+ *Note: All presets support `-down` (on scroll down) and `-up` (on scroll up) suffixes.*
227
+
228
+ ## CSS Variables
229
+
230
+ You can customize the global defaults in your CSS:
231
+
232
+ ```css
233
+ :root {
234
+ --viewport-duration: 0.6s;
235
+ --viewport-ease: ease-out;
236
+ --viewport-delay: 0s; /* Global default delay */
237
+ --viewport-distance: 2rem;
238
+ --viewport-stagger: 100ms;
239
+ --viewport-scale-in: 0.95;
240
+ --viewport-scale-out: 1.05;
241
+ --viewport-blur: 12px;
242
+ }
243
+ ```
244
+
245
+ ## Accessibility & Print
246
+
247
+ The library is designed to be inclusive and reliable:
248
+
249
+ - **Reduced Motion**: If a user has enabled "Reduce Motion" in their system settings, the library automatically detects the `@media (prefers-reduced-motion: reduce)` preference. In this case, all animations are disabled, and elements appear instantly in their final state (`opacity: 1`, `transform: none`).
250
+ - **Print Friendly**: When printing a page, all animations and initial "hidden" states are stripped away via `@media print`. This ensures that all content is fully visible and correctly positioned on the physical or PDF page.
251
+
252
+ ## API Reference
253
+
254
+ ### Plugin Options
255
+
256
+ Options passed to `app.use(ViewportPlugin, options)`.
257
+
258
+ | Option | Type | Default | Description |
259
+ | :--- | :--- | :--- | :--- |
260
+ | `presets` | `Record<string, string>` | `DEFAULT_PRESETS` | Custom presets map. |
261
+
262
+ ### Directive Options
263
+
264
+ Options object passed as `v-viewport="{ ... }"`.
265
+
266
+ | Option | Type | Default | Description |
267
+ | :--- | :--- | :--- | :--- |
268
+ | `animation` | `string` | `undefined` | The animation class or preset name(s). |
269
+ | `stagger` | `number \| string \| boolean` | `undefined` | Delay (ms/string) or `true` for global default. |
270
+ | `duration` | `number \| string` | `undefined` | Custom duration. |
271
+ | `delay` | `number \| string` | `undefined` | Custom delay. |
272
+ | `easing` | `string` | `undefined` | Custom easing function. |
273
+ | `once` | `boolean` | `false` | Disconnect after first entry. |
274
+ | `threshold` | `number \| number[]` | `0.1` | IntersectionObserver threshold. |
275
+ | `rootMargin` | `string` | `auto` | Manually override the calculated margin. |
276
+ | `onEnter` | `function` | `-` | Callback when entering viewport. |
277
+ | `onLeave` | `function` | `-` | Callback when leaving viewport. |
278
+
279
+ ### Directive Modifiers
280
+
281
+ | Modifier | Description |
282
+ | :--- | :--- |
283
+ | `.once` | Disconnect after first entry. |
284
+
285
+ ### Directive Events
286
+
287
+ | Event | Type | Description |
288
+ | :--- | :--- | :--- |
289
+ | `@view-enter` | `ViewportEvent` | Dispatched when entering viewport. |
290
+ | `@view-leave` | `ViewportEvent` | Dispatched when leaving viewport. |
291
+
292
+ ## License
293
+
294
+ MIT
@@ -0,0 +1,300 @@
1
+ import { ComponentOptionsMixin } from 'vue';
2
+ import { ComponentProvideOptions } from 'vue';
3
+ import { DefineComponent } from 'vue';
4
+ import { Directive } from 'vue';
5
+ import { ExtractPropTypes } from 'vue';
6
+ import { Plugin as Plugin_2 } from 'vue';
7
+ import { PropType } from 'vue';
8
+ import { PublicProps } from 'vue';
9
+ import { Ref } from 'vue';
10
+
11
+ declare const __VLS_component: DefineComponent<ExtractPropTypes< {
12
+ /** The HTML tag to render. Defaults to 'div'. */
13
+ as: {
14
+ type: StringConstructor;
15
+ default: string;
16
+ };
17
+ /** The animation preset name (e.g., 'fade-up'). */
18
+ preset: {
19
+ type: StringConstructor;
20
+ default: undefined;
21
+ };
22
+ /** Delay in ms or CSS string (e.g. '100ms'). Set to true to use global variable. */
23
+ stagger: {
24
+ type: PropType<ViewportOptions["stagger"]>;
25
+ default: undefined;
26
+ };
27
+ /** Intersection threshold (0.0 - 1.0). */
28
+ threshold: {
29
+ type: PropType<ViewportOptions["threshold"]>;
30
+ default: undefined;
31
+ };
32
+ /** Custom rootMargin string. */
33
+ rootMargin: {
34
+ type: PropType<ViewportOptions["rootMargin"]>;
35
+ default: undefined;
36
+ };
37
+ /** If true, disconnects the observer after the first entry. */
38
+ once: {
39
+ type: BooleanConstructor;
40
+ default: boolean;
41
+ };
42
+ /** Custom root element (defaults to viewport). */
43
+ root: {
44
+ type: PropType<ViewportOptions["root"]>;
45
+ default: undefined;
46
+ };
47
+ /** Custom duration for the animation. */
48
+ duration: {
49
+ type: PropType<ViewportOptions["duration"]>;
50
+ default: undefined;
51
+ };
52
+ /** Custom delay for the animation. */
53
+ delay: {
54
+ type: PropType<ViewportOptions["delay"]>;
55
+ default: undefined;
56
+ };
57
+ /** Custom easing for the animation. */
58
+ easing: {
59
+ type: StringConstructor;
60
+ default: undefined;
61
+ };
62
+ }>, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {} & {
63
+ enter: (payload: {
64
+ entry: IntersectionObserverEntry;
65
+ direction: ViewportDirection;
66
+ }) => any;
67
+ leave: (payload: {
68
+ entry: IntersectionObserverEntry;
69
+ direction: ViewportDirection;
70
+ }) => any;
71
+ }, string, PublicProps, Readonly<ExtractPropTypes< {
72
+ /** The HTML tag to render. Defaults to 'div'. */
73
+ as: {
74
+ type: StringConstructor;
75
+ default: string;
76
+ };
77
+ /** The animation preset name (e.g., 'fade-up'). */
78
+ preset: {
79
+ type: StringConstructor;
80
+ default: undefined;
81
+ };
82
+ /** Delay in ms or CSS string (e.g. '100ms'). Set to true to use global variable. */
83
+ stagger: {
84
+ type: PropType<ViewportOptions["stagger"]>;
85
+ default: undefined;
86
+ };
87
+ /** Intersection threshold (0.0 - 1.0). */
88
+ threshold: {
89
+ type: PropType<ViewportOptions["threshold"]>;
90
+ default: undefined;
91
+ };
92
+ /** Custom rootMargin string. */
93
+ rootMargin: {
94
+ type: PropType<ViewportOptions["rootMargin"]>;
95
+ default: undefined;
96
+ };
97
+ /** If true, disconnects the observer after the first entry. */
98
+ once: {
99
+ type: BooleanConstructor;
100
+ default: boolean;
101
+ };
102
+ /** Custom root element (defaults to viewport). */
103
+ root: {
104
+ type: PropType<ViewportOptions["root"]>;
105
+ default: undefined;
106
+ };
107
+ /** Custom duration for the animation. */
108
+ duration: {
109
+ type: PropType<ViewportOptions["duration"]>;
110
+ default: undefined;
111
+ };
112
+ /** Custom delay for the animation. */
113
+ delay: {
114
+ type: PropType<ViewportOptions["delay"]>;
115
+ default: undefined;
116
+ };
117
+ /** Custom easing for the animation. */
118
+ easing: {
119
+ type: StringConstructor;
120
+ default: undefined;
121
+ };
122
+ }>> & Readonly<{
123
+ onEnter?: ((payload: {
124
+ entry: IntersectionObserverEntry;
125
+ direction: ViewportDirection;
126
+ }) => any) | undefined;
127
+ onLeave?: ((payload: {
128
+ entry: IntersectionObserverEntry;
129
+ direction: ViewportDirection;
130
+ }) => any) | undefined;
131
+ }>, {
132
+ root: Element | Document | null | undefined;
133
+ rootMargin: string | undefined;
134
+ threshold: number | number[] | undefined;
135
+ stagger: string | number | boolean | undefined;
136
+ duration: string | number | undefined;
137
+ delay: string | number | undefined;
138
+ easing: string;
139
+ once: boolean;
140
+ as: string;
141
+ preset: string;
142
+ }, {}, {}, {}, string, ComponentProvideOptions, true, {}, any>;
143
+
144
+ declare function __VLS_template(): {
145
+ attrs: Partial<{}>;
146
+ slots: {
147
+ default?(_: {}): any;
148
+ };
149
+ refs: {};
150
+ rootEl: any;
151
+ };
152
+
153
+ declare type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
154
+
155
+ declare type __VLS_WithTemplateSlots<T, S> = T & {
156
+ new (): {
157
+ $slots: S;
158
+ };
159
+ };
160
+
161
+ /**
162
+ * Interface for the resolved configuration used internally by the directive.
163
+ */
164
+ export declare interface ResolvedConfig {
165
+ options: ViewportOptions;
166
+ animationName: string | undefined;
167
+ once: boolean;
168
+ }
169
+
170
+ /**
171
+ * A composable that tracks whether an element is within the viewport.
172
+ *
173
+ * @param target - The ref of the HTML element to observe.
174
+ * @param options - IntersectionObserver options.
175
+ * @returns Object containing `isInView` boolean ref and the `entry` object.
176
+ *
177
+ * @example
178
+ * ```ts
179
+ * const target = ref(null)
180
+ * const { isInView } = useInViewport(target)
181
+ * ```
182
+ */
183
+ export declare function useInViewport(target: Ref<HTMLElement | null>, options?: IntersectionObserverInit): UseInViewportReturn;
184
+
185
+ /**
186
+ * Return value of the useInViewport composable.
187
+ */
188
+ export declare interface UseInViewportReturn {
189
+ /**
190
+ * Boolean ref indicating if the element is currently in the viewport.
191
+ */
192
+ isInView: Ref<boolean>;
193
+ /**
194
+ * The current IntersectionObserverEntry, or null if not yet observed.
195
+ */
196
+ entry: Ref<IntersectionObserverEntry | null>;
197
+ }
198
+
199
+ export declare const Viewport: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
200
+
201
+ /**
202
+ * Direction of the scroll movement relative to the viewport.
203
+ */
204
+ export declare type ViewportDirection = 'down' | 'up';
205
+
206
+ /**
207
+ * Custom event emitted by the directive on enter/leave.
208
+ */
209
+ export declare type ViewportEvent = CustomEvent<ViewportEventDetail>;
210
+
211
+ /**
212
+ * Detail object for Viewport custom events.
213
+ */
214
+ export declare interface ViewportEventDetail {
215
+ entry: IntersectionObserverEntry;
216
+ direction: ViewportDirection;
217
+ }
218
+
219
+ /**
220
+ * Options for the v-viewport directive.
221
+ * Extends IntersectionObserverInit to allow custom observer configuration.
222
+ */
223
+ export declare interface ViewportOptions extends IntersectionObserverInit {
224
+ /**
225
+ * The preset name(s) to apply (e.g. 'fade-up').
226
+ * Custom utility classes should be applied via the standard 'class' attribute.
227
+ */
228
+ animation?: string;
229
+ /**
230
+ * Stagger delay for elements entering together.
231
+ * - `number`: milliseconds
232
+ * - `string`: CSS time (e.g. '100ms', '0.1s')
233
+ * - `true`: uses global `--viewport-stagger` variable
234
+ */
235
+ stagger?: number | string | boolean;
236
+ /**
237
+ * Custom duration for the animation.
238
+ * - `number`: milliseconds
239
+ * - `string`: CSS time (e.g. '1000ms', '1s')
240
+ */
241
+ duration?: number | string;
242
+ /**
243
+ * Custom delay for the animation.
244
+ * - `number`: milliseconds
245
+ * - `string`: CSS time (e.g. '500ms', '0.5s')
246
+ */
247
+ delay?: number | string;
248
+ /**
249
+ * Custom easing for the animation (e.g. 'ease-in-out', 'cubic-bezier(...)').
250
+ */
251
+ easing?: string;
252
+ /**
253
+ * If true, the observer will disconnect after the first entry.
254
+ */
255
+ once?: boolean;
256
+ /**
257
+ * Callback triggered when the element enters the viewport.
258
+ */
259
+ onEnter?: (entry: IntersectionObserverEntry, direction: ViewportDirection) => void;
260
+ /**
261
+ * Callback triggered when the element leaves the viewport.
262
+ */
263
+ onLeave?: (entry: IntersectionObserverEntry, direction: ViewportDirection) => void;
264
+ }
265
+
266
+ declare const ViewportPlugin: Plugin_2;
267
+ export { ViewportPlugin }
268
+ export default ViewportPlugin;
269
+
270
+ /**
271
+ * Options for the ViewportPlugin installation.
272
+ */
273
+ export declare interface ViewportPluginOptions {
274
+ /**
275
+ * Custom presets to merge with or override the default presets.
276
+ * Key is the preset name, value is the CSS class(es).
277
+ */
278
+ presets?: Record<string, string>;
279
+ }
280
+
281
+ /**
282
+ * Vue Directive: v-viewport
283
+ *
284
+ * Detects when an element enters the viewport and applies animation states via data attributes.
285
+ * Uses data-vp-* attributes to avoid conflicts with Vue's class binding.
286
+ */
287
+ export declare const vViewport: Directive<HTMLElement, ViewportOptions | string>;
288
+
289
+ export { }
290
+
291
+
292
+ declare module 'vue' {
293
+ interface HTMLAttributes {
294
+ onViewEnter?: (event: ViewportEvent) => void;
295
+ onViewLeave?: (event: ViewportEvent) => void;
296
+ }
297
+ interface GlobalDirectives {
298
+ vViewport: ViewportOptions | string;
299
+ }
300
+ }
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ :root{--viewport-duration: .6s;--viewport-ease: ease-out;--viewport-delay: 0s;--viewport-distance: 2rem;--viewport-stagger: .1s;--viewport-scale-in: .95;--viewport-scale-out: 1.05;--viewport-blur: 12px}[data-vp-preset*=animate-]{transition-duration:var(--viewport-duration);transition-timing-function:var(--viewport-ease);transition-delay:var(--viewport-delay)}[data-vp-preset~=animate-fade],[data-vp-preset~=animate-fade-down][data-vp-entry=down],[data-vp-preset~=animate-fade-down][data-vp-pos=below],[data-vp-preset~=animate-fade-up][data-vp-entry=up],[data-vp-preset~=animate-fade-up][data-vp-pos=above]{opacity:0;transition-property:opacity}[data-vp-preset~=animate-fade][data-vp-in-view],[data-vp-preset~=animate-fade-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-fade-up][data-vp-entry=up][data-vp-in-view]{opacity:1}[data-vp-preset~=animate-fade-up],[data-vp-preset~=animate-fade-up-down][data-vp-entry=down],[data-vp-preset~=animate-fade-up-down][data-vp-pos=below],[data-vp-preset~=animate-fade-up-up][data-vp-entry=up],[data-vp-preset~=animate-fade-up-up][data-vp-pos=above]{opacity:0;transform:translateY(var(--viewport-distance));transition-property:opacity,transform}[data-vp-preset~=animate-fade-up][data-vp-in-view],[data-vp-preset~=animate-fade-up-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-fade-up-up][data-vp-entry=up][data-vp-in-view]{opacity:1;transform:translateY(0)}[data-vp-preset~=animate-fade-down],[data-vp-preset~=animate-fade-down-down][data-vp-entry=down],[data-vp-preset~=animate-fade-down-down][data-vp-pos=below],[data-vp-preset~=animate-fade-down-up][data-vp-entry=up],[data-vp-preset~=animate-fade-down-up][data-vp-pos=above]{opacity:0;transform:translateY(calc(var(--viewport-distance) * -1));transition-property:opacity,transform}[data-vp-preset~=animate-fade-down][data-vp-in-view],[data-vp-preset~=animate-fade-down-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-fade-down-up][data-vp-entry=up][data-vp-in-view]{opacity:1;transform:translateY(0)}[data-vp-preset~=animate-fade-left],[data-vp-preset~=animate-fade-left-down][data-vp-entry=down],[data-vp-preset~=animate-fade-left-down][data-vp-pos=below],[data-vp-preset~=animate-fade-left-up][data-vp-entry=up],[data-vp-preset~=animate-fade-left-up][data-vp-pos=above]{opacity:0;transform:translate(var(--viewport-distance));transition-property:opacity,transform}[data-vp-preset~=animate-fade-left][data-vp-in-view],[data-vp-preset~=animate-fade-left-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-fade-left-up][data-vp-entry=up][data-vp-in-view]{opacity:1;transform:translate(0)}[data-vp-preset~=animate-fade-right],[data-vp-preset~=animate-fade-right-down][data-vp-entry=down],[data-vp-preset~=animate-fade-right-down][data-vp-pos=below],[data-vp-preset~=animate-fade-right-up][data-vp-entry=up],[data-vp-preset~=animate-fade-right-up][data-vp-pos=above]{opacity:0;transform:translate(calc(var(--viewport-distance) * -1));transition-property:opacity,transform}[data-vp-preset~=animate-fade-right][data-vp-in-view],[data-vp-preset~=animate-fade-right-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-fade-right-up][data-vp-entry=up][data-vp-in-view]{opacity:1;transform:translate(0)}[data-vp-preset~=animate-slide-up],[data-vp-preset~=animate-slide-up-down][data-vp-entry=down],[data-vp-preset~=animate-slide-up-down][data-vp-pos=below],[data-vp-preset~=animate-slide-up-up][data-vp-entry=up],[data-vp-preset~=animate-slide-up-up][data-vp-pos=above]{transform:translateY(var(--viewport-distance));transition-property:transform}[data-vp-preset~=animate-slide-up][data-vp-in-view],[data-vp-preset~=animate-slide-up-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-slide-up-up][data-vp-entry=up][data-vp-in-view]{transform:translateY(0)}[data-vp-preset~=animate-slide-down],[data-vp-preset~=animate-slide-down-down][data-vp-entry=down],[data-vp-preset~=animate-slide-down-down][data-vp-pos=below],[data-vp-preset~=animate-slide-down-up][data-vp-entry=up],[data-vp-preset~=animate-slide-down-up][data-vp-pos=above]{transform:translateY(calc(var(--viewport-distance) * -1));transition-property:transform}[data-vp-preset~=animate-slide-down][data-vp-in-view],[data-vp-preset~=animate-slide-down-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-slide-down-up][data-vp-entry=up][data-vp-in-view]{transform:translateY(0)}[data-vp-preset~=animate-slide-left],[data-vp-preset~=animate-slide-left-down][data-vp-entry=down],[data-vp-preset~=animate-slide-left-down][data-vp-pos=below],[data-vp-preset~=animate-slide-left-up][data-vp-entry=up],[data-vp-preset~=animate-slide-left-up][data-vp-pos=above]{transform:translate(var(--viewport-distance));transition-property:transform}[data-vp-preset~=animate-slide-left][data-vp-in-view],[data-vp-preset~=animate-slide-left-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-slide-left-up][data-vp-entry=up][data-vp-in-view]{transform:translate(0)}[data-vp-preset~=animate-slide-right],[data-vp-preset~=animate-slide-right-down][data-vp-entry=down],[data-vp-preset~=animate-slide-right-down][data-vp-pos=below],[data-vp-preset~=animate-slide-right-up][data-vp-entry=up],[data-vp-preset~=animate-slide-right-up][data-vp-pos=above]{transform:translate(calc(var(--viewport-distance) * -1));transition-property:transform}[data-vp-preset~=animate-slide-right][data-vp-in-view],[data-vp-preset~=animate-slide-right-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-slide-right-up][data-vp-entry=up][data-vp-in-view]{transform:translate(0)}[data-vp-preset~=animate-scale-up],[data-vp-preset~=animate-scale-up-down][data-vp-entry=down],[data-vp-preset~=animate-scale-up-down][data-vp-pos=below],[data-vp-preset~=animate-scale-up-up][data-vp-entry=up],[data-vp-preset~=animate-scale-up-up][data-vp-pos=above]{opacity:0;transform:scale(var(--viewport-scale-in));transition-property:opacity,transform}[data-vp-preset~=animate-scale-up][data-vp-in-view],[data-vp-preset~=animate-scale-up-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-scale-up-up][data-vp-entry=up][data-vp-in-view]{opacity:1;transform:scale(1)}[data-vp-preset~=animate-scale-down],[data-vp-preset~=animate-scale-down-down][data-vp-entry=down],[data-vp-preset~=animate-scale-down-down][data-vp-pos=below],[data-vp-preset~=animate-scale-down-up][data-vp-entry=up],[data-vp-preset~=animate-scale-down-up][data-vp-pos=above]{opacity:0;transform:scale(var(--viewport-scale-out));transition-property:opacity,transform}[data-vp-preset~=animate-scale-down][data-vp-in-view],[data-vp-preset~=animate-scale-down-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-scale-down-up][data-vp-entry=up][data-vp-in-view]{opacity:1;transform:scale(1)}[data-vp-preset~=animate-blur-in],[data-vp-preset~=animate-blur-in-down][data-vp-entry=down],[data-vp-preset~=animate-blur-in-down][data-vp-pos=below],[data-vp-preset~=animate-blur-in-up][data-vp-entry=up],[data-vp-preset~=animate-blur-in-up][data-vp-pos=above]{opacity:0;filter:blur(var(--viewport-blur));transition-property:opacity,filter}[data-vp-preset~=animate-blur-in][data-vp-in-view],[data-vp-preset~=animate-blur-in-down][data-vp-entry=down][data-vp-in-view],[data-vp-preset~=animate-blur-in-up][data-vp-entry=up][data-vp-in-view]{opacity:1;filter:blur(0)}[data-vp-preset~=animate-fade-y][data-vp-entry=down],[data-vp-preset~=animate-fade-y][data-vp-pos=below],[data-vp-preset~=animate-fade-y][data-vp-entry=up],[data-vp-preset~=animate-fade-y][data-vp-pos=above]{opacity:0;transition-property:opacity,transform}[data-vp-preset~=animate-fade-y][data-vp-entry=down],[data-vp-preset~=animate-fade-y][data-vp-pos=below]{transform:translateY(var(--viewport-distance))}[data-vp-preset~=animate-fade-y][data-vp-entry=up],[data-vp-preset~=animate-fade-y][data-vp-pos=above]{transform:translateY(calc(var(--viewport-distance) * -1))}[data-vp-preset~=animate-fade-y][data-vp-in-view]{opacity:1;transform:translateY(0)}[data-vp-preset~=animate-slide-y][data-vp-entry=down],[data-vp-preset~=animate-slide-y][data-vp-pos=below],[data-vp-preset~=animate-slide-y][data-vp-entry=up],[data-vp-preset~=animate-slide-y][data-vp-pos=above]{transition-property:transform}[data-vp-preset~=animate-slide-y][data-vp-entry=down],[data-vp-preset~=animate-slide-y][data-vp-pos=below]{transform:translateY(var(--viewport-distance))}[data-vp-preset~=animate-slide-y][data-vp-entry=up],[data-vp-preset~=animate-slide-y][data-vp-pos=above]{transform:translateY(calc(var(--viewport-distance) * -1))}[data-vp-preset~=animate-slide-y][data-vp-in-view]{transform:translateY(0)}@media(prefers-reduced-motion:reduce),print{[data-vp-mounted]{opacity:1!important;transform:none!important;transition:none!important;filter:none!important;animation:none!important;translate:none!important}}