├── .gitignore ├── .storybook └── main.js ├── README.md ├── package.json ├── renovate.json ├── rollup.config.js ├── src ├── components │ ├── CheckedIcon.svelte │ ├── Switch.svelte │ └── UncheckedIcon.svelte ├── index.js └── utils │ └── index.js ├── stories ├── 1-switch.stories.js └── views │ ├── BasicDefaultSwitchView.svelte │ ├── CustomIconsSwitchView.svelte │ ├── CustomStyleSwitchView.svelte │ ├── DisabledSwitchView.svelte │ └── SmallerHandleSwitchView.svelte └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | storybook-static 4 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ["../stories/**/*.stories.js"], 3 | addons: [ 4 | "@storybook/addon-actions", 5 | "@storybook/addon-links", 6 | "@storybook/addon-storysource", 7 | "@storybook/addon-notes/register", 8 | ], 9 | }; 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # svelte-switch 2 | 3 | [![NPM](https://img.shields.io/npm/v/svelte-switch.svg)](https://www.npmjs.com/package/svelte-switch) 4 | [![npm bundle size (minified + gzip)](https://img.shields.io/bundlephobia/minzip/svelte-switch.svg)](https://www.npmjs.com/package/svelte-switch) 5 | 6 | SvelteJS component for switch or toggle a boolean. User would be able to drag or click for toggling. 7 | 8 | ## Demo 9 | 10 | [Click here for Storybook link](https://svelte-switch.netlify.app/) 11 | 12 | [REPL Link](https://svelte.dev/repl/72a37aee9ae24705b7d874def7e1f270) 13 | 14 | ## Installation 15 | 16 | ``` 17 | npm install svelte-switch 18 | 19 | or 20 | 21 | yarn add svelte-switch 22 | ``` 23 | 24 | ## Usage 25 | 26 | ```svelte 27 | 37 | 38 |

Simple usage

