Full Code of michalsnik/aos for AI

next 329fb34f7770 cached
57 files
79.1 KB
25.3k tokens
11 symbols
1 requests
Download .txt
Repository: michalsnik/aos
Branch: next
Commit: 329fb34f7770
Files: 57
Total size: 79.1 KB

Directory structure:
gitextract_zh9g82gd/

├── .babelrc
├── .editorconfig
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .npmignore
├── .travis.yml
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── cypress/
│   ├── integration/
│   │   ├── aos_spec.js
│   │   ├── js_events_spec.js
│   │   ├── mutation_spec.js
│   │   ├── settings_anchorPlacement_spec.js
│   │   ├── settings_anchor_spec.js
│   │   ├── settings_animatedClassName_spec.js
│   │   ├── settings_delay_spec.js
│   │   ├── settings_disableMutationObserver_spec.js
│   │   ├── settings_disable_spec.js
│   │   ├── settings_duration_spec.js
│   │   ├── settings_easing_spec.js
│   │   ├── settings_initClassName_spec.js
│   │   ├── settings_mirror.js
│   │   ├── settings_offset_spec.js
│   │   ├── settings_once_spec.js
│   │   ├── settings_startEvent_spec.js
│   │   └── settings_useClassNames.js
│   ├── plugins/
│   │   └── index.js
│   └── support/
│       ├── commands.js
│       └── index.js
├── cypress.json
├── demo/
│   ├── anchor.html
│   ├── animatecss.html
│   ├── async.html
│   ├── css/
│   │   └── styles.css
│   ├── index.html
│   ├── offset.html
│   └── once.html
├── package.json
├── rollup.config.js
├── scripts/
│   ├── run-cypress-tests.js
│   └── start-server.js
└── src/
    ├── js/
    │   ├── aos.js
    │   ├── helpers/
    │   │   ├── detector.js
    │   │   ├── elements.js
    │   │   ├── getInlineOption.js
    │   │   ├── handleScroll.js
    │   │   ├── offsetCalculator.js
    │   │   └── prepare.js
    │   └── libs/
    │       ├── observer.js
    │       └── offset.js
    └── sass/
        ├── _animations.scss
        ├── _core.scss
        ├── _easing.scss
        └── aos.scss

================================================
FILE CONTENTS
================================================

================================================
FILE: .babelrc
================================================
{
  "presets": [
    ["env", {
      "modules": false
    }]
  ],
  "plugins": [
    "transform-object-assign",
    "external-helpers"
  ]
}


================================================
FILE: .editorconfig
================================================
# editorconfig.org

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false


================================================
FILE: .eslintrc.json
================================================
{
  "env": {
    "browser": true,
    "es6": true
  },
  "parser": "babel-eslint",
  "extends": [
    "plugin:prettier/recommended"
  ],
  "rules": {
    "prettier/prettier": [2, {
      "singleQuote": true
    }]
  }
}


================================================
FILE: .gitattributes
================================================
# Enforce Unix newlines
*.css   text eol=lf
*.scss  text eol=lf
*.html  text eol=lf
*.js    text eol=lf
*.md    text eol=lf
*.svg   text eol=lf
*.yml   text eol=lf
# Don't diff or textually merge source maps
*.map   binary

================================================
FILE: .gitignore
================================================
# Numerous always-ignore extensions
*.diff
*.err
*.log
*.orig
*.rej
*.swo
*.swp
*.vi
*.zip
*~

# OS or Editor folders
._*
.cache
.DS_Store
.idea
.project
.settings
.tmproj
*.esproj
*.sublime-project
*.sublime-workspace
nbproject
Thumbs.db

# Folders to ignore
bower_components
node_modules

# Dev files to ignore
dist
cypress/screenshots
cypress/videos


================================================
FILE: .npmignore
================================================
demo
test
node_modules
cypress
.babelrc


================================================
FILE: .travis.yml
================================================
language: node_js
sudo: false
node_js:
- 8

install:
- yarn


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to AOS

## Bugs

Found a bug? Have a problem with AOS? Please check past issues, maybe someone already had that problem. If you don't find similar issue create new, but remember to add accurate informations so that I can dig into it straight away. If it's possible add CodePen example that presents called issue.

## Development process

### Setup

- Install all dependencies: 
  
  ```
  yarn
  ```

- Run rollup and dev server in watch mode:
  
  ```
  yarn dev
  ```

  This will run [local-server](http://localhost:8080), build AOS and automatically refresh page on any changes (it loads content from `demo` folder).

### Testing

Before you create Pull Request make sure all tests are passing.

In order to do so run:
```
yarn test
```

If you want to run tests while working on the plugin (when local-server is running on), run:
```
yarn test:dev
```

### Commiting changes

If all tests are passing then you're good to go. Commit your changes, but remember to **not commit `dist` folder**.
Create well described Pull Request with as many informations as possible and wait for my answer :) I'd be happy to make a code review and put some thougths.


================================================
FILE: ISSUE_TEMPLATE.md
================================================
<!--- Provide a general summary of the issue in the Title above -->

## This is:
<!-- Select one -->
- Bug
- Feature request
- Question
- Idea

<!--- If you report bug, please follow template below -->
<!--- It will allow us to better understand problem and help you faster -->

## Specifications

  - AOS version:
  - OS:
  - Browser:

## Expected Behavior
<!--- Tell us what should happen -->

## Actual Behavior
<!--- Tell us what happens instead of the expected behavior -->

## Steps to Reproduce the Problem
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.

## Detailed Description
<!--- Provide a detailed description of the change or addition you are proposing -->

## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 Michał Sajnóg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: PULL_REQUEST_TEMPLATE.md
================================================
## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Your solution
<!--- Plese describe your solution, have you encountered any issues along the way? -->

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->

## Screenshots (if relevant):


