├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .github
└── workflows
│ ├── build.yml
│ └── tests.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── __tests__
├── slider.spec.ts
└── utils.spec.ts
├── examples
├── cdn
│ ├── index.html
│ └── style.css
└── esm
│ ├── .babelrc
│ ├── .postcssrc
│ ├── package-lock.json
│ ├── package.json
│ └── src
│ ├── css
│ └── app.scss
│ ├── index.html
│ └── js
│ ├── cursor.js
│ └── index.js
├── jest.config.js
├── old.eslintrc.json
├── package-lock.json
├── package.json
├── rollup.config.js
└── src
├── autoInit.ts
├── index.ts
├── interfaces
└── options.ts
├── slider.ts
└── utils.ts
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "modules": false,
7 | "targets": {
8 | "browsers": "> 0.25%, ie 11, not op_mini all, not dead"
9 | }
10 | }
11 | ]
12 | ],
13 | "plugins": [
14 | "@babel/plugin-proposal-class-properties",
15 | "@babel/plugin-proposal-optional-chaining"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailling_whitespace = true
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2020": true,
5 | "jest/globals": true
6 | },
7 | "extends": ["standard", "prettier"],
8 | "parser": "@typescript-eslint/parser",
9 | "parserOptions": {
10 | "ecmaVersion": 11,
11 | "sourceType": "module"
12 | },
13 | "plugins": ["@typescript-eslint", "jest", "prettier"],
14 | "rules": {
15 | "strict": 0,
16 | "prettier/prettier": "error"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | lint:
7 | name: Linting
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: 'Checkout'
11 | uses: actions/checkout@v2
12 |
13 | - name: Set up Node.js
14 | uses: actions/setup-node@v1
15 | with:
16 | node-version: 12
17 |
18 | - name: Install Node.js dependencies
19 | run: npm ci
20 |
21 | - name: Lint
22 | run: npm run lint
23 |
24 | - name: Build
25 | run: npm run build
26 |
27 | build:
28 | name: Building
29 | needs: lint
30 | runs-on: ubuntu-latest
31 | steps:
32 | - name: 'Checkout'
33 | uses: actions/checkout@v2
34 |
35 | - name: Set up Node.js
36 | uses: actions/setup-node@v1
37 | with:
38 | node-version: 12
39 |
40 | - name: Install Node.js dependencies
41 | run: npm ci
42 |
43 | - name: Build
44 | run: npm run build
45 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | test:
7 | name: Testing
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: 'Checkout'
11 | uses: actions/checkout@v2
12 |
13 | - name: Set up Node.js
14 | uses: actions/setup-node@v1
15 | with:
16 | node-version: 12
17 |
18 | - name: Install Node.js dependencies
19 | run: npm ci
20 |
21 | - name: Test
22 | run: npm run test
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .cache
2 | node_modules
3 | .env
4 | .DS_Store
5 | dev
6 | dist
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "tabWidth": 2,
4 | "singleQuote": true
5 | }
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.alwaysShowStatus": true,
3 | "javascript.validate.enable": false,
4 | "editor.formatOnSave": true,
5 | "editor.tabSize": 2,
6 | "[javascript]": {
7 | "editor.formatOnSave": false
8 | },
9 | "[typescript]": {
10 | "editor.formatOnSave": false
11 | },
12 | "[html]": {
13 | "editor.formatOnSave": true
14 | },
15 | "editor.codeActionsOnSave": {
16 | "source.fixAll": true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Armand Sallé
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 🚨 ❌❌❌ 🚨
2 |
3 | ⚠️⚠️⚠️
4 |
5 | Butter Slider is no more maintained! Please use another slider tool or fork it and tweak it. The code is not good and performances are bad, but it was fun to do
6 |
7 | ⚠️⚠️⚠️
8 |
9 | 🚨 ❌❌❌ 🚨
10 |
11 | # Butter Slider
12 |
13 | [](http://makeapullrequest.com) [](https://github.com/armandsalle/Slider/actions) [](https://www.npmjs.com/package/butter-slider)
14 |
15 | A [smooth, simple, lightweight, vanilla JS, no dependencies] drag and hold slider, made for easy setup.
16 |
17 | Simple demo on [CodeSandbox](https://codesandbox.io/s/butter-slider-demo-rwxwi)
18 |
19 | ## Install
20 |
21 | With NPM or Yarn
22 |
23 | ```
24 | # With NPM
25 | npm i --save butter-slider
26 |
27 | # With Yarn
28 | yarn add butter-slider
29 | ```
30 |
31 | With a CDN
32 |
33 | ```html
34 |
35 |
36 |
37 |
38 |
39 | ```
40 |
41 | Imports and init
42 |
43 | ```js
44 | // With imports
45 | import { CreateSlider, autoInit } from 'butter-slider'
46 |
47 | const reallyCoolSlider = new CreateSlider(...)
48 | const autoInitSlider = autoInit()
49 | ```
50 |
51 | ```js
52 | // Without imports
53 | const reallyCoolSlider = new butterSlider.CreateSlider(...)
54 | const autoInitSlider = butterSlider.autoInit()
55 | ```
56 |
57 | ## Usage
58 |
59 | There are 2 ways to use it. With pure javascript or with data-attributes directly on your HTML.
60 |
61 | ### With data-attributes and auto init
62 |
63 | `autoButter` can be used only with data attributes and return an array with your sliders in it.
64 |
65 | For auto init to works you need `data-butter-container` and `data-butter-slidable`. Value passed on the two data attributes need to be the same to works.
66 |
67 | **Required**
68 |
69 | ```html
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
81 | ```
82 |
83 | **Options with data attributes**
84 |
85 | You can pass params with `data-butter-NAME-options`. You have access to 3 params : **smoothAmount**, **dragSpeed** and **hasTouchEvent**
86 |
87 | ```html
88 |
91 | ```
92 |
93 | **Progress bar**
94 |
95 | If you want a simple progress bar add `data-butter-progress` on the element you want to anime with ease the width with the scroll amount.
96 |
97 | ```html
98 |
99 |
100 |
101 | ```
102 |
103 | ### Or with plain vanilla js
104 |
105 | ```js
106 | // ES6 way
107 | import { CreateSlider } from 'butter-slider'
108 |
109 | const mySlider = new CreateSlider({
110 | container: '.slider-container', // Where to listen events
111 | slider: '.slider-items', // What to move
112 | })
113 |
114 | // No modules way
115 | const mySlider = new butterSlider.CreateSlider({
116 | container: '.slider-container', // Where to listen events
117 | slider: '.slider-items', // What to move
118 | })
119 | ```
120 |
121 | ## Options
122 |
123 | **Params**
124 |
125 | | Name | Type | Default | Required | Description | Data-atributes |
126 | | ---------------- | ---------------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------- | -------------- |
127 | | container | string, DOM element | - | YES | Where to listen events | YES |
128 | | slider | string, DOM element | - | YES | What to move | YES |
129 | | dragSpeed | number, string | 1.00 | - | Amount of speed. Can be a float number | YES |
130 | | smoothAmount | number, string | 0.15 | - | Amount of smooth. Can be a float number | YES |
131 | | hasTouchEvent | bool | False | - | Touch devices have already a hold and drag slider built-in. But if you want to use Butter Slider instead you can. | YES |
132 | | mouseEnter | function | - | - | Call when mouse enter the container. Usefull for cursor effect. | - |
133 | | mouseDown | function | - | - | Call when click in the container. Usefull for cursor effect. | - |
134 | | mouseUp | function | - | - | Call when release the click in the container. Usefull for cursor effect. | - |
135 | | getScrollPercent | function => value in percent | - | - | Call on every frame with the amount of scroll in percent (between 0 and 100). Usefull for custom progress bar. | - |
136 | | setRelativePosition | function => value in pixel | - | - | If you want to use custom arrows to move the slider, this method is for you. But keep in mind, you need to code your own logic. | - |
137 |
138 | **Functions**
139 |
140 | If you want to use arrows, or move the slider by a specif distance, use setRelativePosition!
141 |
142 | ```js
143 | const myArrowTag = document.querySelector('.myArrow')
144 | const mySlider = new butterSlider.CreateSlider({
145 | container: '.slider-container', // Where to listen events
146 | slider: '.slider-items', // What to move
147 | })
148 |
149 | // Each time the arrow is click, the slider will move to 500px
150 | myArrowTag.addEventListener('click', () => {
151 | mySlider.setRelativePosition(500)
152 | })
153 | ```
154 |
155 | If you want to destroy your slider you can cann `destroy()`methods like this
156 |
157 | ```js
158 | const mySlider = new butterSlider.CreateSlider({
159 | container: '.slider-container', // Where to listen events
160 | slider: '.slider-items', // What to move
161 | })
162 |
163 | mySlider.destroy()
164 | ```
165 |
166 | And if you want to init it again you can call `init()`like this
167 |
168 | ```js
169 | mySlider.init()
170 | ```
171 |
172 | It works also with autoInit
173 |
174 | ```js
175 | const sliders = butterSlider.autoInit() // return an array of instances of sliders
176 | sldiers.forEach((el) => {
177 | el.destroy()
178 | // or
179 | el.init()
180 | })
181 | ```
182 |
--------------------------------------------------------------------------------
/__tests__/slider.spec.ts:
--------------------------------------------------------------------------------
1 | import CreateSlider from '../src/slider'
2 |
3 | describe('Test slider.ts', () => {
4 | const container = document.createElement('div')
5 | const wrapper = document.createElement('div')
6 |
7 | test('Should create a basic slider', () => {
8 | const mySlider = new CreateSlider({
9 | container,
10 | slider: wrapper,
11 | })
12 |
13 | expect(mySlider).toBeTruthy()
14 | })
15 |
16 | test('Should not return a slider', () => {
17 | try {
18 | // eslint-disable-next-line no-new
19 | new CreateSlider({ container: '', slider: '' })
20 | } catch (error) {
21 | expect(error).toBeTruthy()
22 | }
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/__tests__/utils.spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | map,
3 | lerp,
4 | checkCallbackType,
5 | getFloatNumber,
6 | capitalizeDataset,
7 | isElement,
8 | } from '../src/utils'
9 |
10 | describe('Test utils.ts', () => {
11 | test('Should map a number', () => {
12 | const mapNumber = map(0.5, 0, 1, 0, 10)
13 |
14 | expect(mapNumber).toBe(5)
15 | })
16 |
17 | test('Should say if it is an HTML element or not', () => {
18 | const myElement = document.createElement('div')
19 | const truthyRes = isElement(myElement)
20 | const falsyRes = isElement('div')
21 |
22 | expect(truthyRes).toBeTruthy()
23 | expect(falsyRes).toBeFalsy()
24 | })
25 |
26 | test('Should output a capitalize dataset', () => {
27 | const dataAtt = capitalizeDataset('butter-slider-cool-dab')
28 | const string = capitalizeDataset('hello')
29 |
30 | expect(dataAtt).toBe('butterSliderCoolDab')
31 | expect(string).toBe('hello')
32 | })
33 |
34 | test('Should give a float number', () => {
35 | const getMaxValue = getFloatNumber(2, 0.15, 0, 1)
36 | const getMinValue = getFloatNumber(0, 1, 0.4567, 5)
37 | const getToFixedValue = getFloatNumber(0.2222222, 0.1, 0, 1)
38 | const getDefaultValue = getFloatNumber('hello', 1, 0, 10)
39 |
40 | expect(getMaxValue).toBe(1)
41 | expect(getToFixedValue).toBe(0.222)
42 | expect(getMinValue).toBe(0.457)
43 | expect(getDefaultValue).toBe(1)
44 | })
45 |
46 | test('Should say if it is a function or note', () => {
47 | const myFunc = function () {}
48 | const myNoFunc = 'This is not a function'
49 | const isFucntion = checkCallbackType(myFunc)
50 | const isNotFucntion = checkCallbackType(myNoFunc)
51 |
52 | expect(isFucntion).toBeTruthy()
53 | expect(isNotFucntion).toBeFalsy()
54 | })
55 |
56 | test('Should give a lerp distance', () => {
57 | expect(lerp(10, 1, 0)).toBe(10)
58 | expect(lerp(0, 1, 0.5)).toBe(0.5)
59 | })
60 |
61 | // Not sure how to test getEvent function
62 | })
63 |
--------------------------------------------------------------------------------
/examples/cdn/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Slider
7 |
8 |
9 |
10 |