39 | Switch with default style 40 | 41 |
42 | The switch is {checkedValue ? 'on' : 'off'}. 43 | 44 | ``` 45 | 46 | ## API 47 | 48 | ### Props 49 | 50 | | Prop Name | Description | Default Value | 51 | | --------------- | -------------- | ------------------ | 52 | | checked | Required field | undefined | 53 | | disabled | | false | 54 | | offColor | | "#888" | 55 | | onColor | | "#080" | 56 | | offHandleColor | | "#fff" | 57 | | onHandleColor | | "#fff" | 58 | | handleDiameter | | 0 | 59 | | boxShadow | | null | 60 | | activeBoxShadow | | "0 0 2px 3px #3bf" | 61 | | height | | 28 | 62 | | width | | 56 | 63 | | id | | '' | 64 | | containerClass | | '' | 65 | 66 | ### Slots 67 | 68 | | Slot Name | Description | Default Set? | 69 | | ------------- | ----------- | ------------ | 70 | | checkedIcon | | Yes | 71 | | unCheckedIcon | | Yes | 72 | 73 | ### Events 74 | 75 | | Event Name | Description | `event.detail` info | 76 | | ---------- | ----------- | ------------------------- | 77 | | change | | `{event: event, checked}` | 78 | 79 | ### Examples 80 | 81 | [Click here](https://github.com/thecodejack/svelte-switch/tree/master/stories/views) to view stories implementation 82 | 83 | ## Credits 84 | 85 | Component is reimplementation [react-switch](https://github.com/markusenglund/react-switch). Complete credit goes to author and contributors of [react-switch](https://github.com/markusenglund/react-switch). 86 | 87 | ## License 88 | 89 | MIT 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-switch", 3 | "version": "0.0.4", 4 | "description": "Svelte component for toggle button", 5 | "svelte": "src/index.js", 6 | "module": "dist/index.mjs", 7 | "main": "dist/index.js", 8 | "scripts": { 9 | "build": "rollup -c", 10 | "prepublishOnly": "npm run build", 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "storybook": "start-storybook -p 6006", 13 | "build-storybook": "build-storybook" 14 | }, 15 | "author": "thecodejack", 16 | "license": "MIT", 17 | "repository": { 18 | "url": "https://github.com/thecodejack/svelte-switch" 19 | }, 20 | "dependencies": {}, 21 | "devDependencies": { 22 | "@babel/core": "7.12.10", 23 | "@rollup/plugin-commonjs": "17.0.0", 24 | "@rollup/plugin-node-resolve": "11.1.0", 25 | "@storybook/addon-actions": "6.1.14", 26 | "@storybook/addon-links": "6.1.14", 27 | "@storybook/addon-notes": "5.3.21", 28 | "@storybook/addon-storysource": "6.1.14", 29 | "@storybook/addons": "6.1.14", 30 | "@storybook/svelte": "6.1.14", 31 | "babel-loader": "8.2.2", 32 | "rollup": "2.36.2", 33 | "rollup-plugin-svelte": "7.0.0", 34 | "svelte": "3.31.2", 35 | "svelte-loader": "2.13.6" 36 | }, 37 | "keywords": [ 38 | "svelte", 39 | "svelte3", 40 | "svelte-components", 41 | "toggle", 42 | "svelte-switch", 43 | "sveltejs" 44 | ], 45 | "files": [ 46 | "src", 47 | "dist" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import svelte from "rollup-plugin-svelte"; 2 | import resolve from "@rollup/plugin-node-resolve"; 3 | import commonjs from "@rollup/plugin-commonjs"; 4 | import pkg from "./package.json"; 5 | 6 | const name = pkg.name 7 | .replace(/^(@\S+\/)?(svelte-)?(\S+)/, "$3") 8 | .replace(/^\w/, (m) => m.toUpperCase()) 9 | .replace(/-\w/g, (m) => m[1].toUpperCase()); 10 | 11 | export default { 12 | input: "src/index.js", 13 | output: [ 14 | { file: pkg.module, format: "es" }, 15 | { file: pkg.main, format: "umd", name }, 16 | ], 17 | plugins: [svelte(), resolve(), commonjs()], 18 | }; 19 | -------------------------------------------------------------------------------- /src/components/CheckedIcon.svelte: -------------------------------------------------------------------------------- 1 | 6 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/Switch.svelte: -------------------------------------------------------------------------------- 1 | 301 | 302 | 305 | 306 |
307 |
e.preventDefault()}> 312 |
313 | 314 | 315 | 316 |
317 |
318 | 319 | 320 | 321 |
322 |
323 |
e.preventDefault()} 327 | on:mousedown={disabled ? null : onMouseDown} 328 | on:touchstart={disabled ? null : onTouchStart} 329 | on:touchmove={disabled ? null : onTouchMove} 330 | on:touchend={disabled ? null : onTouchEnd} 331 | on:touchcancel={disabled ? null : unsetHasOutline} /> 332 | 342 |
343 | -------------------------------------------------------------------------------- /src/components/UncheckedIcon.svelte: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Switch from "./components/Switch.svelte"; 2 | 3 | export default Switch; 4 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | function createBackgroundColor( 2 | pos, 3 | checkedPos, 4 | uncheckedPos, 5 | offColor, 6 | onColor 7 | ) { 8 | const relativePos = (pos - uncheckedPos) / (checkedPos - uncheckedPos); 9 | if (relativePos === 0) { 10 | return offColor; 11 | } 12 | if (relativePos === 1) { 13 | return onColor; 14 | } 15 | 16 | let newColor = "#"; 17 | for (let i = 1; i < 6; i += 2) { 18 | const offComponent = parseInt(offColor.substr(i, 2), 16); 19 | const onComponent = parseInt(onColor.substr(i, 2), 16); 20 | const weightedValue = Math.round( 21 | (1 - relativePos) * offComponent + relativePos * onComponent 22 | ); 23 | let newComponent = weightedValue.toString(16); 24 | if (newComponent.length === 1) { 25 | newComponent = `0${newComponent}`; 26 | } 27 | newColor += newComponent; 28 | } 29 | return newColor; 30 | } 31 | 32 | function convertShorthandColor(color) { 33 | if (color.length === 7) { 34 | return color; 35 | } 36 | let sixDigitColor = "#"; 37 | for (let i = 1; i < 4; i += 1) { 38 | sixDigitColor += color[i] + color[i]; 39 | } 40 | return sixDigitColor; 41 | } 42 | 43 | export default function getBackgroundColor( 44 | pos, 45 | checkedPos, 46 | uncheckedPos, 47 | offColor, 48 | onColor 49 | ) { 50 | const sixDigitOffColor = convertShorthandColor(offColor); 51 | const sixDigitOnColor = convertShorthandColor(onColor); 52 | return createBackgroundColor( 53 | pos, 54 | checkedPos, 55 | uncheckedPos, 56 | sixDigitOffColor, 57 | sixDigitOnColor 58 | ); 59 | } 60 | -------------------------------------------------------------------------------- /stories/1-switch.stories.js: -------------------------------------------------------------------------------- 1 | import { action } from "@storybook/addon-actions"; 2 | 3 | import BasicDefaultSwitchView from "./views/BasicDefaultSwitchView.svelte"; 4 | import DisabledSwitchView from "./views/DisabledSwitchView.svelte"; 5 | import CustomStyleSwitchView from "./views/CustomStyleSwitchView.svelte"; 6 | import SmallerHandleSwitchView from "./views/SmallerHandleSwitchView.svelte"; 7 | import CustomIconsSwitchView from "./views/CustomIconsSwitchView.svelte"; 8 | 9 | import intro from "./../README.md"; 10 | 11 | export default { 12 | title: "Examples", 13 | parameters: { 14 | notes: { Introduction: intro }, 15 | }, 16 | }; 17 | 18 | export const BasicDefaultSwitch = () => ({ 19 | Component: BasicDefaultSwitchView, 20 | props: {}, 21 | }); 22 | 23 | export const DisabledSwitch = () => ({ 24 | Component: DisabledSwitchView, 25 | props: {}, 26 | }); 27 | 28 | export const CustomStyleSwitch = () => ({ 29 | Component: CustomStyleSwitchView, 30 | props: {}, 31 | }); 32 | 33 | export const SmallerHandleSwitch = () => ({ 34 | Component: SmallerHandleSwitchView, 35 | props: {}, 36 | }); 37 | 38 | export const CustomIconsSwitch = () => ({ 39 | Component: CustomIconsSwitchView, 40 | props: {}, 41 | }); 42 | -------------------------------------------------------------------------------- /stories/views/BasicDefaultSwitchView.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |

Simple usage

13 | Switch with default style 14 | 15 |
16 | The switch is {checkedValue ? 'on' : 'off'}. 17 | -------------------------------------------------------------------------------- /stories/views/CustomIconsSwitchView.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |

Custom Icons

13 | Switch with default style 14 | 15 |
19 | Off 20 |
21 | 27 | 28 | 29 |
30 |
31 | The switch is {checkedValue ? 'on' : 'off'}. 32 | -------------------------------------------------------------------------------- /stories/views/CustomStyleSwitchView.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |

Custom styling

13 | Switch with style inspired by Material Design 14 | 27 | 28 | 29 | 30 |
31 | The switch is {checkedValue ? 'on' : 'off'}. 32 |
33 |
34 | Icons are removed by passing empty named slots 35 | -------------------------------------------------------------------------------- /stories/views/DisabledSwitchView.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |

Disabled Switch

13 | 14 |
15 | The switch is {checkedValue ? 'on' : 'off'}. 16 | -------------------------------------------------------------------------------- /stories/views/SmallerHandleSwitchView.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |

Smaller Handle

13 | Thick switch with smaller handle radius 14 | 26 |
27 | The switch is {checkedValue ? 'on' : 'off'}. 28 | --------------------------------------------------------------------------------