================================================
FILE: README.md
================================================
[![AOS - Animate on scroll library](https://s32.postimg.org/ktvt59hol/aos_header.png)](http://michalsnik.github.io/aos/)

[![NPM version](https://img.shields.io/npm/v/aos/next.svg?style=flat)](https://npmjs.org/package/aos)
[![NPM downloads](https://img.shields.io/npm/dm/aos.svg?style=flat)](https://npmjs.org/package/aos)
[![Build Status](https://travis-ci.org/michalsnik/aos.svg?branch=master)](https://travis-ci.org/michalsnik/aos)
[![Gitter](https://badges.gitter.im/michalsnik/aos.svg)](https://gitter.im/michalsnik/aos?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

[![Twitter Follow](https://img.shields.io/twitter/follow/michalsnik.svg?style=social)](https://twitter.com/michalsnik) [![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/home?status=AOS%20-%20Animate%20on%20Scroll%20library%0Ahttps%3A//github.com/michalsnik/aos)

## :exclamation::exclamation::exclamation: This is README for aos@next :exclamation::exclamation::exclamation:

For last stable release (v2) go [here](https://github.com/michalsnik/aos/tree/v2)

---
### 🚀 [Demo](http://michalsnik.github.io/aos/)

### 🌟 Codepen Examples
- [Different built-in animations](http://codepen.io/michalsnik/pen/WxNdvq)
- [With anchor setting in use](http://codepen.io/michalsnik/pen/jrOYVO)
- [With anchor-placement and different easings](http://codepen.io/michalsnik/pen/EyxoNm)
- [With simple custom animations](http://codepen.io/michalsnik/pen/WxvNvE)

👉 To get a better understanding how this actually works, I encourage you to check [my post on CSS-tricks](https://css-tricks.com/aos-css-driven-scroll-animation-library/).

---

## ⚙ Installation

### Basic

Add styles in `<head>`:

```html
  <link rel="stylesheet" href="https://unpkg.com/aos@next/dist/aos.css" />
```

Add script right before closing `</body>` tag, and initialize AOS:
```html
  <script src="https://unpkg.com/aos@next/dist/aos.js"></script>
  <script>
    AOS.init();
  </script>
```

### Using package managers

Install `aos` package:
* `yarn add aos@next`
* or `npm install --save aos@next`

Import script, styles and initialize AOS:
```js
import AOS from 'aos';
import 'aos/dist/aos.css'; // You can also use <link> for styles
// ..
AOS.init();
```

In order to make it work you'll have to make sure your build process has configured styles loader, and bundles it all correctly.
If you're using [Parcel](https://parceljs.org/) however, it will work out of the box as provided.

---


## 🤔 How to use it?

### 1. Initialize AOS:

```js
AOS.init();

// You can also pass an optional settings object
// below listed default settings
AOS.init({
  // Global settings:
  disable: false, // accepts following values: 'phone', 'tablet', 'mobile', boolean, expression or function
  startEvent: 'DOMContentLoaded', // name of the event dispatched on the document, that AOS should initialize on
  initClassName: 'aos-init', // class applied after initialization
  animatedClassName: 'aos-animate', // class applied on animation
  useClassNames: false, // if true, will add content of `data-aos` as classes on scroll
  disableMutationObserver: false, // disables automatic mutations' detections (advanced)
  debounceDelay: 50, // the delay on debounce used while resizing window (advanced)
  throttleDelay: 99, // the delay on throttle used while scrolling the page (advanced)
  

  // Settings that can be overridden on per-element basis, by `data-aos-*` attributes:
  offset: 120, // offset (in px) from the original trigger point
  delay: 0, // values from 0 to 3000, with step 50ms
  duration: 400, // values from 0 to 3000, with step 50ms
  easing: 'ease', // default easing for AOS animations
  once: false, // whether animation should happen only once - while scrolling down
  mirror: false, // whether elements should animate out while scrolling past them
  anchorPlacement: 'top-bottom', // defines which position of the element regarding to window should trigger the animation

});
```

### 2. Set animation using `data-aos` attribute:

```html
  <div data-aos="fade-in"></div>
```

And adjust behaviour by using `data-aos-*` attributes:
```html
  <div
    data-aos="fade-up"
    data-aos-offset="200"
    data-aos-delay="50"
    data-aos-duration="1000"
    data-aos-easing="ease-in-out"
    data-aos-mirror="true"
    data-aos-once="false"
    data-aos-anchor-placement="top-center"
  >
  </div>
```

[See full list of all animations, easings and anchor placements](https://github.com/michalsnik/aos#animations)

#### Anchor

There is also a setting that can be used only on per-element basis:
* `data-aos-anchor` - element whose offset will be used to trigger animation instead of an actual one.

Examples:
```html
<div data-aos="fade-up" data-aos-anchor=".other-element"></div>
```

This way you can trigger animation on one element, while you scroll to another - useful in animating fixed elements.

---

## API

AOS object is exposed as a global variable, for now there are three methods available:

  * `init` - initialize AOS
  * `refresh` - recalculate all offsets and positions of elements (called on window resize)
  * `refreshHard` - reinit array with AOS elements and trigger `refresh` (called on DOM changes that are related to `aos` elements)

Example execution:
```javascript
  AOS.refresh();
```

By default AOS is watching for DOM changes and if there are any new elements loaded asynchronously or when something is removed from DOM it calls `refreshHard` automatically. In browsers that don't support `MutationObserver` like IE you might need to call `AOS.refreshHard()` by yourself.

`refresh` method is called on window resize and so on, as it doesn't require to build new store with AOS elements and should be as light as possible.

---

## JS Events

AOS dispatches two events on document: `aos:in` and `aos:out` whenever any element animates in or out, so that you can do extra stuff in JS:
```js
document.addEventListener('aos:in', ({ detail }) => {
  console.log('animated in', detail);
});

document.addEventListener('aos:out', ({ detail }) => {
  console.log('animated out', detail);
});
```

You can also tell AOS to trigger custom event on specific element, by setting `data-aos-id` attribute:
```html
<div data-aos="fade-in" data-aos-id="super-duper"></div>
```

Then you'll be able to listen for two custom events then:
- `aos:in:super-duper`
- `aos:out:super-duper`

---

## Recipes:

#### Adding custom animations:
Sometimes built-in animations are just not enough. Let's say you need one box to have different animation depending on resolution.
Here's how you could do it:

```css
[data-aos="new-animation"] {
  opacity: 0;
  transition-property: transform, opacity;

  &.aos-animate {
    opacity: 1;
  }

  @media screen and (min-width: 768px) {
    transform: translateX(100px);

    &.aos-animate {
      transform: translateX(0);
    }
  }
}
```
Then use it in HTML:
```html
<div data-aos="new-animation"></div>
```
The element will only animate opacity on mobile devices, but from 768px width it'll also slide from right to left.

#### Adding custom easing:
Similar to animations you can add custom easings:
```css
[data-aos] {
  body[data-aos-easing="new-easing"] &,
  &[data-aos][data-aos-easing="new-easing"] {
    transition-timing-function: cubic-bezier(.250, .250, .750, .750);
  }
}
```

#### Customizing default animations distance
Default distance for built-in animations is 100px. As long as you're using SCSS though, you can override it:
```css
$aos-distance: 200px; // It has to be above import
@import 'node_modules/aos/src/sass/aos.scss';
```
You have to however configure your build process to allow it to import styles from `node_modules` beforehand.

#### Integrating external CSS animation library (e.g. Animate.css):
Use `animatedClassName` to change default behaviour of AOS, to apply class names placed inside `data-aos` on scroll.

```html
<div data-aos="fadeInUp"></div>
```

```js
AOS.init({
  useClassNames: true,
  initClassName: false,
  animatedClassName: 'animated',
});
```

The above element will get two classes: `animated` and `fadeInUp`. Using different combinations of the three above settings, you should be able to integrate any external CSS animation library.

External libraries however don't care too much about animation state before the actual animation. So if you want those elements to be not visible before scrolling, you might need to add similar styles:
```css
[data-aos] {
  visibility: hidden;
}
[data-aos].animated {
  visibility: visible;
}
```

---

## Caveats:

#### setting: `duration`, `delay`

Duration and delay accept values from 50 to 3000, with step 50ms, it's because those are handled by css, and to not make css longer than it is already I implemented only a subset. I believe those should cover most cases.

If not, you can write simple CSS that will add another duration, for example:

```css
  body[data-aos-duration='4000'] [data-aos],
  [data-aos][data-aos][data-aos-duration='4000'] {
    transition-duration: 4000ms;
  }
```
This code will add 4000ms duration available for you to set on AOS elements, or to set as global duration while initializing AOS script.
Notice that double `[data-aos][data-aos]` - it's not a mistake, it is a trick, to make individual settings more important than global, without need to write ugly "!important" there :)

Example usage:
```html
  <div data-aos="fade-in" data-aos-duration="4000"></div>
```

---

## Predefined options

### Animations

  * Fade animations:
    * fade
    * fade-up
    * fade-down
    * fade-left
    * fade-right
    * fade-up-right
    * fade-up-left
    * fade-down-right
    * fade-down-left

  * Flip animations:
    * flip-up
    * flip-down
    * flip-left
    * flip-right

  * Slide animations:
    * slide-up
    * slide-down
    * slide-left
    * slide-right

  * Zoom animations:
    * 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

### Anchor placements:

  * top-bottom
  * top-center
  * top-top
  * center-bottom
  * center-center
  * center-top
  * bottom-bottom
  * bottom-center
  * bottom-top

### Easing functions:

  * 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

---

## ❔Questions

If you found a bug, have a question or an idea, please check [AOS contribution guide](CONTRIBUTING.md) and don't hesitate to create new issues.


================================================
FILE: cypress/integration/aos_spec.js
================================================
describe('AOS', function() {
  before(() => {
    cy.visit('/');
    cy.initAOS();
  });

  it('Should be defined', function() {
    cy
      .window()
      .its('AOS')
      .should('exist');
  });

  it('Should have init method', function() {
    cy
      .window()
      .its('AOS.init')
      .should('exist');
  });

  it('Should have refresh method', function() {
    cy
      .window()
      .its('AOS.refresh')
      .should('exist');
  });

  it('Should have refreshHard method', function() {
    cy
      .window()
      .its('AOS.refreshHard')
      .should('exist');
  });

  it('Should add aos-init class on all elements', function() {
    cy.get('.aos-init').should('have.length', 24);
  });

  it('Should add aos-animate class on all visible elements', () => {
    cy.get('.aos-animate').should('have.length', 6);
  });

  it('Should add or remove aos-animate classes regarding to their visibility after scroll', () => {
    cy.scrollTo(0, 200);
    cy.get('.aos-animate').should('have.length', 9);

    cy.scrollTo(0, 800);
    cy.get('.aos-animate').should('have.length', 15);

    cy.scrollTo('top');
    cy.get('.aos-animate').should('have.length', 6);
  });

  it('Should refresh on window resize and orientation change', () => {
    cy.viewport('iphone-6');
    cy.get('.aos-animate').should('have.length', 2);

    cy.scrollTo(0, 100);
    cy.get('.aos-animate').should('have.length', 2);

    cy.viewport('iphone-6', 'landscape');
    cy.get('.aos-animate').should('have.length', 4);

    cy.scrollTo(0, 450);
    cy.get('.aos-animate').should('have.length', 6);

    cy.scrollTo('top');
    cy.get('.aos-animate').should('have.length', 2);

    cy.viewport(1280, 720);
    cy.get('.aos-animate').should('have.length', 6);
  });
});


================================================
FILE: cypress/integration/js_events_spec.js
================================================
describe('JS Events', function() {
  context('default events', function() {
    let aosInStub;
    let aosOutStub;

    before(() => {
      aosInStub = cy.stub();
      aosOutStub = cy.stub();
      cy
        .visit('/')
        .document()
        .then(document => {
          document.addEventListener('aos:in', aosInStub);
          document.addEventListener('aos:out', aosOutStub);
        })
        .initAOS();
    });

    it('Should trigger custom events', function() {
      expect(aosInStub).to.have.callCount(6);
      expect(aosOutStub).to.be.not.called;

      cy.scrollTo(0, 800);
      cy.wait(0, () => {
        expect(aosInStub).to.have.callCount(15);
      });

      cy.scrollTo('top');
      cy.wait(0, () => {
        expect(aosInStub).to.have.callCount(15);
        expect(aosOutStub).to.have.callCount(9);
      });
    });
  });

  context('custom events', function() {
    let aosInStub;
    let aosOutStub;

    before(() => {
      aosInStub = cy.stub();
      aosOutStub = cy.stub();
      cy
        .visit('/')
        .document()
        .then(document => {
          document.addEventListener('aos:in:super-duper', aosInStub);
          document.addEventListener('aos:out:super-duper', aosOutStub);
        })
        .initAOS();
    });

    it('Should trigger custom events', function() {
      expect(aosInStub).to.be.not.called;
      expect(aosOutStub).to.be.not.called;

      cy.scrollTo(0, 350);
      cy.wait(0, () => {
        expect(aosInStub).to.be.calledOnce;
      });

      cy.scrollTo('top');
      cy.wait(0, () => {
        expect(aosOutStub).to.be.calledOnce;
      });
    });
  });
});


================================================
FILE: cypress/integration/mutation_spec.js
================================================
describe('mutation observer', function() {
  before(() => {
    cy.visit('/async.html');
    cy.initAOS();
  });

  it('Should not animate any items if not present', function() {
    cy.get('.aos-item').should('have.length', 0);
    cy.get('.aos-animate').should('have.length', 0);
  });

  it('Should animate new items as they appear', function() {
    cy.dispatchEvent('add-aos-item');
    cy.get('.aos-item').should('have.length', 1);
    cy.get('.aos-animate').should('have.length', 1);

    cy.dispatchEvent('add-aos-item');
    cy.get('.aos-item').should('have.length', 2);
    cy.get('.aos-animate').should('have.length', 2);

    cy.dispatchEvent('add-aos-item');
    cy.get('.aos-item').should('have.length', 3);
    cy.get('.aos-animate').should('have.length', 3);

    cy.dispatchEvent('add-aos-item', 3);
    cy.get('.aos-item').should('have.length', 6);
    cy.get('.aos-animate').should('have.length', 6);

    cy.dispatchEvent('add-aos-item', 3);
    cy.get('.aos-item').should('have.length', 9);
    cy.get('.aos-animate').should('have.length', 6);

    cy.dispatchEvent('add-aos-item', 15);
    cy.get('.aos-item').should('have.length', 24);
    cy.get('.aos-animate').should('have.length', 6);
  });

  it('Should properly animate not visible items on scroll', () => {
    cy.scrollTo(0, 200);
    cy.get('.aos-animate').should('have.length', 9);

    cy.scrollTo('bottom');
    cy.get('.aos-animate').should('have.length', 24);

    cy.scrollTo('top');
    cy.get('.aos-animate').should('have.length', 6);
  });

  it('Should gracefully handle nodes deletion', function() {
    Cypress.$('.aos-item')[1].remove();
    cy.get('.aos-item').should('have.length', 23);
    cy.get('.aos-animate').should('have.length', 6);
  });
});


================================================
FILE: cypress/integration/settings_anchorPlacement_spec.js
================================================
describe('setting: anchorPlacement', function() {
  beforeEach(() => {
    cy.visit('/index.html');
    cy.viewport(1280, 700);
  });

  context('global setting', () => {
    it('Should be respected by all elements', () => {
      cy.initAOS({
        offset: 0,
        anchorPlacement: 'top-center'
      });

      cy.get('.aos-animate').should('have.length', 6);

      cy.scrollTo(0, 300);
      cy.get('.aos-animate').should('have.length', 9);
    });

    it('Should respect default offset', () => {
      cy.initAOS({
        offset: 120,
        anchorPlacement: 'top-center'
      });

      cy.get('.aos-animate').should('have.length', 3);

      cy.scrollTo(0, 120);
      cy.get('.aos-animate').should('have.length', 6);
    });
  });

  context('inline setting', () => {
    it('Should override global setting and reset default offset', () => {
      cy.document().then(document => {
        const el = document.querySelector('[data-id="6"]');
        el.dataset.aosAnchorPlacement = 'bottom-center';
      });

      cy.initAOS({
        offset: 400,
        anchorPlacement: 'top-center'
      });

      cy.get('[data-id="6"]').should('not.have.class', 'aos-animate');

      cy.scrollTo(0, 290);
      cy.get('[data-id="6"]').should('not.have.class', 'aos-animate');

      cy.scrollTo(0, 300);
      cy.get('[data-id="6"]').should('have.class', 'aos-animate');
    });

    it('Should respect inline offset', () => {
      cy.document().then(document => {
        const el = document.querySelector('[data-id="6"]');
        el.dataset.aosAnchorPlacement = 'bottom-center';
        el.dataset.aosOffset = 100;
      });

      cy.initAOS({
        offset: 400,
        anchorPlacement: 'top-center'
      });

      cy.get('[data-id="6"]').should('not.have.class', 'aos-animate');

      cy.scrollTo(0, 300);
      cy.get('[data-id="6"]').should('not.have.class', 'aos-animate');

      cy.scrollTo(0, 400);
      cy.get('[data-id="6"]').should('have.class', 'aos-animate');
    });
  });
});


================================================
FILE: cypress/integration/settings_anchor_spec.js
================================================
describe('setting: anchor', function() {
  before(() => {
    cy.visit('/anchor.html');
    cy.viewport(1280, 700);
    cy.initAOS({
      offset: 0
    });
  });

  it('Should properly animate elements according to anchor positions', () => {
    cy.get('.aos-animate').should('have.length', 0);

    cy.scrollTo(0, 50);
    cy.get('.aos-animate').should('have.length', 1);
    cy.get('[data-id="1"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 550);
    cy.get('.aos-animate').should('have.length', 2);
    cy.get('[data-id="2"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 750);
    cy.get('.aos-animate').should('have.length', 3);
    cy.get('[data-id="4"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 1050);
    cy.get('.aos-animate').should('have.length', 4);
    cy.get('[data-id="3"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 1250);
    cy.get('.aos-animate').should('have.length', 5);
    cy.get('[data-id="5"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 1450);
    cy.get('.aos-animate').should('have.length', 6);
    cy.get('[data-id="7"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 1750);
    cy.get('.aos-animate').should('have.length', 7);
    cy.get('[data-id="6"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 1950);
    cy.get('.aos-animate').should('have.length', 8);
    cy.get('[data-id="8"]').should('have.class', 'aos-animate');

    cy.scrollTo(0, 2450);
    cy.get('.aos-animate').should('have.length', 9);
    cy.get('[data-id="9"]').should('have.class', 'aos-animate');
  });
});


================================================
FILE: cypress/integration/settings_animatedClassName_spec.js
================================================
describe('setting: animatedClassName', function() {
  context('with: "rawr"', function() {
    before(() => {
      cy.visit('/');
      cy.initAOS({
        animatedClassName: 'rawr'
      });
    });

    it('Should set proper class names on AOS elements', function() {
      cy.get('.aos-animate').should('have.length', 0);
      cy.get('.rawr').should('have.length', 6);

      cy.scrollTo(0, 800);
      cy.get('.aos-animate').should('have.length', 0);
      cy.get('.rawr').should('have.length', 15);
    });
  });

  context('with: null', function() {
    before(() => {
      cy.visit('/');
      cy.initAOS({
        animatedClassName: null
      });
    });

    it('Should not set class names on AOS elements on scroll', function() {
      cy.get('.aos-animate').should('have.length', 0);
      cy.scrollTo(0, 800);
      cy.get('.aos-animate').should('have.length', 0);
    });
  });
});


================================================
FILE: cypress/integration/settings_delay_spec.js
================================================
describe('setting: delay', function() {
  before(() => {
    cy.visit('/');
  });

  it('Should set default delay attribue on body', function() {
    cy.initAOS();
    cy.get('body').should('have.attr', 'data-aos-delay', '0');
  });

  it('Should respect global delay setting and set attribue on body', function() {
    cy.initAOS({
      delay: 100
    });
    cy.get('body').should('have.attr', 'data-aos-delay', '100');
  });
});


================================================
FILE: cypress/integration/settings_disableMutationObserver_spec.js
================================================
describe('setting: disableMutationObserver', function() {
  before(() => {
    cy.visit('/async.html');
    cy.initAOS({
      disableMutationObserver: true
    });
  });

  it('Should not detect any changes in DOM, and thus not animate any elements as a result', function() {
    cy.dispatchEvent('add-aos-item', 20);
    cy.get('.aos-item').should('have.length', 20);
    cy.get('.aos-animate').should('have.length', 0);
  });

  it('Should not animate dynamically loaded elements on scroll', function() {
    cy.scrollTo('bottom');
    cy.get('.aos-animate').should('have.length', 0);
  });
});


================================================
FILE: cypress/integration/settings_disable_spec.js
================================================
describe('setting: disable', function() {
  beforeEach(() => {
    cy.visit('/');
  });

  it('Should properly disable AOS', function() {
    cy.initAOS({
      disable: true
    });

    cy.get('.aos-item[data-aos]').should('have.length', 0);
    cy.get('.aos-init').should('have.length', 0);
    cy.get('.aos-animate').should('have.length', 0);
  });

  it('Should respect function passed as "disable" value', function() {
    cy.viewport(360, 420);

    cy.window().then(({ AOS, innerWidth }) => {
      AOS.init({
        disable: () => innerWidth < 400
      });
    });

    cy.get('.aos-item[data-aos]').should('have.length', 0);
    cy.get('.aos-init').should('have.length', 0);
    cy.get('.aos-animate').should('have.length', 0);
  });
});


================================================
FILE: cypress/integration/settings_duration_spec.js
================================================
describe('setting: duration', function() {
  before(() => {
    cy.visit('/');
  });

  it('Should set default duration attribue on body', function() {
    cy.initAOS();
    cy.get('body').should('have.attr', 'data-aos-duration', '400');
  });

  it('Should respect global duration setting and set attribue on body', function() {
    cy.initAOS({
      duration: 2000
    });
    cy.get('body').should('have.attr', 'data-aos-duration', '2000');
  });
});


================================================
FILE: cypress/integration/settings_easing_spec.js
================================================
describe('setting: easing', function() {
  before(() => {
    cy.visit('/');
  });

  it('Should set default easing attribue on body', function() {
    cy.initAOS();
    cy.get('body').should('have.attr', 'data-aos-easing', 'ease');
  });

  it('Should respect global easing setting and set attribue on body', function() {
    cy.initAOS({
      easing: 'ease-in-sine'
    });
    cy.get('body').should('have.attr', 'data-aos-easing', 'ease-in-sine');
  });
});


================================================
FILE: cypress/integration/settings_initClassName_spec.js
================================================
describe('setting: initClassName', function() {
  context('with: "rawr"', function() {
    before(() => {
      cy.visit('/');
      cy.initAOS({
        initClassName: 'rawr'
      });
    });

    it('Should set proper class names on AOS elements', function() {
      cy.get('.aos-init').should('have.length', 0);
      cy.get('.rawr').should('have.length', 24);
    });
  });

  context('with: null', function() {
    before(() => {
      cy.visit('/');
      cy.initAOS({
        initClassName: null
      });
    });

    it('Should not set initial class name on AOS elements', function() {
      cy.get('.aos-init').should('have.length', 0);
    });
  });
});


================================================
FILE: cypress/integration/settings_mirror.js
================================================
describe('setting: mirror', function() {
  before(() => {
    cy.visit('/');
    cy.viewport(1280, 650);
    cy.initAOS({
      mirror: true,
      offset: 50
    });
  });

  it('Should animate in and out', function() {
    cy.get('.aos-animate').should('have.length', 6);

    cy.scrollTo(0, 50);
    cy.get('.aos-animate').should('have.length', 9);
    cy
      .get('.aos-init')
      .eq(0)
      .should('have.class', 'aos-animate');

    cy.scrollTo(0, 300);
    cy.get('.aos-animate').should('have.length', 6);
    cy
      .get('.aos-init')
      .eq(0)
      .should('not.have.class', 'aos-animate');

    cy.scrollTo(0, 350);
    cy.get('.aos-animate').should('have.length', 9);
    cy
      .get('.aos-init')
      .eq(3)
      .should('have.class', 'aos-animate');

    cy.scrollTo(0, 600);
    cy.get('.aos-animate').should('have.length', 6);
    cy
      .get('.aos-init')
      .eq(3)
      .should('not.have.class', 'aos-animate');

    cy.scrollTo(0, 650);
    cy.get('.aos-animate').should('have.length', 9);
  });
});


================================================
FILE: cypress/integration/settings_offset_spec.js
================================================
describe('setting: offset', function() {
  context('global', () => {
    before(() => {
      cy.visit('/');
    });

    context('400px', () => {
      before(() => {
        cy.initAOS({
          offset: 400
        });
      });

      it('Should animate 3 items', function() {
        cy.get('.aos-animate').should('have.length', 3);
      });

      it('Should animate next 3 items on scroll', function() {
        cy.scrollTo(0, 50);
        cy.get('.aos-animate').should('have.length', 6);
      });
    });

    context('0px', () => {
      before(() => {
        cy.initAOS({
          offset: 0
        });
      });

      it('Should animate 9 items', function() {
        cy.get('.aos-animate').should('have.length', 9);
        cy.scrollTo(0, 50);
        cy.get('.aos-animate').should('have.length', 9);
      });
    });
  });

  context('inline', () => {
    before(() => {
      cy.visit('/offset.html');
      cy.initAOS();
      cy.viewport(1280, 500);
    });

    it('Should properly tigger all animations', function() {
      cy.get('.aos-animate').should('have.length', 7);
      cy.scrollTo(0, 1 * 150);
      cy.get('.aos-animate').should('have.length', 8);
      cy.scrollTo(0, 2 * 150);
      cy.get('.aos-animate').should('have.length', 10);
      cy.scrollTo(0, 3 * 150);
      cy.get('.aos-animate').should('have.length', 11);
      cy.scrollTo(0, 4 * 150);
      cy.get('.aos-animate').should('have.length', 13);
      cy.scrollTo(0, 5 * 150);
      cy.get('.aos-animate').should('have.length', 14);
      cy.scrollTo(0, 6 * 150);
      cy.get('.aos-animate').should('have.length', 16);
      cy.scrollTo(0, 7 * 150);
      cy.get('.aos-animate').should('have.length', 17);
      cy.scrollTo(0, 8 * 150);
      cy.get('.aos-animate').should('have.length', 19);
      cy.scrollTo(0, 9 * 150);
      cy.get('.aos-animate').should('have.length', 20);
      cy.scrollTo(0, 10 * 150);
      cy.get('.aos-animate').should('have.length', 22);
      cy.scrollTo(0, 11 * 150);
      cy.get('.aos-animate').should('have.length', 23);
      cy.scrollTo(0, 12 * 150);
      cy.get('.aos-animate').should('have.length', 25);
      cy.scrollTo(0, 13 * 150);
      cy.get('.aos-animate').should('have.length', 26);
      cy.scrollTo(0, 14 * 150);
      cy.get('.aos-animate').should('have.length', 27);
    });
  });
});


================================================
FILE: cypress/integration/settings_once_spec.js
================================================
describe('setting: once', function() {
  context('global', () => {
    before(() => {
      cy.visit('/');
      cy.initAOS({
        once: true
      });
    });

    it('Should add aos-animate class on all visible elements', () => {
      cy.get('.aos-animate').should('have.length', 6);
    });

    it('Should add aos-animate class to all visible elements after scroll', () => {
      cy.scrollTo(0, 200);
      cy.get('.aos-animate').should('have.length', 9);

      cy.scrollTo(0, 800);
      cy.get('.aos-animate').should('have.length', 15);
    });

    it('Should not remove aos-animate class after scrolling up', () => {
      cy.scrollTo(0, 0);
      cy.get('.aos-animate').should('have.length', 15);
    });
  });

  context('inline', () => {
    before(() => {
      cy.visit('/once.html');
      cy.initAOS();
    });

    it('Should add aos-animate class on all visible elements', () => {
      cy.get('.aos-animate').should('have.length', 6);
    });

    it('Should add aos-animate class to all visible elements after scroll', () => {
      cy.scrollTo(0, 200);
      cy.get('.aos-animate').should('have.length', 9);

      cy.scrollTo('bottom');
      cy.get('.aos-animate').should('have.length', 21);
    });

    it('Should not remove aos-animate class after scrolling up', () => {
      cy.scrollTo(0, 0);
      cy.get('.aos-animate').should('have.length', 11);
      cy
        .get('.aos-init')
        .eq(8)
        .should('have.class', 'aos-animate');
      cy
        .get('.aos-init')
        .eq(10)
        .should('have.class', 'aos-animate');
      cy
        .get('.aos-init')
        .eq(12)
        .should('have.class', 'aos-animate');
      cy
        .get('.aos-init')
        .eq(16)
        .should('have.class', 'aos-animate');
      cy
        .get('.aos-init')
        .eq(20)
        .should('have.class', 'aos-animate');
    });
  });
});


================================================
FILE: cypress/integration/settings_startEvent_spec.js
================================================
describe('setting: startEvent', function() {
  beforeEach(() => {
    cy.visit('/');
  });

  it('Should allow to initialize AOS on custom event', function() {
    cy.initAOS({
      startEvent: 'customEvent'
    });

    cy.get('.aos-init').should('have.length', 0);
    cy.dispatchEvent('customEvent');
    cy.get('.aos-init').should('have.length', 24);
  });

  it('Should properly initialize on "load" event', function() {
    cy.initAOS({
      startEvent: 'load'
    });

    cy.window().then(window => window.dispatchEvent(new Event('load')));

    cy.get('.aos-init').should('have.length', 24);
  });

  it("Shouldn't initialize when event is not dispatched", function() {
    cy.initAOS({
      startEvent: 'another-event-name'
    });

    cy.get('.aos-init').should('have.length', 0);
  });
});


================================================
FILE: cypress/integration/settings_useClassNames.js
================================================
describe('setting: useClassNames', function() {
  context('just useClassNames', function() {
    before(() => {
      cy.visit('/animatecss.html');
      cy.initAOS({
        useClassNames: true
      });
    });

    it('Should set proper custom class names on AOS elements', function() {
      cy.get('.aos-animate').should('have.length', 6);
      cy.get('.fadeInUp').should('have.length', 6);

      cy.scrollTo(0, 800);
      cy.get('.aos-animate').should('have.length', 15);
      cy.get('.fadeInUp').should('have.length', 15);
    });
  });

  context('with animatedClassName and initClassName', function() {
    before(() => {
      cy.visit('/animatecss.html');
      cy.initAOS({
        useClassNames: true,
        initClassName: false,
        animatedClassName: 'animate'
      });
    });

    it('Should set proper custom class names on AOS elements', function() {
      cy.get('.aos-init').should('have.length', 0);
      cy.get('.aos-animate').should('have.length', 0);

      cy.get('.animate').should('have.length', 6);
      cy.get('.fadeInUp').should('have.length', 6);

      cy.scrollTo(0, 800);
      cy.get('.aos-animate').should('have.length', 0);
      cy.get('.animate').should('have.length', 15);
      cy.get('.fadeInUp').should('have.length', 15);
    });
  });
});


================================================
FILE: cypress/plugins/index.js
================================================
module.exports = (on, config) => {
  on('before:browser:launch', (browser = {}, args) => {
    console.log(browser, args); // see what all is in here!

    if (browser.name === 'chrome') {
      args.push('--disable-gpu');
      return args;
    }
  });
};


================================================
FILE: cypress/support/commands.js
================================================
Cypress.Commands.add('initAOS', settings => {
  cy.window().then(({ AOS }) => {
    AOS.init(settings);
  });
});

Cypress.Commands.add('dispatchEvent', (eventName, times = 1) => {
  cy.window().then(window => {
    const event = new Event(eventName);
    for (let i = 0; i < times; i++) {
      window.document.dispatchEvent(event);
    }
  });
});


================================================
FILE: cypress/support/index.js
================================================
import './commands';


================================================
FILE: cypress.json
================================================
{
  "baseUrl": "http://127.0.0.1:8080",
  "viewportWidth": 1280,
  "viewportHeight": 720
}


================================================
FILE: demo/anchor.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>AOS - Animate on scroll library</title>
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="css/styles.css" />
    <link rel="stylesheet" href="dist/aos.css" />
    <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="aos-anchors">
      <div class="aos-anchors__lines"></div>
      <div class="aos-anchors__sidebar">
        <div data-id="1" data-aos="fade-up" data-aos-anchor="[data-anchor-id='1']" data-aos-anchor-placement="top-top">
          Anchor: 1
        </div>
        <div data-id="2" data-aos="fade-up" data-aos-anchor="[data-anchor-id='2']" data-aos-anchor-placement="center-top">
          Anchor: 2
        </div>
        <div data-id="3" data-aos="fade-up" data-aos-anchor="[data-anchor-id='3']" data-aos-anchor-placement="bottom-top">
          Anchor: 3
        </div>
        <div data-id="4" data-aos="fade-up" data-aos-anchor="[data-anchor-id='4']" data-aos-anchor-placement="top-center">
          Anchor: 4
        </div>
        <div data-id="5" data-aos="fade-up" data-aos-anchor="[data-anchor-id='5']" data-aos-anchor-placement="center-center">
          Anchor: 5
        </div>
        <div data-id="6" data-aos="fade-up" data-aos-anchor="[data-anchor-id='6']" data-aos-anchor-placement="bottom-center">
          Anchor: 6
        </div>
        <div data-id="7" data-aos="fade-up" data-aos-anchor="[data-anchor-id='7']" data-aos-anchor-placement="top-bottom">
          Anchor: 7
        </div>
        <div data-id="8" data-aos="fade-up" data-aos-anchor="[data-anchor-id='8']" data-aos-anchor-placement="center-bottom">
          Anchor: 8
        </div>
        <div data-id="9" data-aos="fade-up" data-aos-anchor="[data-anchor-id='9']" data-aos-anchor-placement="bottom-bottom">
          Anchor: 9
        </div>
      </div>
      <div class="aos-anchors__content">
        <div data-anchor-id="1" data-placement="top-top"></div>
        <div data-anchor-id="2" data-placement="center-top"></div>
        <div data-anchor-id="3" data-placement="bottom-top"></div>
        <div data-anchor-id="4" data-placement="top-center"></div>
        <div data-anchor-id="5" data-placement="center-center"></div>
        <div data-anchor-id="6" data-placement="bottom-center"></div>
        <div data-anchor-id="7" data-placement="top-bottom"></div>
        <div data-anchor-id="8" data-placement="center-bottom"></div>
        <div data-anchor-id="9" data-placement="bottom-bottom"></div>
      </div>
    </div>

    <script src="dist/aos.js"></script>
    <script>
      if (!window.Cypress) AOS.init();
    </script>
  </body>
</html>


================================================
FILE: demo/animatecss.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>AOS - Animate on scroll library</title>
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="css/styles.css" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
    <style>
      [data-aos] {
        visibility: hidden;
      }
      [data-aos].animated {
        visibility: visible;
      }
    </style>
    <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="aos-all">
      <div data-id="1" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="2" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="3" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="4" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="5" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="6" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="7" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="8" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="9" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="10" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="11" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="12" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="13" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="14" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="15" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="16" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="17" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="18" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="19" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="20" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="21" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="22" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="23" class="aos-item" data-aos="fadeInUp"></div>
      <div data-id="24" class="aos-item" data-aos="fadeInUp"></div>
    </div>

    <script src="dist/aos.js"></script>
    <script>
      if (!window.Cypress) AOS.init({
        useClassNames: true,
        initClassName: false,
        animatedClassName: 'animated',
      });
    </script>
  </body>
</html>


================================================
FILE: demo/async.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>AOS - Animate on scroll library</title>
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="css/styles.css" />
    <link rel="stylesheet" href="dist/aos.css" />
    <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div id="aos-demo" class="aos-all"></div>

    <script src="dist/aos.js"></script>
    <script>
      if (!window.Cypress) {
        AOS.init();
        setInterval(addItem, 150);
      } else {
        document.addEventListener('add-aos-item', addItem);
      }

      var itemsCounter = 1;
      var container = document.getElementById('aos-demo');

      function addItem () {
        if (itemsCounter > 24) return;
        var item = document.createElement('div');
        item.classList.add('aos-item');
        item.setAttribute('data-id', itemsCounter);
        item.setAttribute('data-aos', 'fade-up');
        container.appendChild(item);
        itemsCounter++;
      }
    </script>
  </body>
</html>


================================================
FILE: demo/css/styles.css
================================================
body {
  font-family: Helvetica,Tahoma;
}

*,
*:before,
*:after {
  box-sizing: border-box;
}

.scroll-counter {
  position: fixed;
  top: 0;
  right: 0;
  padding: 15px;
  color: white;
  background-color: rgba(0,0,0,0.4);
}

.aos-all {
  width: 1000px;
  max-width: 98%;
  margin: 50px auto;
}

.aos-item {
  display: inline-block;
  float: left;
  width: 100%;
  height: 300px;
  padding: 20px;
}

.aos-item::before {
  content: attr(data-id);
  position: relative;
  width: 100%;
  height: 100%;
  float: left;
  background: #1da4e2;
  line-height: 260px;
  text-align: center;
  color: #fff;
}

@media screen and (min-width: 420px) {
  .aos-item {
    width: 50%;
  }
}

@media screen and (min-width: 1024px) {
  .aos-item {
    width: 33%;
  }
}

.aos-anchors__lines {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  border-top: 2px solid blue;
  border-bottom: 2px solid red;
}

.aos-anchors__lines::before {
  content: '';
  width: 100%;
  height: 2px;
  position: absolute;
  margin: auto;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: green;
}

.aos-anchors__sidebar {
  position: fixed;
  left: 0;
  top: 0;
}

.aos-anchors__sidebar > div {
  padding: 5px 10px;
  background: #f1f1f1;
}

.aos-anchors__content {
  width: 400px;
  margin: 50px auto;
}

.aos-anchors__content > div {
  position: relative;
  width: 100%;
  height: 300px;
  margin-bottom: 50px;
  background: #f1f1f1;
  line-height: 300px;
  text-align: center;
  color: #333;
}

.aos-anchors__content > div::before {
  content: '';
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
}

.aos-anchors__content > div::after {
  content: attr(data-anchor-id);
  position: relative;
  background-color: #f1f1f1;
}

.aos-anchors__content > div[data-placement$="-bottom"]::before {
  background-color: red;
}

.aos-anchors__content > div[data-placement$="-center"]::before {
  background-color: green;
}

.aos-anchors__content > div[data-placement$="-top"]::before {
  background-color: blue;
}

.aos-anchors__content > div[data-placement^="top-"]::before {
  top: 0;
}

.aos-anchors__content > div[data-placement^="center-"]::before {
  top: 0;
  bottom: 0;
  margin: auto;
}

.aos-anchors__content > div[data-placement^="bottom-"]::before {
  bottom: 0;
}


================================================
FILE: demo/index.html
================================================
<!DOCTYPE html>
<html class="no-js">
  <head>
    <meta charset="utf-8">
    <title>AOS - Animate on scroll library</title>
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="css/styles.css" />
    <link rel="stylesheet" href="dist/aos.css" />
    <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="js-scroll-counter scroll-counter"></div>
    <div class="aos-all">
      <div data-id="1" class="aos-item" data-aos="fade-up"></div>
      <div data-id="2" class="aos-item" data-aos="fade-down"></div>
      <div data-id="3" class="aos-item" data-aos="zoom-out-down"></div>
      <div data-id="4" class="aos-item" data-aos="flip-down"></div>
      <div data-id="5" class="aos-item" data-aos="flip-up"></div>
      <div data-id="6" class="aos-item" data-aos="fade-down"></div>
      <div data-id="7" class="aos-item" data-aos="fade-in"></div>
      <div data-id="8" class="aos-item" data-aos="fade-down"></div>
      <div data-id="9" class="aos-item" data-aos="fade-in"></div>
      <div data-id="10" class="aos-item" data-aos="fade-down" data-aos-id="super-duper"></div>
      <div data-id="11" class="aos-item" data-aos="fade-up"></div>
      <div data-id="12" class="aos-item" data-aos="fade-down"></div>
      <div data-id="13" class="aos-item" data-aos="fade-in"></div>
      <div data-id="14" class="aos-item" data-aos="fade-up"></div>
      <div data-id="15" class="aos-item" data-aos="fade-in"></div>
      <div data-id="16" class="aos-item" data-aos="fade-up"></div>
      <div data-id="17" class="aos-item" data-aos="fade-down"></div>
      <div data-id="18" class="aos-item" data-aos="fade-up"></div>
      <div data-id="19" class="aos-item" data-aos="zoom-out"></div>
      <div data-id="20" class="aos-item" data-aos="fade-up"></div>
      <div data-id="21" class="aos-item" data-aos="zoom-out"></div>
      <div data-id="22" class="aos-item" data-aos="fade-in"></div>
      <div data-id="23" class="aos-item" data-aos="zoom-out-up"></div>
      <div data-id="24" class="aos-item" data-aos="zoom-out-down"></div>
    </div>

    <script src="dist/aos.js"></script>
    <script>
      document.querySelector('html').classList.remove('no-js');
      if (!window.Cypress) {
        const scrollCounter = document.querySelector('.js-scroll-counter');

        AOS.init({
          mirror: true
        });

        document.addEventListener('aos:in', function(e) {
          console.log('in!', e.detail);
        });

        window.addEventListener('scroll', function() {
          scrollCounter.innerHTML = window.pageYOffset;
        });
      }
    </script>
  </body>
</html>


================================================
FILE: demo/offset.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>AOS - Animate on scroll library</title>
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="css/styles.css" />
    <link rel="stylesheet" href="dist/aos.css" />
    <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="aos-all">
      <div data-id="1" class="aos-item" data-aos="fade-up"></div>
      <div data-id="2" class="aos-item" data-aos="fade-up"></div>
      <div data-id="3" class="aos-item" data-aos="fade-up"></div>

      <div data-id="4" class="aos-item" data-aos="fade-up"></div>
      <div data-id="5" class="aos-item" data-aos="fade-up"></div>
      <div data-id="6" class="aos-item" data-aos="fade-up"></div>

      <div data-id="7" class="aos-item" data-aos="fade-up" data-aos-offset="-150"></div>
      <div data-id="8" class="aos-item" data-aos="fade-up" data-aos-offset="0"></div>
      <div data-id="9" class="aos-item" data-aos="fade-up" data-aos-offset="150"></div>

      <div data-id="10" class="aos-item" data-aos="fade-down" data-aos-offset="-150"></div>
      <div data-id="11" class="aos-item" data-aos="fade-down" data-aos-offset="0"></div>
      <div data-id="12" class="aos-item" data-aos="fade-down" data-aos-offset="150"></div>

      <div data-id="13" class="aos-item" data-aos="flip-up" data-aos-offset="-150"></div>
      <div data-id="14" class="aos-item" data-aos="flip-up" data-aos-offset="0"></div>
      <div data-id="15" class="aos-item" data-aos="flip-up" data-aos-offset="150"></div>

      <div data-id="16" class="aos-item" data-aos="flip-down" data-aos-offset="-150"></div>
      <div data-id="17" class="aos-item" data-aos="flip-down" data-aos-offset="0"></div>
      <div data-id="18" class="aos-item" data-aos="flip-down" data-aos-offset="150"></div>

      <div data-id="19" class="aos-item" data-aos="zoom-out-up" data-aos-offset="-150"></div>
      <div data-id="20" class="aos-item" data-aos="zoom-out-up" data-aos-offset="0"></div>
      <div data-id="21" class="aos-item" data-aos="zoom-out-up" data-aos-offset="150"></div>

      <div data-id="22" class="aos-item" data-aos="zoom-out-down" data-aos-offset="-150"></div>
      <div data-id="23" class="aos-item" data-aos="zoom-out-down" data-aos-offset="0"></div>
      <div data-id="24" class="aos-item" data-aos="zoom-out-down" data-aos-offset="150"></div>

      <div data-id="25" class="aos-item" data-aos="zoom-in-up" data-aos-offset="-150"></div>
      <div data-id="26" class="aos-item" data-aos="zoom-in-up" data-aos-offset="0"></div>
      <div data-id="27" class="aos-item" data-aos="zoom-in-up" data-aos-offset="150"></div>
    </div>

    <script src="dist/aos.js"></script>
    <script>
      if (!window.Cypress) AOS.init();
    </script>
  </body>
</html>


================================================
FILE: demo/once.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>AOS - Animate on scroll library</title>
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="css/styles.css" />
    <link rel="stylesheet" href="dist/aos.css" />
    <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <div class="aos-all">
      <div data-id="1" class="aos-item" data-aos="fade-up" data-aos-once="true"></div>
      <div data-id="2" class="aos-item" data-aos="fade-down"></div>
      <div data-id="3" class="aos-item" data-aos="zoom-out-down"></div>
      <div data-id="4" class="aos-item" data-aos="flip-down"></div>
      <div data-id="5" class="aos-item" data-aos="flip-up" data-aos-once="true"></div>
      <div data-id="6" class="aos-item" data-aos="fade-down"></div>
      <div data-id="7" class="aos-item" data-aos="fade-in"></div>
      <div data-id="8" class="aos-item" data-aos="fade-down"></div>
      <div data-id="9" class="aos-item" data-aos="fade-in" data-aos-once="true"></div>
      <div data-id="10" class="aos-item" data-aos="fade-down"></div>
      <div data-id="11" class="aos-item" data-aos="fade-up" data-aos-once="true"></div>
      <div data-id="12" class="aos-item" data-aos="fade-down"></div>
      <div data-id="13" class="aos-item" data-aos="fade-in" data-aos-once="true"></div>
      <div data-id="14" class="aos-item" data-aos="fade-up"></div>
      <div data-id="15" class="aos-item" data-aos="fade-in"></div>
      <div data-id="16" class="aos-item" data-aos="fade-up"></div>
      <div data-id="17" class="aos-item" data-aos="fade-down" data-aos-once="true"></div>
      <div data-id="18" class="aos-item" data-aos="fade-up"></div>
      <div data-id="19" class="aos-item" data-aos="zoom-out"></div>
      <div data-id="20" class="aos-item" data-aos="fade-up"></div>
      <div data-id="21" class="aos-item" data-aos="zoom-out" data-aos-once="true"></div>
    </div>

    <script src="dist/aos.js"></script>
    <script>
      if (!window.Cypress) AOS.init();
    </script>
  </body>
</html>


================================================
FILE: package.json
================================================
{
  "name": "aos",
  "version": "3.0.0-beta.6",
  "description": "Animate on scroll library",
  "homepage": "https://michalsnik.github.io/aos/",
  "author": "Michał Sajnóg <michal.sajnog@hotmail.com>",
  "license": "MIT",
  "main": "dist/aos.cjs.js",
  "module": "dist/aos.esm.js",
  "browser": "dist/aos.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/michalsnik/aos.git"
  },
  "bugs": {
    "url": "https://github.com/michalsnik/aos/issues"
  },
  "devDependencies": {
    "autoprefixer": "^8.4.1",
    "babel-core": "^6.26.3",
    "babel-eslint": "^8.2.3",
    "babel-plugin-external-helpers": "^6.22.0",
    "babel-plugin-transform-object-assign": "^6.22.0",
    "babel-preset-env": "^1.7.0",
    "cssnano": "^3.10.0",
    "cypress": "^2.1.0",
    "eslint": "^4.19.1",
    "eslint-config-prettier": "^2.9.0",
    "eslint-plugin-prettier": "^2.6.0",
    "live-server": "tapio/live-server#master",
    "node-sass": "^4.9.0",
    "npm-run-all": "^4.1.3",
    "rollup": "^0.58.2",
    "rollup-plugin-babel": "^3.0.4",
    "rollup-plugin-commonjs": "^9.1.3",
    "rollup-plugin-node-resolve": "^3.3.0",
    "rollup-plugin-postcss": "^1.6.1",
    "rollup-plugin-uglify": "^3.0.0"
  },
  "dependencies": {
    "classlist-polyfill": "^1.2.0",
    "lodash.debounce": "^4.0.8",
    "lodash.throttle": "^4.1.1"
  },
  "scripts": {
    "build": "NODE_ENV=production rollup -c",
    "watch": "NODE_ENV=dev rollup -c -w",
    "serve": "node ./scripts/start-server.js",
    "dev": "npm-run-all --parallel serve watch",
    "test": "yarn lint && NODE_ENV=test node ./scripts/run-cypress-tests.js",
    "test:dev": "cypress open",
    "lint": "eslint src cypress demo scripts",
    "prepare": "npm run build"
  },
  "files": [
    "dist",
    "src"
  ]
}


================================================
FILE: rollup.config.js
================================================
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import postcss from 'rollup-plugin-postcss';
import uglify from 'rollup-plugin-uglify';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import pkg from './package.json';

const transformStyles = postcss({
  extract: 'dist/aos.css',
  plugins: [autoprefixer, cssnano]
});

const input = 'src/js/aos.js';

export default [
  {
    input,
    output: {
      file: pkg.browser,
      name: 'AOS',
      format: 'umd',
      sourcemap: process.env.NODE_ENV === 'dev'
    },
    plugins: [
      transformStyles,
      resolve(),
      commonjs(),
      babel({
        exclude: ['node_modules/**']
      }),
      uglify()
    ]
  },
  {
    input,
    external: Object.keys(pkg.dependencies),
    output: [
      { file: pkg.main, format: 'cjs' },
      { file: pkg.module, format: 'es' }
    ],
    plugins: [
      transformStyles,
      babel({
        exclude: ['node_modules/**']
      })
    ]
  }
];


================================================
FILE: scripts/run-cypress-tests.js
================================================
const cypress = require('cypress');
const server = require('./start-server');

cypress.run().then(({ failures }) => {
  server.close();
  process.exit(failures === 0 ? 0 : 1);
});


================================================
FILE: scripts/start-server.js
================================================
const liveServer = require('live-server');

const params = {
  port: 8080,
  host: '0.0.0.0',
  root: './demo',
  watch: ['dist/**', 'demo/**'],
  open: process.env.NODE_ENV !== 'test',
  mount: [['/dist', './dist']],
  noCssInject: true
};

const server = liveServer.start(params);

module.exports = server;


================================================
FILE: src/js/aos.js
================================================
/**
 * *******************************************************
 * AOS (Animate on scroll) - wowjs alternative
 * made to animate elements on scroll in both directions
 * *******************************************************
 */
import styles from './../sass/aos.scss';

// Modules & helpers
import throttle from 'lodash.throttle';
import debounce from 'lodash.debounce';

import observer from './libs/observer';

import detect from './helpers/detector';
import handleScroll from './helpers/handleScroll';
import prepare from './helpers/prepare';
import elements from './helpers/elements';

/**
 * Private variables
 */
let $aosElements = [];
let initialized = false;

/**
 * Default options
 */
let options = {
  offset: 120,
  delay: 0,
  easing: 'ease',
  duration: 400,
  disable: false,
  once: false,
  mirror: false,
  anchorPlacement: 'top-bottom',
  startEvent: 'DOMContentLoaded',
  animatedClassName: 'aos-animate',
  initClassName: 'aos-init',
  useClassNames: false,
  disableMutationObserver: false,
  throttleDelay: 99,
  debounceDelay: 50
};

// Detect not supported browsers (<=IE9)
// http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
const isBrowserNotSupported = () => document.all && !window.atob;

const initializeScroll = function initializeScroll() {
  // Extend elements objects in $aosElements with their positions
  $aosElements = prepare($aosElements, options);
  // Perform scroll event, to refresh view and show/hide elements
  handleScroll($aosElements);

  /**
   * Handle scroll event to animate elements on scroll
   */
  window.addEventListener(
    'scroll',
    throttle(() => {
      handleScroll($aosElements, options.once);
    }, options.throttleDelay)
  );

  return $aosElements;
};

/**
 * Refresh AOS
 */
const refresh = function refresh(initialize = false) {
  // Allow refresh only when it was first initialized on startEvent
  if (initialize) initialized = true;
  if (initialized) initializeScroll();
};

/**
 * Hard refresh
 * create array with new elements and trigger refresh
 */
const refreshHard = function refreshHard() {
  $aosElements = elements();

  if (isDisabled(options.disable) || isBrowserNotSupported()) {
    return disable();
  }

  refresh();
};

/**
 * Disable AOS
 * Remove all attributes to reset applied styles
 */
const disable = function() {
  $aosElements.forEach(function(el, i) {
    el.node.removeAttribute('data-aos');
    el.node.removeAttribute('data-aos-easing');
    el.node.removeAttribute('data-aos-duration');
    el.node.removeAttribute('data-aos-delay');

    if (options.initClassName) {
      el.node.classList.remove(options.initClassName);
    }

    if (options.animatedClassName) {
      el.node.classList.remove(options.animatedClassName);
    }
  });
};

/**
 * Check if AOS should be disabled based on provided setting
 */
const isDisabled = function(optionDisable) {
  return (
    optionDisable === true ||
    (optionDisable === 'mobile' && detect.mobile()) ||
    (optionDisable === 'phone' && detect.phone()) ||
    (optionDisable === 'tablet' && detect.tablet()) ||
    (typeof optionDisable === 'function' && optionDisable() === true)
  );
};

/**
 * Initializing AOS
 * - Create options merging defaults with user defined options
 * - Set attributes on <body> as global setting - css relies on it
 * - Attach preparing elements to options.startEvent,
 *   window resize and orientation change
 * - Attach function that handle scroll and everything connected to it
 *   to window scroll event and fire once document is ready to set initial state
 */
const init = function init(settings) {
  options = Object.assign(options, settings);

  // Create initial array with elements -> to be fullfilled later with prepare()
  $aosElements = elements();

  /**
   * Disable mutation observing if not supported
   */
  if (!options.disableMutationObserver && !observer.isSupported()) {
    console.info(`
      aos: MutationObserver is not supported on this browser,
      code mutations observing has been disabled.
      You may have to call "refreshHard()" by yourself.
    `);
    options.disableMutationObserver = true;
  }

  /**
   * Observe [aos] elements
   * If something is loaded by AJAX
   * it'll refresh plugin automatically
   */
  if (!options.disableMutationObserver) {
    observer.ready('[data-aos]', refreshHard);
  }

  /**
   * Don't init plugin if option `disable` is set
   * or when browser is not supported
   */
  if (isDisabled(options.disable) || isBrowserNotSupported()) {
    return disable();
  }

  /**
   * Set global settings on body, based on options
   * so CSS can use it
   */
  document
    .querySelector('body')
    .setAttribute('data-aos-easing', options.easing);

  document
    .querySelector('body')
    .setAttribute('data-aos-duration', options.duration);

  document.querySelector('body').setAttribute('data-aos-delay', options.delay);

  /**
   * Handle initializing
   */
  if (['DOMContentLoaded', 'load'].indexOf(options.startEvent) === -1) {
    // Listen to options.startEvent and initialize AOS
    document.addEventListener(options.startEvent, function() {
      refresh(true);
    });
  } else {
    window.addEventListener('load', function() {
      refresh(true);
    });
  }

  if (
    options.startEvent === 'DOMContentLoaded' &&
    ['complete', 'interactive'].indexOf(document.readyState) > -1
  ) {
    // Initialize AOS if default startEvent was already fired
    refresh(true);
  }

  /**
   * Refresh plugin on window resize or orientation change
   */
  window.addEventListener(
    'resize',
    debounce(refresh, options.debounceDelay, true)
  );

  window.addEventListener(
    'orientationchange',
    debounce(refresh, options.debounceDelay, true)
  );

  return $aosElements;
};

/**
 * Export Public API
 */

export default {
  init,
  refresh,
  refreshHard
};


================================================
FILE: src/js/helpers/detector.js
================================================
/**
 * Device detector
 */

const fullNameRe = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i;
const prefixRe = /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i;
const fullNameMobileRe = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i;
const prefixMobileRe = /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i;

function ua() {
  return navigator.userAgent || navigator.vendor || window.opera || '';
}

class Detector {
  phone() {
    const a = ua();
    return !!(fullNameRe.test(a) || prefixRe.test(a.substr(0, 4)));
  }

  mobile() {
    const a = ua();
    return !!(fullNameMobileRe.test(a) || prefixMobileRe.test(a.substr(0, 4)));
  }

  tablet() {
    return this.mobile() && !this.phone();
  }

  // http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c
  ie11() {
    return (
      '-ms-scroll-limit' in document.documentElement.style &&
      '-ms-ime-align' in document.documentElement.style
    );
  }
}

export default new Detector();


================================================
FILE: src/js/helpers/elements.js
================================================
/**
 * Generate initial array with elements as objects
 * This array will be extended later with elements attributes values
 * like 'position'
 */
export default () => {
  const elements = document.querySelectorAll('[data-aos]');
  return Array.prototype.map.call(elements, node => ({ node }));
};


================================================
FILE: src/js/helpers/getInlineOption.js
================================================
/**
 * Get inline option with a fallback.
 *
 * @param  {Node} el [Dom element]
 * @param  {String} key [Option key]
 * @param  {String} fallback [Default (fallback) value]
 * @return {Mixed} [Option set with inline attributes or fallback value if not set]
 */

export default (el, key, fallback) => {
  const attr = el.getAttribute('data-aos-' + key);

  if (typeof attr !== 'undefined') {
    if (attr === 'true') {
      return true;
    } else if (attr === 'false') {
      return false;
    }
  }

  return attr || fallback;
};


================================================
FILE: src/js/helpers/handleScroll.js
================================================
import detect from './detector';

/**
 * Adds multiple classes on node
 * @param {DOMNode} node
 * @param {array}  classes
 */
const addClasses = (node, classes) =>
  classes && classes.forEach(className => node.classList.add(className));

/**
 * Removes multiple classes from node
 * @param {DOMNode} node
 * @param {array}  classes
 */
const removeClasses = (node, classes) =>
  classes && classes.forEach(className => node.classList.remove(className));

const fireEvent = (eventName, data) => {
  let customEvent;

  if (detect.ie11()) {
    customEvent = document.createEvent('CustomEvent');
    customEvent.initCustomEvent(eventName, true, true, { detail: data });
  } else {
    customEvent = new CustomEvent(eventName, {
      detail: data
    });
  }

  return document.dispatchEvent(customEvent);
};

/**
 * Set or remove aos-animate class
 * @param {node} el         element
 * @param {int}  top        scrolled distance
 */
const applyClasses = (el, top) => {
  const { options, position, node, data } = el;

  const hide = () => {
    if (!el.animated) return;

    removeClasses(node, options.animatedClassNames);
    fireEvent('aos:out', node);

    if (el.options.id) {
      fireEvent(`aos:in:${el.options.id}`, node);
    }

    el.animated = false;
  };

  const show = () => {
    if (el.animated) return;

    addClasses(node, options.animatedClassNames);

    fireEvent('aos:in', node);
    if (el.options.id) {
      fireEvent(`aos:in:${el.options.id}`, node);
    }

    el.animated = true;
  };

  if (options.mirror && top >= position.out && !options.once) {
    hide();
  } else if (top >= position.in) {
    show();
  } else if (el.animated && !options.once) {
    hide();
  }
};

/**
 * Scroll logic - add or remove 'aos-animate' class on scroll
 *
 * @param  {array} $elements         array of elements nodes
 * @return {void}
 */
const handleScroll = $elements =>
  $elements.forEach((el, i) => applyClasses(el, window.pageYOffset));

export default handleScroll;


================================================
FILE: src/js/helpers/offsetCalculator.js
================================================
/**
 * Calculate offset
 * basing on element's settings like:
 * - anchor
 * - offset
 *
 * @param  {Node} el [Dom element]
 * @return {Integer} [Final offset that will be used to trigger animation in good position]
 */

import getOffset from './../libs/offset';
import getInlineOption from './getInlineOption';

export const getPositionIn = (el, defaultOffset, defaultAnchorPlacement) => {
  const windowHeight = window.innerHeight;
  const anchor = getInlineOption(el, 'anchor');
  const inlineAnchorPlacement = getInlineOption(el, 'anchor-placement');
  const additionalOffset = Number(
    getInlineOption(el, 'offset', inlineAnchorPlacement ? 0 : defaultOffset)
  );
  const anchorPlacement = inlineAnchorPlacement || defaultAnchorPlacement;
  let finalEl = el;

  if (anchor && document.querySelectorAll(anchor)) {
    finalEl = document.querySelectorAll(anchor)[0];
  }

  let triggerPoint = getOffset(finalEl).top - windowHeight;

  switch (anchorPlacement) {
    case 'top-bottom':
      // Default offset
      break;
    case 'center-bottom':
      triggerPoint += finalEl.offsetHeight / 2;
      break;
    case 'bottom-bottom':
      triggerPoint += finalEl.offsetHeight;
      break;
    case 'top-center':
      triggerPoint += windowHeight / 2;
      break;
    case 'center-center':
      triggerPoint += windowHeight / 2 + finalEl.offsetHeight / 2;
      break;
    case 'bottom-center':
      triggerPoint += windowHeight / 2 + finalEl.offsetHeight;
      break;
    case 'top-top':
      triggerPoint += windowHeight;
      break;
    case 'bottom-top':
      triggerPoint += windowHeight + finalEl.offsetHeight;
      break;
    case 'center-top':
      triggerPoint += windowHeight + finalEl.offsetHeight / 2;
      break;
  }

  return triggerPoint + additionalOffset;
};

export const getPositionOut = (el, defaultOffset) => {
  const windowHeight = window.innerHeight;
  const anchor = getInlineOption(el, 'anchor');
  const additionalOffset = getInlineOption(el, 'offset', defaultOffset);
  let finalEl = el;

  if (anchor && document.querySelectorAll(anchor)) {
    finalEl = document.querySelectorAll(anchor)[0];
  }

  const elementOffsetTop = getOffset(finalEl).top;

  return elementOffsetTop + finalEl.offsetHeight - additionalOffset;
};


================================================
FILE: src/js/helpers/prepare.js
================================================
/* Clearing variables */

import { getPositionIn, getPositionOut } from './offsetCalculator';
import getInlineOption from './getInlineOption';

const prepare = function($elements, options) {
  $elements.forEach((el, i) => {
    const mirror = getInlineOption(el.node, 'mirror', options.mirror);
    const once = getInlineOption(el.node, 'once', options.once);
    const id = getInlineOption(el.node, 'id');
    const customClassNames =
      options.useClassNames && el.node.getAttribute('data-aos');

    const animatedClassNames = [options.animatedClassName]
      .concat(customClassNames ? customClassNames.split(' ') : [])
      .filter(className => typeof className === 'string');

    if (options.initClassName) {
      el.node.classList.add(options.initClassName);
    }

    el.position = {
      in: getPositionIn(el.node, options.offset, options.anchorPlacement),
      out: mirror && getPositionOut(el.node, options.offset)
    };

    el.options = {
      once,
      mirror,
      animatedClassNames,
      id
    };
  });

  return $elements;
};

export default prepare;


================================================
FILE: src/js/libs/observer.js
================================================
let callback = () => {};

function containsAOSNode(nodes) {
  let i, currentNode, result;

  for (i = 0; i < nodes.length; i += 1) {
    currentNode = nodes[i];

    if (currentNode.dataset && currentNode.dataset.aos) {
      return true;
    }

    result = currentNode.children && containsAOSNode(currentNode.children);

    if (result) {
      return true;
    }
  }

  return false;
}

function check(mutations) {
  if (!mutations) return;

  mutations.forEach(mutation => {
    const addedNodes = Array.prototype.slice.call(mutation.addedNodes);
    const removedNodes = Array.prototype.slice.call(mutation.removedNodes);
    const allNodes = addedNodes.concat(removedNodes);

    if (containsAOSNode(allNodes)) {
      return callback();
    }
  });
}

function getMutationObserver() {
  return (
    window.MutationObserver ||
    window.WebKitMutationObserver ||
    window.MozMutationObserver
  );
}

function isSupported() {
  return !!getMutationObserver();
}

function ready(selector, fn) {
  const doc = window.document;
  const MutationObserver = getMutationObserver();

  const observer = new MutationObserver(check);
  callback = fn;

  observer.observe(doc.documentElement, {
    childList: true,
    subtree: true,
    removedNodes: true
  });
}

export default { isSupported, ready };


================================================
FILE: src/js/libs/offset.js
================================================
/**
 * Get offset of DOM element
 * like there were no transforms applied on it
 *
 * @param  {Node} el [DOM element]
 * @return {Object} [top and left offset]
 */
const offset = function(el) {
  let _x = 0;
  let _y = 0;

  while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
    _x += el.offsetLeft - (el.tagName != 'BODY' ? el.scrollLeft : 0);
    _y += el.offsetTop - (el.tagName != 'BODY' ? el.scrollTop : 0);
    el = el.offsetParent;
  }

  return {
    top: _y,
    left: _x
  };
};

export default offset;


================================================
FILE: src/sass/_animations.scss
================================================
// Animations variables
$aos-distance: 100px !default;

@media screen {
  html:not(.no-js) {
    /**
    * Fade animations:
    * fade
    * fade-up, fade-down, fade-left, fade-right
    * fade-up-right, fade-up-left, fade-down-right, fade-down-left
    */

    [data-aos^='fade'][data-aos^='fade'] {
      opacity: 0;
      transition-property: opacity, transform;

      &.aos-animate {
        opacity: 1;
        transform: none;
      }
    }

    [data-aos='fade-up'] {
      transform: translate3d(0, $aos-distance, 0);
    }

    [data-aos='fade-down'] {
      transform: translate3d(0, -$aos-distance, 0);
    }

    [data-aos='fade-right'] {
      transform: translate3d(-$aos-distance, 0, 0);
    }

    [data-aos='fade-left'] {
      transform: translate3d($aos-distance, 0, 0);
    }

    [data-aos='fade-up-right'] {
      transform: translate3d(-$aos-distance, $aos-distance, 0);
    }

    [data-aos='fade-up-left'] {
      transform: translate3d($aos-distance, $aos-distance, 0);
    }

    [data-aos='fade-down-right'] {
      transform: translate3d(-$aos-distance, -$aos-distance, 0);
    }

    [data-aos='fade-down-left'] {
      transform: translate3d($aos-distance, -$aos-distance, 0);
    }




    /**
    * Zoom animations:
    * 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
    */

    [data-aos^='zoom'][data-aos^='zoom'] {
      opacity: 0;
      transition-property: opacity, transform;

      &.aos-animate {
        opacity: 1;
        transform: translate3d(0, 0, 0) scale(1);
      }
    }

    [data-aos='zoom-in'] {
      transform: scale(.6);
    }

    [data-aos='zoom-in-up'] {
      transform: translate3d(0, $aos-distance, 0) scale(.6);
    }

    [data-aos='zoom-in-down'] {
      transform: translate3d(0, -$aos-distance, 0) scale(.6);
    }

    [data-aos='zoom-in-right'] {
      transform: translate3d(-$aos-distance, 0, 0) scale(.6);
    }

    [data-aos='zoom-in-left'] {
      transform: translate3d($aos-distance, 0, 0) scale(.6);
    }

    [data-aos='zoom-out'] {
      transform: scale(1.2);
    }

    [data-aos='zoom-out-up'] {
      transform: translate3d(0, $aos-distance, 0) scale(1.2);
    }

    [data-aos='zoom-out-down'] {
      transform: translate3d(0, -$aos-distance, 0) scale(1.2);
    }

    [data-aos='zoom-out-right'] {
      transform: translate3d(-$aos-distance, 0, 0) scale(1.2);
    }

    [data-aos='zoom-out-left'] {
      transform: translate3d($aos-distance, 0, 0) scale(1.2);
    }




    /**
    * Slide animations
    */

    [data-aos^='slide'][data-aos^='slide'] {
      transition-property: transform;
      visibility: hidden;

      &.aos-animate {
        visibility: visible;
        transform: translate3d(0, 0, 0);
      }
    }

    [data-aos='slide-up'] {
      transform: translate3d(0, 100%, 0);
    }

    [data-aos='slide-down'] {
      transform: translate3d(0, -100%, 0);
    }

    [data-aos='slide-right'] {
      transform: translate3d(-100%, 0, 0);
    }

    [data-aos='slide-left'] {
      transform: translate3d(100%, 0, 0);
    }




    /**
    * Flip animations:
    * flip-left, flip-right, flip-up, flip-down
    */

    [data-aos^='flip'][data-aos^='flip'] {
      backface-visibility: hidden;
      transition-property: transform;
    }

    [data-aos='flip-left'] {
      transform: perspective(2500px) rotateY(-100deg);
      &.aos-animate {transform: perspective(2500px) rotateY(0);}
    }

    [data-aos='flip-right'] {
      transform: perspective(2500px) rotateY(100deg);
      &.aos-animate {transform: perspective(2500px) rotateY(0);}
    }

    [data-aos='flip-up'] {
      transform: perspective(2500px) rotateX(-100deg);
      &.aos-animate {transform: perspective(2500px) rotateX(0);}
    }

    [data-aos='flip-down'] {
      transform: perspective(2500px) rotateX(100deg);
      &.aos-animate {transform: perspective(2500px) rotateX(0);}
    }
  }
}


================================================
FILE: src/sass/_core.scss
================================================
// Generate Duration && Delay
[data-aos] {
  @for $i from 1 through 60 {
    body[data-aos-duration='#{$i * 50}'] &,
    &[data-aos][data-aos-duration='#{$i * 50}'] {
      transition-duration: #{$i * 50}ms;
    }

    body[data-aos-delay='#{$i * 50}'] &,
    &[data-aos][data-aos-delay='#{$i * 50}'] {
      transition-delay: 0s;

      &.aos-animate {
        transition-delay: #{$i * 50}ms;
      }
    }
  }
}

[data-aos] {
  pointer-events: none;
  &.aos-animate {
    pointer-events: auto;
  }
}


================================================
FILE: src/sass/_easing.scss
================================================
$aos-easing: (
  linear: cubic-bezier(.250, .250, .750, .750),

  ease: cubic-bezier(.250, .100, .250, 1),
  ease-in: cubic-bezier(.420, 0, 1, 1),
  ease-out: cubic-bezier(.000, 0, .580, 1),
  ease-in-out: cubic-bezier(.420, 0, .580, 1),

  ease-in-back: cubic-bezier(.6, -.28, .735, .045),
  ease-out-back: cubic-bezier(.175, .885, .32, 1.275),
  ease-in-out-back: cubic-bezier(.68, -.55, .265, 1.55),

  ease-in-sine: cubic-bezier(.47, 0, .745, .715),
  ease-out-sine: cubic-bezier(.39, .575, .565, 1),
  ease-in-out-sine: cubic-bezier(.445, .05, .55, .95),

  ease-in-quad: cubic-bezier(.55, .085, .68, .53),
  ease-out-quad: cubic-bezier(.25, .46, .45, .94),
  ease-in-out-quad: cubic-bezier(.455, .03, .515, .955),

  ease-in-cubic: cubic-bezier(.55, .085, .68, .53),
  ease-out-cubic: cubic-bezier(.25, .46, .45, .94),
  ease-in-out-cubic: cubic-bezier(.455, .03, .515, .955),

  ease-in-quart: cubic-bezier(.55, .085, .68, .53),
  ease-out-quart: cubic-bezier(.25, .46, .45, .94),
  ease-in-out-quart: cubic-bezier(.455, .03, .515, .955)
);

// Easings implementations
// Default timing function: 'ease'

[data-aos] {
  @each $key, $val in $aos-easing {
    body[data-aos-easing="#{$key}"] &,
    &[data-aos][data-aos-easing="#{$key}"] {
      transition-timing-function: $val;
    }
  }
}


================================================
FILE: src/sass/aos.scss
================================================
@import 'core';
@import 'easing';
@import 'animations';
Download .txt
gitextract_zh9g82gd/

├── .babelrc
├── .editorconfig
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .npmignore
├── .travis.yml
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── cypress/
│   ├── integration/
│   │   ├── aos_spec.js
│   │   ├── js_events_spec.js
│   │   ├── mutation_spec.js
│   │   ├── settings_anchorPlacement_spec.js
│   │   ├── settings_anchor_spec.js
│   │   ├── settings_animatedClassName_spec.js
│   │   ├── settings_delay_spec.js
│   │   ├── settings_disableMutationObserver_spec.js
│   │   ├── settings_disable_spec.js
│   │   ├── settings_duration_spec.js
│   │   ├── settings_easing_spec.js
│   │   ├── settings_initClassName_spec.js
│   │   ├── settings_mirror.js
│   │   ├── settings_offset_spec.js
│   │   ├── settings_once_spec.js
│   │   ├── settings_startEvent_spec.js
│   │   └── settings_useClassNames.js
│   ├── plugins/
│   │   └── index.js
│   └── support/
│       ├── commands.js
│       └── index.js
├── cypress.json
├── demo/
│   ├── anchor.html
│   ├── animatecss.html
│   ├── async.html
│   ├── css/
│   │   └── styles.css
│   ├── index.html
│   ├── offset.html
│   └── once.html
├── package.json
├── rollup.config.js
├── scripts/
│   ├── run-cypress-tests.js
│   └── start-server.js
└── src/
    ├── js/
    │   ├── aos.js
    │   ├── helpers/
    │   │   ├── detector.js
    │   │   ├── elements.js
    │   │   ├── getInlineOption.js
    │   │   ├── handleScroll.js
    │   │   ├── offsetCalculator.js
    │   │   └── prepare.js
    │   └── libs/
    │       ├── observer.js
    │       └── offset.js
    └── sass/
        ├── _animations.scss
        ├── _core.scss
        ├── _easing.scss
        └── aos.scss
Download .txt
SYMBOL INDEX (11 symbols across 2 files)

FILE: src/js/helpers/detector.js
  function ua (line 10) | function ua() {
  class Detector (line 14) | class Detector {
    method phone (line 15) | phone() {
    method mobile (line 20) | mobile() {
    method tablet (line 25) | tablet() {
    method ie11 (line 30) | ie11() {

FILE: src/js/libs/observer.js
  function containsAOSNode (line 3) | function containsAOSNode(nodes) {
  function check (line 23) | function check(mutations) {
  function getMutationObserver (line 37) | function getMutationObserver() {
  function isSupported (line 45) | function isSupported() {
  function ready (line 49) | function ready(selector, fn) {
Condensed preview — 57 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (88K chars).
[
  {
    "path": ".babelrc",
    "chars": 141,
    "preview": "{\n  \"presets\": [\n    [\"env\", {\n      \"modules\": false\n    }]\n  ],\n  \"plugins\": [\n    \"transform-object-assign\",\n    \"ext"
  },
  {
    "path": ".editorconfig",
    "chars": 208,
    "preview": "# editorconfig.org\n\nroot = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_"
  },
  {
    "path": ".eslintrc.json",
    "chars": 220,
    "preview": "{\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true\n  },\n  \"parser\": \"babel-eslint\",\n  \"extends\": [\n    \"plugin:prettier/r"
  },
  {
    "path": ".gitattributes",
    "chars": 222,
    "preview": "# Enforce Unix newlines\n*.css   text eol=lf\n*.scss  text eol=lf\n*.html  text eol=lf\n*.js    text eol=lf\n*.md    text eol"
  },
  {
    "path": ".gitignore",
    "chars": 353,
    "preview": "# Numerous always-ignore extensions\n*.diff\n*.err\n*.log\n*.orig\n*.rej\n*.swo\n*.swp\n*.vi\n*.zip\n*~\n\n# OS or Editor folders\n._"
  },
  {
    "path": ".npmignore",
    "chars": 40,
    "preview": "demo\ntest\nnode_modules\ncypress\n.babelrc\n"
  },
  {
    "path": ".travis.yml",
    "chars": 60,
    "preview": "language: node_js\nsudo: false\nnode_js:\n- 8\n\ninstall:\n- yarn\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1169,
    "preview": "# Contributing to AOS\n\n## Bugs\n\nFound a bug? Have a problem with AOS? Please check past issues, maybe someone already ha"
  },
  {
    "path": "ISSUE_TEMPLATE.md",
    "chars": 866,
    "preview": "<!--- Provide a general summary of the issue in the Title above -->\n\n## This is:\n<!-- Select one -->\n- Bug\n- Feature req"
  },
  {
    "path": "LICENSE",
    "chars": 1081,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Michał Sajnóg\n\nPermission is hereby granted, free of charge, to any person obt"
  },
  {
    "path": "PULL_REQUEST_TEMPLATE.md",
    "chars": 685,
    "preview": "## Related Issue\n<!--- This project only accepts pull requests related to open issues -->\n<!--- If suggesting a new feat"
  },
  {
    "path": "README.md",
    "chars": 10756,
    "preview": "[![AOS - Animate on scroll library](https://s32.postimg.org/ktvt59hol/aos_header.png)](http://michalsnik.github.io/aos/)"
  },
  {
    "path": "cypress/integration/aos_spec.js",
    "chars": 1757,
    "preview": "describe('AOS', function() {\n  before(() => {\n    cy.visit('/');\n    cy.initAOS();\n  });\n\n  it('Should be defined', func"
  },
  {
    "path": "cypress/integration/js_events_spec.js",
    "chars": 1643,
    "preview": "describe('JS Events', function() {\n  context('default events', function() {\n    let aosInStub;\n    let aosOutStub;\n\n    "
  },
  {
    "path": "cypress/integration/mutation_spec.js",
    "chars": 1747,
    "preview": "describe('mutation observer', function() {\n  before(() => {\n    cy.visit('/async.html');\n    cy.initAOS();\n  });\n\n  it('"
  },
  {
    "path": "cypress/integration/settings_anchorPlacement_spec.js",
    "chars": 2011,
    "preview": "describe('setting: anchorPlacement', function() {\n  beforeEach(() => {\n    cy.visit('/index.html');\n    cy.viewport(1280"
  },
  {
    "path": "cypress/integration/settings_anchor_spec.js",
    "chars": 1607,
    "preview": "describe('setting: anchor', function() {\n  before(() => {\n    cy.visit('/anchor.html');\n    cy.viewport(1280, 700);\n    "
  },
  {
    "path": "cypress/integration/settings_animatedClassName_spec.js",
    "chars": 900,
    "preview": "describe('setting: animatedClassName', function() {\n  context('with: \"rawr\"', function() {\n    before(() => {\n      cy.v"
  },
  {
    "path": "cypress/integration/settings_delay_spec.js",
    "chars": 433,
    "preview": "describe('setting: delay', function() {\n  before(() => {\n    cy.visit('/');\n  });\n\n  it('Should set default delay attrib"
  },
  {
    "path": "cypress/integration/settings_disableMutationObserver_spec.js",
    "chars": 598,
    "preview": "describe('setting: disableMutationObserver', function() {\n  before(() => {\n    cy.visit('/async.html');\n    cy.initAOS({"
  },
  {
    "path": "cypress/integration/settings_disable_spec.js",
    "chars": 750,
    "preview": "describe('setting: disable', function() {\n  beforeEach(() => {\n    cy.visit('/');\n  });\n\n  it('Should properly disable A"
  },
  {
    "path": "cypress/integration/settings_duration_spec.js",
    "chars": 455,
    "preview": "describe('setting: duration', function() {\n  before(() => {\n    cy.visit('/');\n  });\n\n  it('Should set default duration "
  },
  {
    "path": "cypress/integration/settings_easing_spec.js",
    "chars": 462,
    "preview": "describe('setting: easing', function() {\n  before(() => {\n    cy.visit('/');\n  });\n\n  it('Should set default easing attr"
  },
  {
    "path": "cypress/integration/settings_initClassName_spec.js",
    "chars": 666,
    "preview": "describe('setting: initClassName', function() {\n  context('with: \"rawr\"', function() {\n    before(() => {\n      cy.visit"
  },
  {
    "path": "cypress/integration/settings_mirror.js",
    "chars": 1038,
    "preview": "describe('setting: mirror', function() {\n  before(() => {\n    cy.visit('/');\n    cy.viewport(1280, 650);\n    cy.initAOS("
  },
  {
    "path": "cypress/integration/settings_offset_spec.js",
    "chars": 2338,
    "preview": "describe('setting: offset', function() {\n  context('global', () => {\n    before(() => {\n      cy.visit('/');\n    });\n\n  "
  },
  {
    "path": "cypress/integration/settings_once_spec.js",
    "chars": 1885,
    "preview": "describe('setting: once', function() {\n  context('global', () => {\n    before(() => {\n      cy.visit('/');\n      cy.init"
  },
  {
    "path": "cypress/integration/settings_startEvent_spec.js",
    "chars": 806,
    "preview": "describe('setting: startEvent', function() {\n  beforeEach(() => {\n    cy.visit('/');\n  });\n\n  it('Should allow to initia"
  },
  {
    "path": "cypress/integration/settings_useClassNames.js",
    "chars": 1298,
    "preview": "describe('setting: useClassNames', function() {\n  context('just useClassNames', function() {\n    before(() => {\n      cy"
  },
  {
    "path": "cypress/plugins/index.js",
    "chars": 257,
    "preview": "module.exports = (on, config) => {\n  on('before:browser:launch', (browser = {}, args) => {\n    console.log(browser, args"
  },
  {
    "path": "cypress/support/commands.js",
    "chars": 350,
    "preview": "Cypress.Commands.add('initAOS', settings => {\n  cy.window().then(({ AOS }) => {\n    AOS.init(settings);\n  });\n});\n\nCypre"
  },
  {
    "path": "cypress/support/index.js",
    "chars": 21,
    "preview": "import './commands';\n"
  },
  {
    "path": "cypress.json",
    "chars": 91,
    "preview": "{\n  \"baseUrl\": \"http://127.0.0.1:8080\",\n  \"viewportWidth\": 1280,\n  \"viewportHeight\": 720\n}\n"
  },
  {
    "path": "demo/anchor.html",
    "chars": 2782,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <title>AOS - Animate on scroll library</title>\n    <meta "
  },
  {
    "path": "demo/animatecss.html",
    "chars": 2515,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <title>AOS - Animate on scroll library</title>\n    <meta "
  },
  {
    "path": "demo/async.html",
    "chars": 1136,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <title>AOS - Animate on scroll library</title>\n    <meta "
  },
  {
    "path": "demo/css/styles.css",
    "chars": 2272,
    "preview": "body {\n  font-family: Helvetica,Tahoma;\n}\n\n*,\n*:before,\n*:after {\n  box-sizing: border-box;\n}\n\n.scroll-counter {\n  posit"
  },
  {
    "path": "demo/index.html",
    "chars": 2738,
    "preview": "<!DOCTYPE html>\n<html class=\"no-js\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title>AOS - Animate on scroll library</tit"
  },
  {
    "path": "demo/offset.html",
    "chars": 2896,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <title>AOS - Animate on scroll library</title>\n    <meta "
  },
  {
    "path": "demo/once.html",
    "chars": 2149,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <title>AOS - Animate on scroll library</title>\n    <meta "
  },
  {
    "path": "package.json",
    "chars": 1768,
    "preview": "{\n  \"name\": \"aos\",\n  \"version\": \"3.0.0-beta.6\",\n  \"description\": \"Animate on scroll library\",\n  \"homepage\": \"https://mic"
  },
  {
    "path": "rollup.config.js",
    "chars": 1066,
    "preview": "import resolve from 'rollup-plugin-node-resolve';\nimport commonjs from 'rollup-plugin-commonjs';\nimport babel from 'roll"
  },
  {
    "path": "scripts/run-cypress-tests.js",
    "chars": 180,
    "preview": "const cypress = require('cypress');\nconst server = require('./start-server');\n\ncypress.run().then(({ failures }) => {\n  "
  },
  {
    "path": "scripts/start-server.js",
    "chars": 309,
    "preview": "const liveServer = require('live-server');\n\nconst params = {\n  port: 8080,\n  host: '0.0.0.0',\n  root: './demo',\n  watch:"
  },
  {
    "path": "src/js/aos.js",
    "chars": 5850,
    "preview": "/**\n * *******************************************************\n * AOS (Animate on scroll) - wowjs alternative\n * made to"
  },
  {
    "path": "src/js/helpers/detector.js",
    "chars": 4641,
    "preview": "/**\n * Device detector\n */\n\nconst fullNameRe = /(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|el"
  },
  {
    "path": "src/js/helpers/elements.js",
    "chars": 298,
    "preview": "/**\n * Generate initial array with elements as objects\n * This array will be extended later with elements attributes val"
  },
  {
    "path": "src/js/helpers/getInlineOption.js",
    "chars": 533,
    "preview": "/**\n * Get inline option with a fallback.\n *\n * @param  {Node} el [Dom element]\n * @param  {String} key [Option key]\n * "
  },
  {
    "path": "src/js/helpers/handleScroll.js",
    "chars": 1994,
    "preview": "import detect from './detector';\n\n/**\n * Adds multiple classes on node\n * @param {DOMNode} node\n * @param {array}  class"
  },
  {
    "path": "src/js/helpers/offsetCalculator.js",
    "chars": 2270,
    "preview": "/**\n * Calculate offset\n * basing on element's settings like:\n * - anchor\n * - offset\n *\n * @param  {Node} el [Dom eleme"
  },
  {
    "path": "src/js/helpers/prepare.js",
    "chars": 1086,
    "preview": "/* Clearing variables */\n\nimport { getPositionIn, getPositionOut } from './offsetCalculator';\nimport getInlineOption fro"
  },
  {
    "path": "src/js/libs/observer.js",
    "chars": 1304,
    "preview": "let callback = () => {};\n\nfunction containsAOSNode(nodes) {\n  let i, currentNode, result;\n\n  for (i = 0; i < nodes.lengt"
  },
  {
    "path": "src/js/libs/offset.js",
    "chars": 525,
    "preview": "/**\n * Get offset of DOM element\n * like there were no transforms applied on it\n *\n * @param  {Node} el [DOM element]\n *"
  },
  {
    "path": "src/sass/_animations.scss",
    "chars": 3968,
    "preview": "// Animations variables\n$aos-distance: 100px !default;\n\n@media screen {\n  html:not(.no-js) {\n    /**\n    * Fade animatio"
  },
  {
    "path": "src/sass/_core.scss",
    "chars": 502,
    "preview": "// Generate Duration && Delay\n[data-aos] {\n  @for $i from 1 through 60 {\n    body[data-aos-duration='#{$i * 50}'] &,\n   "
  },
  {
    "path": "src/sass/_easing.scss",
    "chars": 1297,
    "preview": "$aos-easing: (\n  linear: cubic-bezier(.250, .250, .750, .750),\n\n  ease: cubic-bezier(.250, .100, .250, 1),\n  ease-in: cu"
  },
  {
    "path": "src/sass/aos.scss",
    "chars": 56,
    "preview": "@import 'core';\n@import 'easing';\n@import 'animations';\n"
  }
]

About this extraction

This page contains the full source code of the michalsnik/aos GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 57 files (79.1 KB), approximately 25.3k tokens, and a symbol index with 11 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!