svelte-aos 0.0.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.
package/README.md ADDED
@@ -0,0 +1,305 @@
1
+ # AOS Svelte
2
+
3
+ Animate On Scroll library for Svelte 5. Trigger CSS animations when elements scroll into view.
4
+
5
+ ## Quick Start
6
+
7
+ ```svelte
8
+ <script>
9
+ import { aosObserver } from 'svelte-aos';
10
+ import 'svelte-aos/styles/full.css';
11
+ </script>
12
+
13
+ <main {@attach aosObserver()}>
14
+ <div data-aos="fade-up">I animate when scrolled into view</div>
15
+ </main>
16
+ ```
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install svelte-aos
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### 1. Import Styles
27
+
28
+ ```js
29
+ // All animations
30
+ import 'svelte-aos/styles/full.css';
31
+
32
+ // Or selective (smaller bundle)
33
+ import 'svelte-aos/styles/base.css'; // Required
34
+ import 'svelte-aos/styles/fade.css'; // Optional
35
+ import 'svelte-aos/styles/zoom.css'; // Optional
36
+ import 'svelte-aos/styles/flip.css'; // Optional
37
+ import 'svelte-aos/styles/slide.css'; // Optional
38
+ import 'svelte-aos/styles/easings.css'; // Optional
39
+ ```
40
+
41
+ ### 2. Add Observer
42
+
43
+ **Svelte 5 attachment:**
44
+
45
+ ```svelte
46
+ <main {@attach aosObserver()}>
47
+ <!-- elements with data-aos will animate -->
48
+ </main>
49
+ ```
50
+
51
+ **Svelte action:**
52
+
53
+ ```svelte
54
+ <main use:aosAction>
55
+ <!-- elements with data-aos will animate -->
56
+ </main>
57
+ ```
58
+
59
+ ### 3. Add Animations
60
+
61
+ ```svelte
62
+ <div data-aos="fade-up">Fade up</div>
63
+ <div data-aos="zoom-in">Zoom in</div>
64
+ <div data-aos="flip-left">Flip left</div>
65
+ ```
66
+
67
+ Or use the `toAosAttributes` helper to generate attributes programmatically.
68
+
69
+ ```svelte
70
+ <script>
71
+ import { toAosAttributes } from 'svelte-aos';
72
+ const attrs = toAosAttributes({
73
+ animation: 'fade-up',
74
+ delay: 150,
75
+ duration: 400,
76
+ once: true
77
+ });
78
+ </script>
79
+
80
+ <div {...attrs}>Animated</div>
81
+ <!-- or inline -->
82
+ <div data-aos="fade-up" {...toAosAttributes({ delay: 150, duration: 400, once: true })}>
83
+ Animated
84
+ </div>
85
+ ```
86
+
87
+ ## Animations
88
+
89
+ ### Fade
90
+
91
+ ```text
92
+ fade fade-up fade-down fade-left fade-right
93
+ fade-up-left fade-up-right fade-down-left fade-down-right
94
+ ```
95
+
96
+ ### Zoom
97
+
98
+ ```text
99
+ zoom-in zoom-in-up zoom-in-down zoom-in-left zoom-in-right
100
+ zoom-out zoom-out-up zoom-out-down zoom-out-left zoom-out-right
101
+ ```
102
+
103
+ ### Flip
104
+
105
+ ```text
106
+ flip-up flip-down flip-left flip-right
107
+ ```
108
+
109
+ ### Slide
110
+
111
+ ```text
112
+ slide-up slide-down slide-left slide-right
113
+ ```
114
+
115
+ ## Per-Element Options
116
+
117
+ ```svelte
118
+ <!-- Duration (ms) -->
119
+ <div data-aos="fade" data-aos-duration="1000">Slow fade</div>
120
+
121
+ <!-- Delay (ms) -->
122
+ <div data-aos="fade" data-aos-delay="300">Delayed</div>
123
+
124
+ <!-- Easing -->
125
+ <div data-aos="fade" data-aos-easing="ease-out-back">Bouncy</div>
126
+
127
+ <!-- Animate only once -->
128
+ <div data-aos="fade" data-aos-once>Once only</div>
129
+ ```
130
+
131
+ ### Staggered Animation
132
+
133
+ ```svelte
134
+ <div data-aos="fade-up" data-aos-delay="0">First</div>
135
+ <div data-aos="fade-up" data-aos-delay="100">Second</div>
136
+ <div data-aos="fade-up" data-aos-delay="200">Third</div>
137
+ ```
138
+
139
+ ## Easings
140
+
141
+ ```text
142
+ linear ease ease-in ease-out ease-in-out
143
+ ease-in-back ease-out-back ease-in-out-back
144
+ ease-in-sine ease-out-sine ease-in-out-sine
145
+ ease-in-quad ease-out-quad ease-in-out-quad
146
+ ease-in-cubic ease-out-cubic ease-in-out-cubic
147
+ ease-in-quart ease-out-quart ease-in-out-quart
148
+ ```
149
+
150
+ ## Global Options
151
+
152
+ ```svelte
153
+ <main {@attach aosObserver({
154
+ threshold: 0.1, // 0-1, visibility ratio to trigger
155
+ offset: 120, // px from viewport edge
156
+ duration: 600, // default duration (ms)
157
+ delay: 0, // default delay (ms)
158
+ easing: 'ease', // default easing
159
+ once: false, // animate only once
160
+ disable: false, // disable all animations
161
+ anchorPlacement: 'top-bottom'
162
+ })}>
163
+ ```
164
+
165
+ ### Disable Option
166
+
167
+ ```js
168
+ // Disable on device type
169
+ aosObserver({ disable: 'mobile' }); // 'mobile' | 'tablet' | 'desktop'
170
+
171
+ // Disable entirely
172
+ aosObserver({ disable: true });
173
+
174
+ // Custom condition
175
+ aosObserver({ disable: () => window.innerWidth < 768 });
176
+ ```
177
+
178
+ ## API
179
+
180
+ ### aosObserver(options?)
181
+
182
+ Svelte 5 attachment. Observes all `[data-aos]` elements inside the container, this is where all the magic happens, it uses a mutation observer and an intersection observer under the hood.
183
+
184
+ ```svelte
185
+ <main {@attach aosObserver({ once: true })}>
186
+ <div data-aos="fade">...</div>
187
+ </main>
188
+ ```
189
+
190
+ ### aosAction
191
+
192
+ Svelte action (use: directive). Same options as `aosObserver`.
193
+
194
+ ```svelte
195
+ <main use:aosAction={{ threshold: 0.2 }}>
196
+ <div data-aos="fade">...</div>
197
+ </main>
198
+ ```
199
+
200
+ ### toAosAttributes(options)
201
+
202
+ Generate attributes programmatically:
203
+
204
+ ```svelte
205
+ <script>
206
+ import { toAosAttributes } from 'svelte-aos';
207
+
208
+ const attrs = toAosAttributes({
209
+ animation: 'fade-up',
210
+ delay: 150,
211
+ duration: 400,
212
+ once: true
213
+ });
214
+ </script>
215
+
216
+ <div {...attrs}>Animated</div>
217
+
218
+ <!-- Equivalent to: -->
219
+ <div data-aos="fade-up" data-aos-delay="150" data-aos-duration="400" data-aos-once>
220
+ ```
221
+
222
+ ## CSS Files
223
+
224
+ | File | Contents |
225
+ | ------------- | ---------------------------------------- |
226
+ | `base.css` | Core setup, CSS variables (**required**) |
227
+ | `fade.css` | Fade animations |
228
+ | `zoom.css` | Zoom animations |
229
+ | `flip.css` | Flip animations |
230
+ | `slide.css` | Slide animations |
231
+ | `easings.css` | Custom easing functions |
232
+ | `full.css` | All of the above |
233
+
234
+ ## Examples
235
+
236
+ ### Basic Page
237
+
238
+ ```svelte
239
+ <script>
240
+ import { aosObserver } from 'svelte-aos';
241
+ import 'svelte-aos/styles/full.css';
242
+ </script>
243
+
244
+ <main {@attach aosObserver()}>
245
+ <section>
246
+ <h1 data-aos="fade-down">Welcome</h1>
247
+ <p data-aos="fade-up" data-aos-delay="100">Scroll to see more</p>
248
+ </section>
249
+
250
+ <section>
251
+ <div data-aos="fade-right">Card 1</div>
252
+ <div data-aos="fade-right" data-aos-delay="100">Card 2</div>
253
+ <div data-aos="fade-right" data-aos-delay="200">Card 3</div>
254
+ </section>
255
+ </main>
256
+ ```
257
+
258
+ ### Animate Once
259
+
260
+ ```svelte
261
+ <main {@attach aosObserver({ once: true })}>
262
+ <div data-aos="zoom-in">Animates once, stays visible</div>
263
+ </main>
264
+ ```
265
+
266
+ ### With Dynamic Content
267
+
268
+ ```svelte
269
+ <script>
270
+ import { aosObserver } from 'svelte-aos';
271
+ import 'svelte-aos/styles/full.css';
272
+
273
+ let items = $state([]);
274
+
275
+ async function loadMore() {
276
+ items = [...items, ...(await fetchItems())];
277
+ }
278
+ </script>
279
+
280
+ <!-- MutationObserver auto-detects new [data-aos] elements -->
281
+ <main {@attach aosObserver()}>
282
+ {#each items as item, i}
283
+ <div data-aos="fade-up" data-aos-delay={i * 50}>{item.name}</div>
284
+ {/each}
285
+ <button onclick={loadMore}>Load More</button>
286
+ </main>
287
+ ```
288
+
289
+ ### Minimal Bundle (Fade Only)
290
+
291
+ ```svelte
292
+ <script>
293
+ import { aosObserver } from 'svelte-aos';
294
+ import 'svelte-aos/styles/base.css';
295
+ import 'svelte-aos/styles/fade.css';
296
+ </script>
297
+
298
+ <main {@attach aosObserver()}>
299
+ <div data-aos="fade-up">Only fade animations available</div>
300
+ </main>
301
+ ```
302
+
303
+ ## License
304
+
305
+ MIT
package/dist/aos.d.ts ADDED
@@ -0,0 +1,70 @@
1
+ import type { AnimationType, DisableOption, EasingType, AnchorPlacement } from './types.ts';
2
+ /**
3
+ * Create a Svelte attacheemnt that observes elements with `data-aos` and toggles
4
+ * animation classes when they intersect the viewport.
5
+ *
6
+ * The attachement will:
7
+ * - Apply per-element CSS variables (duration/delay) from `data-aos-*` attributes
8
+ * or from the `params` defaults.
9
+ * - Add the `.aos-animate` class when the element meets the `threshold`/`rootMargin` criteria.
10
+ * - Remove `.aos-animate` on exit unless `once` is true (or element has `data-aos-once="true").
11
+ * - If `once` is true, the element will be unobserved after its first entry.
12
+ * - Applies `params.easing` to elements that do not have `data-aos-easing` set.
13
+ *
14
+ * @param {Object} [params] - Global observer and animation options.
15
+ */
16
+ export declare function aosObserver(params?: {
17
+ duration?: number;
18
+ threshold?: number;
19
+ delay?: number;
20
+ once?: boolean;
21
+ disable?: DisableOption;
22
+ anchorPlacement?: AnchorPlacement;
23
+ offset?: number;
24
+ easing?: EasingType;
25
+ }): (node: HTMLElement) => () => void;
26
+ /**
27
+ * This is to use if attachements are not available in your svelte setup.
28
+ * @param node - HTML element to attach AOS behavior to
29
+ *
30
+ * @param params - AOS options
31
+ * @returns
32
+ */
33
+ export declare function aosAction(node: HTMLElement, params?: {
34
+ duration?: number;
35
+ threshold?: number;
36
+ delay?: number;
37
+ once?: boolean;
38
+ disable?: DisableOption;
39
+ anchorPlacement?: AnchorPlacement;
40
+ offset?: number;
41
+ easing?: EasingType;
42
+ }): {
43
+ update: () => void;
44
+ destroy(): void;
45
+ };
46
+ /**
47
+ * Convert a small configuration object into a map of `data-aos-*` attributes.
48
+ *
49
+ * Useful for demos or programmatically attaching attributes to an element (e.g. in Svelte
50
+ * you can spread the returned object with `{...toAosAttributes({...})}`).
51
+ *
52
+ * @param {Object} options - Per-element options
53
+ * @param {number} [options.delay] - Delay in ms
54
+ * @param {number} [options.duration] - Duration in ms
55
+ * @param {EasingType} [options.easing] - Easing name
56
+ * @param {AnimationType} [options.animation] - Animation name
57
+ * @param {boolean} [options.once] - If true, set `data-aos-once` on the element
58
+ * @returns {Record<string,string>} Map of attributes (keys are attribute names, values are strings)
59
+ *
60
+ * @example
61
+ * const attrs = toAosAttributes({ animation: 'fade-up', delay: 150, duration: 400 });
62
+ * // => { 'data-aos': 'fade-up', 'data-aos-delay': '150', 'data-aos-duration': '400' }
63
+ */
64
+ export declare function toAosAttributes(options: {
65
+ delay?: number;
66
+ duration?: number;
67
+ easing?: EasingType;
68
+ animation?: AnimationType;
69
+ once?: boolean;
70
+ }): Record<string, string>;
package/dist/aos.js ADDED
@@ -0,0 +1,214 @@
1
+ // import './styles.css';
2
+ // TODO: Improve this device detection logic
3
+ function detectDeviceType() {
4
+ if (typeof navigator === 'undefined')
5
+ return 'desktop';
6
+ const ua = navigator.userAgent;
7
+ if (/Mobi|Android/i.test(ua)) {
8
+ return 'mobile';
9
+ }
10
+ else if (/Tablet|iPad/i.test(ua)) {
11
+ return 'tablet';
12
+ }
13
+ else {
14
+ return 'desktop';
15
+ }
16
+ }
17
+ const computeRootMargin = (anchorPlacement, offset = 0) => {
18
+ // simple handling for common placements; expand if needed
19
+ if (anchorPlacement === 'top-bottom') {
20
+ return `0px 0px -${offset}px 0px`; // trigger when element top hits viewport bottom - offset
21
+ }
22
+ if (anchorPlacement === 'bottom-top') {
23
+ return `-${offset}px 0px 0px 0px`;
24
+ }
25
+ if (anchorPlacement === 'center-center') {
26
+ return `-50% 0px -50% 0px`;
27
+ }
28
+ return `0px 0px 0px 0px`;
29
+ };
30
+ const defaultOptions = {
31
+ delay: 0,
32
+ easing: 'ease',
33
+ duration: 600,
34
+ disable: 'mobile',
35
+ once: false,
36
+ anchorPlacement: 'top-bottom',
37
+ offset: 120,
38
+ threshold: 0.1
39
+ // TODO: implement these later
40
+ // animatedClassName: 'aos-animate',
41
+ // initClassName?: 'aos-init',
42
+ // useClassNames: false,
43
+ // disableMutationObserver: false
44
+ };
45
+ function setipObserver(params, node) {
46
+ if (params?.duration) {
47
+ node.style.setProperty('--aos-duration', `${params.duration}ms`);
48
+ }
49
+ // handle disable option
50
+ if (typeof params?.disable === 'boolean' && params.disable) {
51
+ node.classList.add('aos-disabled');
52
+ }
53
+ else if (typeof params?.disable === 'string') {
54
+ const deviceType = detectDeviceType();
55
+ if (params.disable === deviceType) {
56
+ node.classList.add('aos-disabled');
57
+ }
58
+ }
59
+ else if (typeof params?.disable === 'function') {
60
+ if (params.disable()) {
61
+ node.classList.add('aos-disabled');
62
+ }
63
+ }
64
+ if (params?.delay) {
65
+ node.style.setProperty('--aos-delay', `${params.delay}ms`);
66
+ }
67
+ const io = new IntersectionObserver((entries) => {
68
+ entries.forEach((entry) => {
69
+ if (entry.isIntersecting && entry.intersectionRatio > 0.05) {
70
+ // handle intersection
71
+ entry.target.classList.add('aos-animate');
72
+ if (params?.once) {
73
+ // why keep observing if we only want once?
74
+ io.unobserve(entry.target);
75
+ }
76
+ }
77
+ else {
78
+ const once = entry.target.hasAttribute('data-aos-once') || params?.once;
79
+ if (!once) {
80
+ entry.target.classList.remove('aos-animate');
81
+ }
82
+ }
83
+ });
84
+ }, {
85
+ threshold: params?.threshold ?? 0.1,
86
+ rootMargin: computeRootMargin(params?.anchorPlacement ?? 'top-bottom', params?.offset ?? 0)
87
+ });
88
+ const observeNode = (el) => {
89
+ if (!el.classList.contains('aos-animate')) {
90
+ // set al lthe custom css variable and values here we do not to do that on intersection
91
+ const dataDuration = el.getAttribute('data-aos-duration') || params?.duration;
92
+ if (dataDuration) {
93
+ el.style.setProperty('--aos-duration', `${dataDuration}ms`);
94
+ }
95
+ const dataDelay = el.getAttribute('data-aos-delay') || params?.delay;
96
+ if (dataDelay) {
97
+ el.style.setProperty('--aos-delay', `${dataDelay}ms`);
98
+ }
99
+ const easing = el.getAttribute('data-aos-easing');
100
+ if (!easing && params?.easing) {
101
+ el.setAttribute('data-aos-easing', params.easing);
102
+ }
103
+ io.observe(el);
104
+ }
105
+ };
106
+ // Observe all existing [data-aos] elements
107
+ node.querySelectorAll('[data-aos]').forEach(observeNode);
108
+ // Watch for new elements or attribute changes
109
+ const mo = new MutationObserver((mutations) => {
110
+ mutations.forEach((m) => {
111
+ // New nodes
112
+ m.addedNodes.forEach((n) => {
113
+ if (n.nodeType === 1) {
114
+ const el = n;
115
+ if (el.matches('[data-aos]'))
116
+ observeNode(el);
117
+ el.querySelectorAll('[data-aos]').forEach(observeNode);
118
+ }
119
+ });
120
+ // Attribute changes
121
+ if (m.type === 'attributes' && m.attributeName === 'data-aos') {
122
+ const target = m.target;
123
+ observeNode(target);
124
+ }
125
+ });
126
+ });
127
+ mo.observe(node, {
128
+ childList: true,
129
+ subtree: true,
130
+ // attributes: true,
131
+ attributeFilter: ['data-aos']
132
+ });
133
+ return { io, mo };
134
+ }
135
+ /**
136
+ * Create a Svelte attacheemnt that observes elements with `data-aos` and toggles
137
+ * animation classes when they intersect the viewport.
138
+ *
139
+ * The attachement will:
140
+ * - Apply per-element CSS variables (duration/delay) from `data-aos-*` attributes
141
+ * or from the `params` defaults.
142
+ * - Add the `.aos-animate` class when the element meets the `threshold`/`rootMargin` criteria.
143
+ * - Remove `.aos-animate` on exit unless `once` is true (or element has `data-aos-once="true").
144
+ * - If `once` is true, the element will be unobserved after its first entry.
145
+ * - Applies `params.easing` to elements that do not have `data-aos-easing` set.
146
+ *
147
+ * @param {Object} [params] - Global observer and animation options.
148
+ */
149
+ export function aosObserver(params) {
150
+ params = { ...defaultOptions, ...params };
151
+ return function (node) {
152
+ const { io, mo } = setipObserver(params, node);
153
+ return () => {
154
+ io.disconnect();
155
+ mo.disconnect();
156
+ };
157
+ };
158
+ }
159
+ /**
160
+ * This is to use if attachements are not available in your svelte setup.
161
+ * @param node - HTML element to attach AOS behavior to
162
+ *
163
+ * @param params - AOS options
164
+ * @returns
165
+ */
166
+ export function aosAction(node, params) {
167
+ params = { ...defaultOptions, ...params };
168
+ const { io, mo } = setipObserver(params, node);
169
+ return {
170
+ update: () => {
171
+ // NOTHING
172
+ },
173
+ destroy() {
174
+ console.log('AOS Action destroyed for node:', node);
175
+ io.disconnect();
176
+ mo.disconnect();
177
+ }
178
+ };
179
+ }
180
+ /**
181
+ * Convert a small configuration object into a map of `data-aos-*` attributes.
182
+ *
183
+ * Useful for demos or programmatically attaching attributes to an element (e.g. in Svelte
184
+ * you can spread the returned object with `{...toAosAttributes({...})}`).
185
+ *
186
+ * @param {Object} options - Per-element options
187
+ * @param {number} [options.delay] - Delay in ms
188
+ * @param {number} [options.duration] - Duration in ms
189
+ * @param {EasingType} [options.easing] - Easing name
190
+ * @param {AnimationType} [options.animation] - Animation name
191
+ * @param {boolean} [options.once] - If true, set `data-aos-once` on the element
192
+ * @returns {Record<string,string>} Map of attributes (keys are attribute names, values are strings)
193
+ *
194
+ * @example
195
+ * const attrs = toAosAttributes({ animation: 'fade-up', delay: 150, duration: 400 });
196
+ * // => { 'data-aos': 'fade-up', 'data-aos-delay': '150', 'data-aos-duration': '400' }
197
+ */
198
+ export function toAosAttributes(options) {
199
+ const attrs = {};
200
+ if (options.delay !== undefined) {
201
+ attrs['data-aos-delay'] = options.delay.toString();
202
+ }
203
+ if (options.duration !== undefined) {
204
+ attrs['data-aos-duration'] = options.duration.toString();
205
+ }
206
+ if (options.easing !== undefined) {
207
+ attrs['data-aos-easing'] = options.easing;
208
+ }
209
+ if (options.once) {
210
+ attrs['data-aos-once'] = '';
211
+ }
212
+ attrs['data-aos'] = options.animation ?? 'fade';
213
+ return attrs;
214
+ }
@@ -0,0 +1,2 @@
1
+ export { aosObserver, aosAction, toAosAttributes } from './aos.ts';
2
+ export type { AOSOptions, AnimationType, EasingType } from './types.ts';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // Reexport your entry components here
2
+ export { aosObserver, aosAction, toAosAttributes } from "./aos.js";
@@ -0,0 +1,45 @@
1
+ /*
2
+ AOS Base Styles
3
+ Core transition setup for all AOS animations
4
+ Required: Always import this file
5
+ */
6
+
7
+ @media screen {
8
+ html:not(.no-js) {
9
+ :not(.aos-disabled) {
10
+ /* CSS Custom Properties (defaults) */
11
+ --aos-duration: 600ms;
12
+ --aos-delay: 50ms;
13
+ --aos-distance: 100px;
14
+
15
+ /* Base transition for all [data-aos] elements */
16
+ [data-aos] {
17
+ transition-duration: var(--aos-duration);
18
+ transition-delay: var(--aos-delay);
19
+ transition-timing-function: ease;
20
+ }
21
+
22
+ /* Default animated state */
23
+ [data-aos].aos-animate {
24
+ transform: translate3d(0, 0, 0) scale(1) rotate(0);
25
+ }
26
+
27
+ /* Reduced motion support */
28
+ @media (prefers-reduced-motion: reduce) {
29
+ [data-aos] {
30
+ opacity: 1 !important;
31
+ transform: none !important;
32
+ transition: none !important;
33
+ }
34
+ }
35
+
36
+ /* Disabled state */
37
+ [data-aos-disabled] [data-aos],
38
+ [data-aos][data-aos-disabled] {
39
+ opacity: 1 !important;
40
+ transform: none !important;
41
+ transition: none !important;
42
+ }
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,97 @@
1
+ /*
2
+ AOS Easing Functions
3
+ Custom easing curves for animations
4
+ Requires: base.css
5
+ */
6
+
7
+ @media screen {
8
+ html:not(.no-js) {
9
+ :not(.aos-disabled) {
10
+ /* Standard easings */
11
+ [data-aos][data-aos-easing='linear'] {
12
+ transition-timing-function: linear;
13
+ }
14
+
15
+ [data-aos][data-aos-easing='ease'] {
16
+ transition-timing-function: ease;
17
+ }
18
+
19
+ [data-aos][data-aos-easing='ease-in'] {
20
+ transition-timing-function: ease-in;
21
+ }
22
+
23
+ [data-aos][data-aos-easing='ease-out'] {
24
+ transition-timing-function: ease-out;
25
+ }
26
+
27
+ [data-aos][data-aos-easing='ease-in-out'] {
28
+ transition-timing-function: ease-in-out;
29
+ }
30
+
31
+ /* Back easings (overshoot) */
32
+ [data-aos][data-aos-easing='ease-in-back'] {
33
+ transition-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
34
+ }
35
+
36
+ [data-aos][data-aos-easing='ease-out-back'] {
37
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
38
+ }
39
+
40
+ [data-aos][data-aos-easing='ease-in-out-back'] {
41
+ transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
42
+ }
43
+
44
+ /* Sine easings (smooth) */
45
+ [data-aos][data-aos-easing='ease-in-sine'] {
46
+ transition-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715);
47
+ }
48
+
49
+ [data-aos][data-aos-easing='ease-out-sine'] {
50
+ transition-timing-function: cubic-bezier(0.39, 0.575, 0.565, 1);
51
+ }
52
+
53
+ [data-aos][data-aos-easing='ease-in-out-sine'] {
54
+ transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
55
+ }
56
+
57
+ /* Quad easings (moderate acceleration) */
58
+ [data-aos][data-aos-easing='ease-in-quad'] {
59
+ transition-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53);
60
+ }
61
+
62
+ [data-aos][data-aos-easing='ease-out-quad'] {
63
+ transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
64
+ }
65
+
66
+ [data-aos][data-aos-easing='ease-in-out-quad'] {
67
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
68
+ }
69
+
70
+ /* Cubic easings (stronger acceleration) */
71
+ [data-aos][data-aos-easing='ease-in-cubic'] {
72
+ transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
73
+ }
74
+
75
+ [data-aos][data-aos-easing='ease-out-cubic'] {
76
+ transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
77
+ }
78
+
79
+ [data-aos][data-aos-easing='ease-in-out-cubic'] {
80
+ transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1);
81
+ }
82
+
83
+ /* Quart easings (aggressive acceleration) */
84
+ [data-aos][data-aos-easing='ease-in-quart'] {
85
+ transition-timing-function: cubic-bezier(0.895, 0.03, 0.685, 0.22);
86
+ }
87
+
88
+ [data-aos][data-aos-easing='ease-out-quart'] {
89
+ transition-timing-function: cubic-bezier(0.165, 0.84, 0.44, 1);
90
+ }
91
+
92
+ [data-aos][data-aos-easing='ease-in-out-quart'] {
93
+ transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
94
+ }
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,61 @@
1
+ /*
2
+ AOS Fade Animations
3
+ fade, fade-up, fade-down, fade-left, fade-right, and diagonal variants
4
+ Requires: base.css
5
+ */
6
+
7
+ @media screen {
8
+ html:not(.no-js) {
9
+ :not(.aos-disabled) {
10
+ /* Base for all fade animations */
11
+ [data-aos^='fade'][data-aos^='fade'] {
12
+ opacity: 0;
13
+ transition-property: opacity, transform;
14
+
15
+ &.aos-animate {
16
+ opacity: 1;
17
+ transform: none;
18
+ }
19
+ }
20
+
21
+ /* Simple fade (no movement) */
22
+ [data-aos='fade'] {
23
+ transform: translate3d(0, 0, 0);
24
+ }
25
+
26
+ /* Directional fades */
27
+ [data-aos='fade-up'] {
28
+ transform: translate3d(0, var(--aos-distance), 0);
29
+ }
30
+
31
+ [data-aos='fade-down'] {
32
+ transform: translate3d(0, calc(-1 * var(--aos-distance)), 0);
33
+ }
34
+
35
+ [data-aos='fade-left'] {
36
+ transform: translate3d(var(--aos-distance), 0, 0);
37
+ }
38
+
39
+ [data-aos='fade-right'] {
40
+ transform: translate3d(calc(-1 * var(--aos-distance)), 0, 0);
41
+ }
42
+
43
+ /* Diagonal fades */
44
+ [data-aos='fade-up-left'] {
45
+ transform: translate3d(var(--aos-distance), var(--aos-distance), 0);
46
+ }
47
+
48
+ [data-aos='fade-up-right'] {
49
+ transform: translate3d(calc(-1 * var(--aos-distance)), var(--aos-distance), 0);
50
+ }
51
+
52
+ [data-aos='fade-down-left'] {
53
+ transform: translate3d(var(--aos-distance), calc(-1 * var(--aos-distance)), 0);
54
+ }
55
+
56
+ [data-aos='fade-down-right'] {
57
+ transform: translate3d(calc(-1 * var(--aos-distance)), calc(-1 * var(--aos-distance)), 0);
58
+ }
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,38 @@
1
+ /*
2
+ AOS Flip Animations
3
+ 3D flip effects in all directions
4
+ Requires: base.css
5
+ */
6
+
7
+ @media screen {
8
+ html:not(.no-js) {
9
+ :not(.aos-disabled) {
10
+ /* Base for all flip animations */
11
+ [data-aos^='flip'][data-aos^='flip'] {
12
+ backface-visibility: hidden;
13
+ transition-property: transform;
14
+
15
+ &.aos-animate {
16
+ transform: perspective(2500px) rotateX(0) rotateY(0);
17
+ }
18
+ }
19
+
20
+ /* Flip directions */
21
+ [data-aos='flip-up'] {
22
+ transform: perspective(2500px) rotateX(-100deg);
23
+ }
24
+
25
+ [data-aos='flip-down'] {
26
+ transform: perspective(2500px) rotateX(100deg);
27
+ }
28
+
29
+ [data-aos='flip-left'] {
30
+ transform: perspective(2500px) rotateY(-100deg);
31
+ }
32
+
33
+ [data-aos='flip-right'] {
34
+ transform: perspective(2500px) rotateY(100deg);
35
+ }
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ AOS All Styles
3
+ Import this file for all animations, or import individual files for tree-shaking.
4
+
5
+ Usage:
6
+ // All animations
7
+ import 'svelte-aos/styles';
8
+
9
+ // Or selective imports
10
+ import 'svelte-aos/styles/base.css'; // Required
11
+ import 'svelte-aos/styles/fade.css'; // Optional
12
+ import 'svelte-aos/styles/zoom.css'; // Optional
13
+ import 'svelte-aos/styles/flip.css'; // Optional
14
+ import 'svelte-aos/styles/slide.css'; // Optional
15
+ import 'svelte-aos/styles/easings.css'; // Optional (for custom easings)
16
+ */
17
+
18
+ @import './base.css';
19
+ @import './fade.css';
20
+ @import './zoom.css';
21
+ @import './flip.css';
22
+ @import './slide.css';
23
+ @import './easings.css';
@@ -0,0 +1,39 @@
1
+ /*
2
+ AOS Slide Animations
3
+ Slide in from edges (no opacity change, uses visibility)
4
+ Requires: base.css
5
+ */
6
+
7
+ @media screen {
8
+ html:not(.no-js) {
9
+ :not(.aos-disabled) {
10
+ /* Base for all slide animations */
11
+ [data-aos^='slide'][data-aos^='slide'] {
12
+ transition-property: transform;
13
+ visibility: hidden;
14
+
15
+ &.aos-animate {
16
+ visibility: visible;
17
+ transform: translate3d(0, 0, 0);
18
+ }
19
+ }
20
+
21
+ /* Slide directions */
22
+ [data-aos='slide-up'] {
23
+ transform: translate3d(0, 100%, 0);
24
+ }
25
+
26
+ [data-aos='slide-down'] {
27
+ transform: translate3d(0, -100%, 0);
28
+ }
29
+
30
+ [data-aos='slide-left'] {
31
+ transform: translate3d(100%, 0, 0);
32
+ }
33
+
34
+ [data-aos='slide-right'] {
35
+ transform: translate3d(-100%, 0, 0);
36
+ }
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,64 @@
1
+ /*
2
+ AOS Zoom Animations
3
+ zoom-in, zoom-out, and directional variants
4
+ Requires: base.css
5
+ */
6
+
7
+ @media screen {
8
+ html:not(.no-js) {
9
+ :not(.aos-disabled) {
10
+ /* Base for all zoom animations */
11
+ [data-aos^='zoom'][data-aos^='zoom'] {
12
+ opacity: 0;
13
+ transition-property: opacity, transform;
14
+
15
+ &.aos-animate {
16
+ opacity: 1;
17
+ transform: translate3d(0, 0, 0) scale(1);
18
+ }
19
+ }
20
+
21
+ /* Zoom In */
22
+ [data-aos='zoom-in'] {
23
+ transform: scale(0.6);
24
+ }
25
+
26
+ [data-aos='zoom-in-up'] {
27
+ transform: translate3d(0, var(--aos-distance), 0) scale(0.6);
28
+ }
29
+
30
+ [data-aos='zoom-in-down'] {
31
+ transform: translate3d(0, calc(-1 * var(--aos-distance)), 0) scale(0.6);
32
+ }
33
+
34
+ [data-aos='zoom-in-left'] {
35
+ transform: translate3d(var(--aos-distance), 0, 0) scale(0.6);
36
+ }
37
+
38
+ [data-aos='zoom-in-right'] {
39
+ transform: translate3d(calc(-1 * var(--aos-distance)), 0, 0) scale(0.6);
40
+ }
41
+
42
+ /* Zoom Out */
43
+ [data-aos='zoom-out'] {
44
+ transform: scale(1.2);
45
+ }
46
+
47
+ [data-aos='zoom-out-up'] {
48
+ transform: translate3d(0, var(--aos-distance), 0) scale(1.2);
49
+ }
50
+
51
+ [data-aos='zoom-out-down'] {
52
+ transform: translate3d(0, calc(-1 * var(--aos-distance)), 0) scale(1.2);
53
+ }
54
+
55
+ [data-aos='zoom-out-left'] {
56
+ transform: translate3d(var(--aos-distance), 0, 0) scale(1.2);
57
+ }
58
+
59
+ [data-aos='zoom-out-right'] {
60
+ transform: translate3d(calc(-1 * var(--aos-distance)), 0, 0) scale(1.2);
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,21 @@
1
+ export type AnchorPlacement = 'top-bottom' | 'top-center' | 'top-top' | 'center-bottom' | 'center-center' | 'center-top' | 'bottom-bottom' | 'bottom-center' | 'bottom-top';
2
+ export type AnimationType = 'fade' | 'fade-up' | 'fade-down' | 'fade-left' | 'fade-right' | 'fade-up-left' | 'fade-up-right' | 'fade-down-left' | 'fade-down-right' | 'zoom-in' | 'zoom-in-up' | 'zoom-in-down' | 'zoom-in-left' | 'zoom-in-right' | 'zoom-out' | 'zoom-out-up' | 'zoom-out-down' | 'zoom-out-left' | 'zoom-out-right' | 'flip-up' | 'flip-down' | 'flip-left' | 'flip-right' | 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right';
3
+ export type EasingType = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'ease-in-back' | 'ease-out-back' | 'ease-in-out-back' | 'ease-in-sine' | 'ease-out-sine' | 'ease-in-out-sine' | 'ease-in-quad' | 'ease-out-quad' | 'ease-in-out-quad' | 'ease-in-cubic' | 'ease-out-cubic' | 'ease-in-out-cubic' | 'ease-in-quart' | 'ease-out-quart' | 'ease-in-out-quart';
4
+ export type DisableOption = boolean | 'mobile' | 'phone' | 'tablet' | (() => boolean);
5
+ export interface AOSOptions {
6
+ /** Offset (in px) from the original trigger point */
7
+ offset?: number;
8
+ /** Values from 0 to 3000, with step 50ms */
9
+ delay?: number;
10
+ /** Duration of animation (accepts values from 0 to 3000, with step 50ms) */
11
+ duration?: number;
12
+ /** Easing for AOS animations */
13
+ easing?: EasingType;
14
+ /** Whether animation should happen only once - while scrolling down */
15
+ once?: boolean;
16
+ /** Defines which position of the element regarding to window should trigger the animation */
17
+ anchorPlacement?: AnchorPlacement;
18
+ /** Condition when AOS should be disabled */
19
+ disable?: DisableOption;
20
+ threshold?: number;
21
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "svelte-aos",
3
+ "version": "0.0.1",
4
+ "files": [
5
+ "dist",
6
+ "!dist/**/*.test.*",
7
+ "!dist/**/*.spec.*"
8
+ ],
9
+ "sideEffects": [
10
+ "**/*.css"
11
+ ],
12
+ "svelte": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "type": "module",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "svelte": "./dist/index.js"
19
+ },
20
+ "./styles/base.css": {
21
+ "svelte": "./dist/styles/base.css"
22
+ },
23
+ "./styles/easings.css": {
24
+ "svelte": "./dist/styles/easings.css"
25
+ },
26
+ "./styles/fade.css": {
27
+ "svelte": "./dist/styles/fade.css"
28
+ },
29
+ "./styles/flip.css": {
30
+ "svelte": "./dist/styles/flip.css"
31
+ },
32
+ "./styles/full.css": {
33
+ "svelte": "./dist/styles/full.css"
34
+ },
35
+ "./styles/slide.css": {
36
+ "svelte": "./dist/styles/slide.css"
37
+ },
38
+ "./styles/zoom.css": {
39
+ "svelte": "./dist/styles/zoom.css"
40
+ }
41
+ },
42
+ "peerDependencies": {
43
+ "svelte": "^4.0.0 || ^5.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "@eslint/compat": "^1.4.0",
47
+ "@eslint/js": "^9.39.1",
48
+ "@sveltejs/adapter-auto": "^7.0.0",
49
+ "@sveltejs/kit": "^2.49.1",
50
+ "@sveltejs/package": "^2.5.7",
51
+ "@sveltejs/vite-plugin-svelte": "^6.2.1",
52
+ "@types/node": "^22",
53
+ "@vitest/browser-playwright": "^4.0.15",
54
+ "eslint": "^9.39.1",
55
+ "eslint-config-prettier": "^10.1.8",
56
+ "eslint-plugin-svelte": "^3.13.1",
57
+ "globals": "^16.5.0",
58
+ "husky": "^9.1.7",
59
+ "lint-staged": "^16.2.7",
60
+ "playwright": "^1.57.0",
61
+ "prettier": "^3.7.4",
62
+ "prettier-plugin-svelte": "^3.4.0",
63
+ "publint": "^0.3.15",
64
+ "svelte": "^5.45.6",
65
+ "svelte-check": "^4.3.4",
66
+ "typescript": "^5.9.3",
67
+ "typescript-eslint": "^8.48.1",
68
+ "vite": "^7.2.6",
69
+ "vite-plugin-devtools-json": "^1.0.0",
70
+ "vitest": "^4.0.15",
71
+ "vitest-browser-svelte": "^2.0.1"
72
+ },
73
+ "keywords": [
74
+ "svelte"
75
+ ],
76
+ "lint-staged": {
77
+ "*.{js,ts,svelte,css,md,json}": "prettier --write"
78
+ },
79
+ "scripts": {
80
+ "dev": "vite dev",
81
+ "build": "vite build && npm run prepack",
82
+ "preview": "vite preview",
83
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
84
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
85
+ "format": "prettier --write .",
86
+ "lint": "prettier --check . && eslint .",
87
+ "test:unit": "vitest",
88
+ "test": "npm run test:unit -- --run"
89
+ }
90
+ }