Skip to content

Commit

Permalink
docs: create documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mickaelchanrion committed Dec 22, 2023
1 parent bad4dc7 commit bd2809e
Show file tree
Hide file tree
Showing 2 changed files with 245 additions and 16 deletions.
241 changes: 232 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
# data-scroll
# DataScroll

[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![bundle][bundle-src]][bundle-href]
[![Codecov][codecov-src]][codecov-href]
<!-- [![Codecov][codecov-src]][codecov-href] -->

Scroll parallax, animation from/to using data attributes
Easily create responsive parallax effect and scroll animations on any element using data attributes.

- 👀 The element only animates while inside the viewport.
- 🎯 The element will have its normal position when in the middle of the viewport.
- 🎨 Animate any property from/to any value.
- 🌈 Apply breakpoint-specific speeds.
- ⚙️ Customize the data-attribute names (hell, even use classes if you want!).
- 🩻 Add helpful markers during development/troubleshooting
- 🚀 Leverages [GSAP](https://gsap.com/docs/v3/GSAP/) and [ScrollTrigger](https://gsap.com/docs/v3/Plugins/ScrollTrigger/) under the hood.

## Usage

Expand All @@ -25,16 +33,231 @@ pnpm install data-scroll
bun install data-scroll
```

Import:
Import and instantiate:

```ts
import { useDataScroll } from "data-scroll";

useDataScroll();
```

Play around!
```html
<div data-scroll-speed="md:0.5 lg:0.2">Oowee!</div>
```

## Data attributes

By default, the following data attributes are used:

### `data-scroll-speed`

The speed factor at which the element will move.

> - 1 is the default
> - 0 is ignored
> - 0.5 will make that element go at half-speed
> - 2 will make it go twice as fast.
```html
<div data-scroll-speed="0.5">Oowee!</div>
```

#### Responsive speed

You can specify the speed depending on a breakpoint.

```html
<div data-scroll-speed="md:0.5 lg:0.2">Oowee!</div>
```
> In this example, the speed will be 0.5 starting at medium screens and 0.2 starting at large screens.
#### Clamp

Your element is above the fold and you want it to start from its normal position? Use `clamp`!

```html
<div data-scroll-speed="md:clamp(0.5)">Oowee!</div>
```

> If the element is below the fold, clamp will be ignored.
### `data-scroll-from`

The style from which the element will animate from. See it as a `gsap.from()`

> Beware that the value has to be valid JSON. For functions, use the `getFrom` option.
```html
<div data-scroll-from='{"backgroundColor": "black"}'>Oowee!</div>
```

> In this example, the element will animate from a black background color to its original background color.
### `data-scroll-to`

The style to which the element will animate to. See it as a `gsap.to()`

> Beware that the value has to be valid JSON. For functions, use the `getTo` option.
```html
<div data-scroll-from='{"rotate": 360}'>Oowee!</div>
```

> In this example, the element will rotate to 360 degrees.
### `data-scroll-markers`

Add helpful markers for development/troubleshooting. It's ScrollTrigger's markers option.

```html
<div data-scroll-speed="0.5" data-scroll-markers>Oowee!</div>
```

## Options

### autoStart

If `true`, will automatically find and instantiate elements.
If `false`, you will have to instantiate manually.

- type: `boolean`
- default: `true`

```ts
const dataScroll = useDataScroll({
autoStart: false,
});

const targets = document.querySelectorAll<HTMLElement>('[data-scroll-speed]')
for (const target of targets) {
dataScroll.apply(target)
}
```

### screens

The breakpoints used for the `data-scroll-speed` attribute. The defaults are the same as [TailwindCSS](https://tailwindcss.com/docs/breakpoints) but you can customize them.

> Only min-width breakpoints are supported.
- type: `Record<string, string>`
- default:
```ts
{
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
"2xl": '1536px'
}
```

Feel free to have as few or as many screens as you want, naming them in whatever way you’d prefer for your project.

```ts
useDataScroll({
screens: {
'tablet': '640px',
'laptop': '1024px',
'desktop': '1280px',
},
});
```

```html
<div data-scroll-speed="tablet:0.5 laptop:0.2 desktop:0.1">Oowee!</div>
```

### selector

The selector used to find elements to instantiate.
- type: `string`
- default: `[data-scroll-speed],[data-scroll-from],[data-scroll-to]`

```ts
useDataScroll({
selector: '.foo',
});
```

### getSpeed

A function that returns the speed of an element.
- type: `(target: HTMLElement) => string | void`
- default: `(target) => target.dataset.scrollSpeed`

> If you don't want or just can't use the default data-attributes, you can plug your custom logic.
```js
// ESM
import {} from "data-scroll";
Let's say you want to use classes instead of data-attributes:

// CommonJS
const {} = require("data-scroll");
```ts
// Extract from a string the contents inside brackets
function extractValue(value: string) {
const matches = value.match(/\[(.*?)\]/);
if (matches) {
return matches[1].replaceAll("_", " ");
}
return "";
}

useDataScroll({
selector: '[class^="scroll-speed"]',
getSpeed: (target) => {
// Find the class that starts with "scroll-speed"
const value = Array.from(target.classList).find((className) => {
return className.startsWith("scroll-speed"),
});
// Extract the value inside the brackets
if (value) return extractValue(value);
},
})
```

```html
<div class="scroll-speed-[0.5]">Oowee!</div>
<div class="scroll-speed-[0.05_md:0.02]">Oooooowwweeeee!</div>
```

### getFrom

A function that returns the style to animate the element from.
- type: `(target: HTMLElement) => gsap.TweenVars | void`
- default:
```ts
(target: HTMLElement) => {
const data = target.dataset.scrollFrom;
if (data) return JSON.parse(data);
}
```

> You could use predefined animations
```ts
useDataScroll({
getFrom: (target) => {
if (target.classList.contains("rotate-360")) {
return { rotate: 360 };
}
}
})
```

```html
<div data-scroll class="rotate-360"></div>
```

### getTo

A function that returns the style to animate the element to. See [getFrom](#getfrom).

## Roadmap

- [x] documentation
- [ ] tests
- [ ] playground
- [ ] Add data-scroll-progress
- [ ] Add hooks for ScrollTrigger like toggleClass, onEnter, onLeave, etc.

## Development

- Clone this repository
Expand Down
20 changes: 13 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

gsap.registerPlugin(ScrollTrigger)

type Screens = Record<string, string>
export interface UseDataScrollOptions {
autoStart?: boolean
screens?: Screens
selector?: string
getSpeed?: (target: HTMLElement) => string | undefined
getFrom?: (target: HTMLElement) => gsap.TweenVars | undefined
getTo?: (target: HTMLElement) => gsap.TweenVars | undefined
getSpeed?: (target: HTMLElement) => string | void
getFrom?: (target: HTMLElement) => gsap.TweenVars | void
getTo?: (target: HTMLElement) => gsap.TweenVars | void
getUseMarkers?: (target: HTMLElement) => boolean
}

Expand All @@ -31,8 +33,7 @@ let matchMedia: gsap.MatchMedia

function getVariables(element: HTMLElement, dataKey: string) {
const data = element.dataset[dataKey]
if (!data) return
return JSON.parse(data) as gsap.TweenVars
if (data) return JSON.parse(data) as gsap.TweenVars
}

function getMediaQuery(
Expand All @@ -43,7 +44,8 @@ function getMediaQuery(
if (!screens) screens = defaultScreen
if (!screen) {
if (type === 'min') return '(min-width: 0px)'
if (type === 'max') throw new Error('Only min is supported without screen.')
if (type === 'max')
throw new Error('Only the type "min" is allowed if screen is undefined.')
return undefined as never
}

Expand Down Expand Up @@ -205,7 +207,11 @@ function apply(target: HTMLElement, options?: ApplyOptions) {
)

// Prevent the element from being visible before the animation starts
if (speed > 1 && startOffset !== 0) {
if (
speed > 1 &&
startOffset !== 0 &&
ScrollTrigger.positionInViewport(target, 'bottom') > 1
) {
gsap.set(target, {
visibility: 'hidden',
})
Expand Down

0 comments on commit bd2809e

Please sign in to comment.