├── .eslintrc.cjs
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── BUG_REPORT.yml
│ └── config.yml
└── pull_request_template.md
├── .gitignore
├── LICENSE
├── README.md
├── examples
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── src
│ ├── app.html
│ ├── global.d.ts
│ ├── routes
│ │ ├── components
│ │ │ ├── AutoplayExample.svelte
│ │ │ ├── BasicExample.svelte
│ │ │ ├── DynamicSlidesExample.svelte
│ │ │ ├── ReactivityExample.svelte
│ │ │ ├── ThumbnailsExample.svelte
│ │ │ └── VideoExample.svelte
│ │ └── index.svelte
│ └── utils
│ │ ├── generateSlides
│ │ └── generateSlides.ts
│ │ └── index.ts
├── static
│ └── favicon.png
├── svelte.config.js
└── tsconfig.json
├── images
├── logo.svg
└── svelte-logo.svg
├── package-lock.json
├── package.json
├── scripts
└── copy-css.js
├── src
├── app.html
├── global.d.ts
├── lib
│ ├── components
│ │ ├── Splide
│ │ │ ├── Splide.svelte
│ │ │ └── bind.ts
│ │ ├── SplideSlide
│ │ │ └── SplideSlide.svelte
│ │ ├── SplideTrack
│ │ │ └── SplideTrack.svelte
│ │ └── index.ts
│ ├── index.ts
│ ├── types
│ │ ├── events.ts
│ │ └── index.ts
│ └── utils
│ │ ├── classNames
│ │ └── classNames.ts
│ │ ├── forOwn
│ │ ├── forOwn.ts
│ │ └── test
│ │ │ └── forOwn.test.ts
│ │ ├── getSlides
│ │ └── getSlides.ts
│ │ ├── index.ts
│ │ ├── isEqualDeep
│ │ ├── isEqualDeep.ts
│ │ └── test
│ │ │ └── isEqualDeep.test.ts
│ │ ├── isEqualShallow
│ │ ├── isEqualShallow.ts
│ │ └── test
│ │ │ └── isEqualShallow.test.ts
│ │ ├── isObject
│ │ ├── isObject.ts
│ │ └── test
│ │ │ └── isObject.test.ts
│ │ └── merge
│ │ ├── merge.test.ts
│ │ └── merge.ts
└── routes
│ ├── components
│ └── BasicExample.svelte
│ ├── index.svelte
│ └── utils
│ ├── generateSlides
│ └── generateSlides.ts
│ └── index.ts
├── static
└── favicon.png
├── svelte.config.js
└── tsconfig.json
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root : true,
3 | parser : '@typescript-eslint/parser',
4 | extends : [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended' ],
5 | plugins : [ 'svelte3', '@typescript-eslint' ],
6 | ignorePatterns: [ '*.cjs' ],
7 | overrides : [ { files: [ '*.svelte' ], processor: 'svelte3/svelte3' } ],
8 | settings: {
9 | 'svelte3/typescript': () => require( 'typescript' ),
10 | },
11 | parserOptions: {
12 | sourceType : 'module',
13 | ecmaVersion: 2019,
14 | },
15 | env: {
16 | browser: true,
17 | es2017 : true,
18 | node : true,
19 | },
20 | rules: {
21 | '@typescript-eslint/no-explicit-any': 'off',
22 | '@typescript-eslint/ban-types': 'off',
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: NaotoshiFujita
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG_REPORT.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Create a bug report.
3 | labels: [ "bug" ]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thank you for taking your time to post a bug report!
9 | Please fill out the following form. I might need to close the issue without required fields or e.g. clear repro steps.
10 | - type: checkboxes
11 | attributes:
12 | label: Checks
13 | description: Before posting a report, please check following things.
14 | options:
15 | - label: "Not a duplicate."
16 | required: true
17 | - label: "Not a question, feature request, or anything other than a bug report directly related to Svelte Splide. Use Discussions for these topics: https://github.com/Splidejs/splide/discussions"
18 | required: true
19 | - type: input
20 | id: version
21 | attributes:
22 | label: Version
23 | description: The version where the bug happens.
24 | placeholder: x.x.x
25 | validations:
26 | required: true
27 | - type: textarea
28 | attributes:
29 | label: Description
30 | description: Describe the bug.
31 | placeholder: Provide a clear and precise description. Feel free to paste your code, screenshort, etc.
32 | validations:
33 | required: true
34 | - type: input
35 | id: reproduction-link
36 | attributes:
37 | label: Reproduction Link
38 | description: A link to a reproduction (CodeSandbox, etc.). **Do not link to your project**, it has to be a minimal and fresh reproduction.
39 | placeholder: "https://codesandbox.io/"
40 | validations:
41 | required: false
42 | - type: textarea
43 | attributes:
44 | label: Steps to Reproduce
45 | description: Describe steps how to reproduce the bug.
46 | value: |
47 | 1.
48 | 2.
49 | ...
50 | validations:
51 | required: true
52 | - type: textarea
53 | attributes:
54 | label: Expected Behaviour
55 | description: Describe what you expected to happen.
56 | validations:
57 | required: true
58 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | ## Related Issues
6 |
7 |
10 |
11 | ## Description
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | /.idea
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021 Naotoshi Fujita
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
24 |
25 | ## Quick Start
26 | Get the latest version from NPM:
27 | ```
28 | $ npm install @splidejs/svelte-splide
29 | ```
30 |
31 | Import CSS and components:
32 |
33 | ```svelte
34 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ```
48 |
49 | Visit [this page](https://splidejs.com/integration/svelte-splide) for more details.
50 |
51 |
52 | ## Support Splide
53 |
54 | Please support the project if you like it!
55 | - [GitHub Sponsors](https://github.com/sponsors/NaotoshiFujita)
56 |
57 |
58 | ## License
59 | Svelte Splide and Splide are released under the MIT license.
60 | © 2021 Naotoshi Fujita
61 |
--------------------------------------------------------------------------------
/examples/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
5 | plugins: ['svelte3', '@typescript-eslint'],
6 | ignorePatterns: ['*.cjs'],
7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
8 | settings: {
9 | 'svelte3/typescript': () => require('typescript')
10 | },
11 | parserOptions: {
12 | sourceType: 'module',
13 | ecmaVersion: 2019
14 | },
15 | env: {
16 | browser: true,
17 | es2017: true,
18 | node: true
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/examples/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | Examples for [Svelte Splide](https://github.com/Splidejs/svelte-splide).
--------------------------------------------------------------------------------
/examples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "examples",
3 | "version": "0.0.1",
4 | "scripts": {
5 | "dev": "svelte-kit dev --port 5000",
6 | "build": "svelte-kit build",
7 | "preview": "svelte-kit preview --port 5050",
8 | "check": "svelte-check --tsconfig ./tsconfig.json",
9 | "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
10 | "lint": "eslint --ignore-path .gitignore ."
11 | },
12 | "devDependencies": {
13 | "@sveltejs/adapter-static": "^1.0.0-next.41",
14 | "@sveltejs/kit": "next",
15 | "@typescript-eslint/eslint-plugin": "^5.36.1",
16 | "@typescript-eslint/parser": "^5.36.1",
17 | "eslint": "^8.23.0",
18 | "eslint-plugin-svelte3": "^4.0.0",
19 | "svelte": "^3.49.0",
20 | "svelte-check": "^2.9.0",
21 | "svelte-preprocess": "^4.10.7",
22 | "tslib": "^2.4.0",
23 | "typescript": "^4.8.2"
24 | },
25 | "type": "module",
26 | "dependencies": {
27 | "@splidejs/splide-extension-video": "^0.7.1",
28 | "@splidejs/svelte-splide": "file:../package"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/examples/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | %svelte.head%
11 |
12 |
13 | %svelte.body%
14 |
15 |
16 |
--------------------------------------------------------------------------------
/examples/src/global.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/examples/src/routes/components/AutoplayExample.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
Autoplay
17 |
18 |
19 |
20 |
21 | { #each slides as slide }
22 |
23 |
24 |
25 | { /each }
26 |
27 |
28 |
29 |
33 |
34 |
38 |
39 |
--------------------------------------------------------------------------------
/examples/src/routes/components/BasicExample.svelte:
--------------------------------------------------------------------------------
1 |
18 |
19 |
20 |
Basic
21 |
22 |
console.log( e.detail.splide.length ) }
25 | on:move={ e => console.log( 'move to', e.detail.index ) }
26 | aria-labelledby="basic-example-heading"
27 | class="custom-class"
28 | >
29 | { #each slides as slide }
30 |
31 |
32 |
33 | { /each }
34 |
35 |
--------------------------------------------------------------------------------
/examples/src/routes/components/DynamicSlidesExample.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
Dynamic Slides
25 |
26 |
32 |
33 |
34 | { #each slides as slide }
35 |
36 |
37 |
38 | { /each }
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/examples/src/routes/components/ReactivityExample.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
56 |
57 |
--------------------------------------------------------------------------------
/examples/src/routes/components/ThumbnailsExample.svelte:
--------------------------------------------------------------------------------
1 |
39 |
40 |
41 |
Thumbnails
42 |
43 |
44 | { #each slides as slide }
45 |
46 |
47 |
48 | { /each }
49 |
50 |
51 |
52 | { #each slides as slide }
53 |
54 |
55 |
56 | { /each }
57 |
58 |
--------------------------------------------------------------------------------
/examples/src/routes/components/VideoExample.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
Video
11 |
12 |
17 | { #each videos as id, index }
18 |
19 |
23 |
24 | { /each }
25 |
26 |
--------------------------------------------------------------------------------
/examples/src/routes/index.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/src/utils/generateSlides/generateSlides.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Return an array with objects containing data of sample images.
3 | *
4 | * @param length - Optional. A number of slides.
5 | * @param sig - Optional. The signature for getting a different image.
6 | *
7 | * @return An array with objects for sample images.
8 | */
9 | export function generateSlides( length = 10, sig = 0 ): Array<{ src: string, alt: string }> {
10 | return Array.from( { length } ).map( ( _, index ) => {
11 | index = sig || index;
12 |
13 | return {
14 | src: `https://source.unsplash.com/random/800x450?sig=${ index }`,
15 | alt: `Image ${ index }`,
16 | };
17 | } );
18 | }
19 |
--------------------------------------------------------------------------------
/examples/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { generateSlides } from './generateSlides/generateSlides';
2 |
--------------------------------------------------------------------------------
/examples/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Splidejs/svelte-splide/72d805bdcb32fc738a225d6373853f9b5c710361/examples/static/favicon.png
--------------------------------------------------------------------------------
/examples/svelte.config.js:
--------------------------------------------------------------------------------
1 | import preprocess from 'svelte-preprocess';
2 | import adapter from '@sveltejs/adapter-static';
3 |
4 | const dev = process.env.NODE_ENV === 'development';
5 |
6 | /** @type {import('@sveltejs/kit').Config} */
7 | const config = {
8 | preprocess: preprocess(),
9 |
10 | kit: {
11 | floc : true,
12 | appDir : 'app',
13 | adapter : adapter( {
14 | fallback: '200.html', // dummy
15 | } ),
16 | paths : {
17 | base: dev ? '' : '/svelte-splide',
18 | },
19 | prerender: { entries: [] },
20 | },
21 | };
22 |
23 | export default config;
24 |
--------------------------------------------------------------------------------
/examples/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "moduleResolution": "node",
5 | "module": "es2020",
6 | "lib": [
7 | "es2020",
8 | "DOM"
9 | ],
10 | "target": "es2020",
11 | "importsNotUsedAsValues": "error",
12 | "isolatedModules": true,
13 | "resolveJsonModule": true,
14 | "sourceMap": true,
15 | "esModuleInterop": true,
16 | "skipLibCheck": true,
17 | "forceConsistentCasingInFileNames": true,
18 | "baseUrl": ".",
19 | "allowJs": true,
20 | "checkJs": true,
21 | "paths": {
22 | "$lib": [
23 | "src/lib"
24 | ],
25 | "$lib/*": [
26 | "src/lib/*"
27 | ]
28 | }
29 | },
30 | "include": [
31 | "src/**/*.d.ts",
32 | "src/**/*.js",
33 | "src/**/*.ts",
34 | "src/**/*.svelte"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/images/logo.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/images/svelte-logo.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@splidejs/svelte-splide",
3 | "version": "0.2.9",
4 | "description": "Svelte component for the Splide slider/carousel.",
5 | "author": "Naotoshi Fujita",
6 | "license": "MIT",
7 | "keywords": [
8 | "splide",
9 | "slider",
10 | "carousel",
11 | "slideshow",
12 | "lightweight",
13 | "touch",
14 | "responsive",
15 | "svelte"
16 | ],
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/Splidejs/svelte-splide.git"
20 | },
21 | "bugs": {
22 | "url": "https://github.com/Splidejs/svelte-splide/issues"
23 | },
24 | "scripts": {
25 | "dev": "svelte-kit dev",
26 | "build": "svelte-kit build",
27 | "package": "node scripts/copy-css.js && svelte-kit package",
28 | "preview": "svelte-kit preview --port 3030",
29 | "check": "svelte-check --tsconfig ./tsconfig.json",
30 | "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
31 | "lint": "eslint src",
32 | "deploy": "gh-pages -d examples/build"
33 | },
34 | "devDependencies": {
35 | "@sveltejs/adapter-static": "^1.0.0-next.42",
36 | "@sveltejs/kit": "next",
37 | "@types/jest": "^29.0.0",
38 | "@typescript-eslint/eslint-plugin": "^5.36.2",
39 | "@typescript-eslint/parser": "^5.36.2",
40 | "eslint": "^8.23.0",
41 | "eslint-plugin-svelte3": "^4.0.0",
42 | "fs-extra": "^10.1.0",
43 | "gh-pages": "^4.0.0",
44 | "jest": "next",
45 | "svelte": "^3.50.0",
46 | "svelte-check": "^2.9.0",
47 | "svelte-preprocess": "^4.10.7",
48 | "svelte2tsx": "^0.5.16",
49 | "tslib": "^2.4.0",
50 | "typescript": "^4.8.2"
51 | },
52 | "type": "module",
53 | "exports": {
54 | ".": "./index.js",
55 | "./css": "./css/splide.min.css",
56 | "./css/core": "./css/splide-core.min.css",
57 | "./css/*": "./css/themes/splide-*.min.css"
58 | },
59 | "dependencies": {
60 | "@splidejs/splide": "^4.1.3"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/scripts/copy-css.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs-extra';
2 |
3 | async function copy() {
4 | await fs.copy( './node_modules/@splidejs/splide/dist/css', './src/lib/css', { overwrite: true } );
5 | }
6 |
7 | copy().catch( console.error )
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %svelte.head%
8 |
9 |
10 | %svelte.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/global.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/lib/components/Splide/Splide.svelte:
--------------------------------------------------------------------------------
1 |
139 |
140 |
141 |
142 |
147 | { #if hasTrack }
148 |
149 |
150 |
151 | { :else }
152 |
153 | { /if }
154 |
155 |
--------------------------------------------------------------------------------
/src/lib/components/Splide/bind.ts:
--------------------------------------------------------------------------------
1 | import type { EventMap, Options, Splide } from '@splidejs/splide';
2 | import {
3 | EVENT_ACTIVE,
4 | EVENT_ARROWS_MOUNTED,
5 | EVENT_ARROWS_UPDATED,
6 | EVENT_AUTOPLAY_PAUSE,
7 | EVENT_AUTOPLAY_PLAY,
8 | EVENT_AUTOPLAY_PLAYING,
9 | EVENT_CLICK,
10 | EVENT_DESTROY,
11 | EVENT_DRAG,
12 | EVENT_DRAGGED,
13 | EVENT_DRAGGING,
14 | EVENT_HIDDEN,
15 | EVENT_INACTIVE,
16 | EVENT_LAZYLOAD_LOADED,
17 | EVENT_MOUNTED,
18 | EVENT_MOVE,
19 | EVENT_MOVED,
20 | EVENT_NAVIGATION_MOUNTED,
21 | EVENT_PAGINATION_MOUNTED,
22 | EVENT_PAGINATION_UPDATED,
23 | EVENT_REFRESH,
24 | EVENT_RESIZE,
25 | EVENT_RESIZED,
26 | EVENT_SCROLL,
27 | EVENT_SCROLLED,
28 | EVENT_UPDATED,
29 | EVENT_VISIBLE,
30 | } from '@splidejs/splide';
31 | import type { PaginationData, PaginationItem, SlideComponent } from '@splidejs/splide';
32 |
33 |
34 | const EVENTS_WITHOUT_ARGS: Array = [
35 | EVENT_MOUNTED,
36 | EVENT_REFRESH,
37 | EVENT_RESIZE,
38 | EVENT_RESIZED,
39 | EVENT_DRAG,
40 | EVENT_DRAGGING,
41 | EVENT_DRAGGED,
42 | EVENT_SCROLL,
43 | EVENT_SCROLLED,
44 | EVENT_DESTROY,
45 | EVENT_AUTOPLAY_PLAY,
46 | EVENT_AUTOPLAY_PAUSE,
47 | ];
48 |
49 | /**
50 | * Binds Splide events to the svelte dispatcher.
51 | *
52 | * @since 0.1.0
53 | *
54 | * @param splide - A splide instance.
55 | * @param dispatchFn - A dispatch function created by `createEventDispatcher()`.
56 | */
57 | export function bind any>( splide: Splide, dispatchFn: T ): void {
58 | const dispatch = ( event: keyof EventMap, detail: Record = {} ) => {
59 | dispatchFn( transform( event ), { splide, ...detail } );
60 | };
61 |
62 | splide.on( EVENT_CLICK, ( Slide: SlideComponent, e: MouseEvent ) => {
63 | dispatch( EVENT_CLICK, { Slide, e } );
64 | } );
65 |
66 | splide.on( EVENT_MOVE, ( index: number, prev: number, dest: number ) => {
67 | dispatch( EVENT_MOVE, { index, prev, dest } );
68 | } );
69 |
70 | splide.on( EVENT_MOVED, ( index: number, prev: number, dest: number ) => {
71 | dispatch( EVENT_MOVED, { index, prev, dest } );
72 | } );
73 |
74 | splide.on( EVENT_ACTIVE, ( Slide: SlideComponent ) => {
75 | dispatch( EVENT_ACTIVE, { Slide } );
76 | } );
77 |
78 | splide.on( EVENT_INACTIVE, ( Slide: SlideComponent ) => {
79 | dispatch( EVENT_INACTIVE, { Slide } );
80 | } );
81 |
82 | splide.on( EVENT_VISIBLE, ( Slide: SlideComponent ) => {
83 | dispatch( EVENT_VISIBLE, { Slide } );
84 | } );
85 |
86 | splide.on( EVENT_HIDDEN, ( Slide: SlideComponent ) => {
87 | dispatch( EVENT_HIDDEN, { Slide } );
88 | } );
89 |
90 | splide.on( EVENT_UPDATED, ( options: Options ) => {
91 | dispatch( EVENT_UPDATED, options );
92 | } );
93 |
94 | splide.on( EVENT_ARROWS_MOUNTED, ( prev: HTMLButtonElement, next: HTMLButtonElement ) => {
95 | dispatch( EVENT_ARROWS_MOUNTED, { prev, next } );
96 | } );
97 |
98 | splide.on( EVENT_ARROWS_UPDATED, ( prev: HTMLButtonElement, next: HTMLButtonElement ) => {
99 | dispatch( EVENT_ARROWS_UPDATED, { prev, next } );
100 | } );
101 |
102 | splide.on( EVENT_PAGINATION_MOUNTED, ( data: PaginationData, item: PaginationItem ) => {
103 | dispatch( EVENT_PAGINATION_MOUNTED, { data, item } );
104 | } );
105 |
106 | splide.on( EVENT_PAGINATION_UPDATED, ( data: PaginationData, prev: PaginationItem, curr: PaginationItem ) => {
107 | dispatch( EVENT_PAGINATION_UPDATED, { data, prev, curr } );
108 | } );
109 |
110 | splide.on( EVENT_NAVIGATION_MOUNTED, ( splides: Splide[] ) => {
111 | dispatch( EVENT_NAVIGATION_MOUNTED, { splides } );
112 | } );
113 |
114 | splide.on( EVENT_AUTOPLAY_PLAYING, ( rate: number ) => {
115 | dispatch( EVENT_AUTOPLAY_PLAYING, { rate } );
116 | } );
117 |
118 | splide.on( EVENT_LAZYLOAD_LOADED, ( img: HTMLImageElement, Slide: SlideComponent ) => {
119 | dispatch( EVENT_LAZYLOAD_LOADED, { img, Slide } );
120 | } );
121 |
122 | EVENTS_WITHOUT_ARGS.forEach( event => {
123 | splide.on( event, () => {
124 | dispatch( event );
125 | } );
126 | } );
127 | }
128 |
129 | /**
130 | * Transforms Splide event names to the camel case.
131 | *
132 | * @since 0.1.0
133 | *
134 | * @param event - An event name to transform.
135 | *
136 | * @return A transformed event name.
137 | */
138 | function transform( event: keyof EventMap ): string {
139 | return event.split( ':' )
140 | .map( ( fragment, index ) => {
141 | return index > 0 ? fragment.charAt( 0 ).toUpperCase() + fragment.slice( 1 ) : fragment;
142 | } )
143 | .join( '' )
144 | .replace( 'Lazyload', 'LazyLoad' );
145 | }
--------------------------------------------------------------------------------
/src/lib/components/SplideSlide/SplideSlide.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/components/SplideTrack/SplideTrack.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Splide } from './Splide/Splide.svelte';
2 | export { default as SplideTrack } from './SplideTrack/SplideTrack.svelte';
3 | export { default as SplideSlide } from './SplideSlide/SplideSlide.svelte';
4 |
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | export * from './components';
2 | export type { Options } from '@splidejs/splide';
--------------------------------------------------------------------------------
/src/lib/types/events.ts:
--------------------------------------------------------------------------------
1 | import type { SlideComponent, Splide } from '@splidejs/splide';
2 |
3 |
4 | export type EventDetail = Record> = { splide: Splide } & T;
5 |
6 | export type SlideEventDetail = EventDetail<{ Slide: SlideComponent }>;
7 |
8 | export type ArrowsEventDetail = EventDetail<{ prev: HTMLButtonElement, next: HTMLButtonElement }>;
9 |
10 | export type MoveEventDetail = EventDetail<{ index: number, prev: number, dest: number }>;
--------------------------------------------------------------------------------
/src/lib/types/index.ts:
--------------------------------------------------------------------------------
1 | export * from './events';
--------------------------------------------------------------------------------
/src/lib/utils/classNames/classNames.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Combines valid class names.
3 | *
4 | * @param classes - An array with classes.
5 | *
6 | * @return A concatenated string with provided class names.
7 | */
8 | export function classNames( ...classes: Array ): string {
9 | return classes.filter( Boolean ).join( ' ' );
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/utils/forOwn/forOwn.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Iterates over the provided object by own enumerable keys with calling the iteratee function.
3 | *
4 | * @param object - An object to iterate over.
5 | * @param iteratee - An iteratee function that takes the value and key as arguments.
6 | *
7 | * @return A provided object itself.
8 | */
9 | export function forOwn(
10 | object: T,
11 | iteratee: ( value: T[ keyof T ], key: keyof T ) => boolean | void
12 | ): T {
13 | if ( object ) {
14 | const keys = Object.keys( object ) as Array;
15 |
16 | for ( let i = 0; i < keys.length; i++ ) {
17 | const key = keys[ i ];
18 |
19 | if ( key !== '__proto__' ) {
20 | if ( iteratee( object[ key ], key ) === false ) {
21 | break;
22 | }
23 | }
24 | }
25 | }
26 |
27 | return object;
28 | }
29 |
--------------------------------------------------------------------------------
/src/lib/utils/forOwn/test/forOwn.test.ts:
--------------------------------------------------------------------------------
1 | import { forOwn } from '../forOwn';
2 |
3 |
4 | describe( 'forOwn', () => {
5 | test( 'can iterate an object by own enumerable properties.', () => {
6 | const object = { a: 1, b: 2, c: 3 };
7 | let counter = 0;
8 |
9 | forOwn( object, ( value, key ) => {
10 | counter++;
11 | expect( object[ key ] ).toBe( value );
12 | } );
13 |
14 | expect( counter ).toBe( Object.keys( object ).length );
15 | } );
16 |
17 | test( 'should not handle inherited properties.', () => {
18 | class Constructor {
19 | a = 1;
20 | b = 2;
21 | }
22 |
23 | ( Constructor as any ).prototype[ 'c' ] = 3;
24 |
25 | const object: any = {};
26 |
27 | forOwn( new Constructor(), ( value, key ) => {
28 | object[ key ] = value;
29 | } );
30 |
31 | expect( object ).toStrictEqual( { a: 1, b: 2 } );
32 | } );
33 | } );
34 |
--------------------------------------------------------------------------------
/src/lib/utils/getSlides/getSlides.ts:
--------------------------------------------------------------------------------
1 | import type { Splide } from '@splidejs/splide';
2 |
3 |
4 | export function getSlides( splide: Splide ): HTMLElement[] {
5 | const children = splide.Components.Elements?.list.children;
6 | return children && Array.prototype.slice.call( children ) || [];
7 | }
--------------------------------------------------------------------------------
/src/lib/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { classNames } from './classNames/classNames';
2 | export { forOwn } from './forOwn/forOwn';
3 | export { getSlides } from './getSlides/getSlides';
4 | export { isEqualDeep } from './isEqualDeep/isEqualDeep';
5 | export { isEqualShallow } from './isEqualShallow/isEqualShallow';
6 | export { isObject } from './isObject/isObject';
7 | export { merge } from './merge/merge';
8 |
--------------------------------------------------------------------------------
/src/lib/utils/isEqualDeep/isEqualDeep.ts:
--------------------------------------------------------------------------------
1 | import { isObject } from '../isObject/isObject';
2 |
3 |
4 | /**
5 | * Checks if provided two arrays are shallowly equal or not.
6 | *
7 | * @param subject1 - An array to test.
8 | * @param subject2 - Anther array to test.
9 | *
10 | * @return `true` if they are considered as equal, or otherwise `false`.
11 | */
12 | export function isEqualDeep( subject1: unknown, subject2: unknown ): boolean {
13 | if ( Array.isArray( subject1 ) && Array.isArray( subject2 ) ) {
14 | return subject1.length === subject2.length
15 | && ! subject1.some( ( elm, index ) => ! isEqualDeep( elm, subject2[ index ] ) );
16 | }
17 |
18 | if ( isObject( subject1 ) && isObject( subject2 ) ) {
19 | const keys1 = Object.keys( subject1 ) as Array;
20 | const keys2 = Object.keys( subject2 );
21 |
22 | return keys1.length === keys2.length && ! keys1.some( key => {
23 | return ! Object.prototype.hasOwnProperty.call( subject2, key )
24 | || ! isEqualDeep( subject1[ key ], subject2[ key ] );
25 | } );
26 | }
27 |
28 | return subject1 === subject2;
29 | }
30 |
--------------------------------------------------------------------------------
/src/lib/utils/isEqualDeep/test/isEqualDeep.test.ts:
--------------------------------------------------------------------------------
1 | import { isEqualDeep } from '../isEqualDeep';
2 |
3 |
4 | describe( 'isEqualDeep', () => {
5 | test( 'can check if 2 arrays are deeply equal or not.', () => {
6 | const array1 = [ 1, [ 2, 3 ] ];
7 | const array2 = [ 1, [ 2, 3 ] ];
8 | const array3 = [ 1, [ 2, 4 ] ];
9 |
10 | expect( isEqualDeep( array1, array2 ) ).toBe( true );
11 | expect( isEqualDeep( array1, array3 ) ).toBe( false );
12 | } );
13 |
14 | test( 'can check if 2 objects are deeply equal or not.', () => {
15 | const object1 = { a: 1, b: { c: 2, d: true, e: [ 1, 2 ] } };
16 | const object2 = { a: 1, b: { c: 2, d: true, e: [ 1, 2 ] } };
17 | const object3 = { a: 1, b: { c: 2, d: true, e: [ 1, 10 ] } };
18 |
19 | expect( isEqualDeep( object1, object2 ) ).toBe( true );
20 | expect( isEqualDeep( object1, object3 ) ).toBe( false );
21 | } );
22 |
23 | test( 'can handle complex objects.', () => {
24 | const object1 = {
25 | a: 1,
26 | b: true,
27 | c: 'x',
28 | d: [ true, true ],
29 | e: { e1: 1, e2: [ 1, 2, 3 ] },
30 | };
31 |
32 | const object2 = {
33 | a: 1,
34 | b: true,
35 | c: 'x',
36 | d: [ true, true ],
37 | e: { e1: 1, e2: [ 1, 2, 3 ] },
38 | };
39 |
40 | const object3 = {
41 | a: 1,
42 | b: true,
43 | c: 'x',
44 | d: [ true, true ],
45 | e: { e1: 1, e2: [ 1, 2, 10 ] },
46 | };
47 |
48 | expect( isEqualDeep( object1, object2 ) ).toBe( true );
49 | expect( isEqualDeep( object1, object3 ) ).toBe( false );
50 | } );
51 | } );
52 |
--------------------------------------------------------------------------------
/src/lib/utils/isEqualShallow/isEqualShallow.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Checks if provided two arrays are shallowly equal or not.
3 | *
4 | * @param array1 - An array to test.
5 | * @param array2 - Anther array to test.
6 | *
7 | * @return `true` if they are considered as equal, or otherwise `false`.
8 | */
9 | export function isEqualShallow( array1: unknown[], array2: unknown[] ): boolean {
10 | return array1.length === array2.length
11 | && ! array1.some( ( elm, index ) => elm !== array2[ index ] );
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/utils/isEqualShallow/test/isEqualShallow.test.ts:
--------------------------------------------------------------------------------
1 | import { isEqualShallow } from '../isEqualShallow';
2 |
3 |
4 | describe( 'isEqualShallow', () => {
5 | test( 'can check if 2 arrays with primitives are shallowly equal or not.', () => {
6 | const array1 = [ 1, true, '1' ];
7 | const array2 = [ 1, true, '1' ];
8 | const array3 = [ 1, true, '3' ];
9 |
10 | expect( isEqualShallow( array1, array2 ) ).toBe( true );
11 | expect( isEqualShallow( array1, array3 ) ).toBe( false );
12 | } );
13 |
14 | test( 'can check if 2 arrays with objects are shallowly equal or not.', () => {
15 | const object1 = {};
16 | const object2 = {};
17 |
18 | const array1 = [ object1, object2 ];
19 | const array2 = [ object1, object2 ];
20 | const array3 = [ object2, object2 ];
21 |
22 | expect( isEqualShallow( array1, array2 ) ).toBe( true );
23 | expect( isEqualShallow( array1, array3 ) ).toBe( false );
24 | } );
25 |
26 | test( 'should return false if length of testing arrays are different.', () => {
27 | const array1 = [ 1, 1 ];
28 | const array2 = [ 1, 1, 1 ];
29 |
30 | expect( isEqualShallow( array1, array2 ) ).toBe( false );
31 | } );
32 | } );
33 |
--------------------------------------------------------------------------------
/src/lib/utils/isObject/isObject.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Checks if the given subject is an object or not.
3 | *
4 | * @param subject - A subject to check.
5 | *
6 | * @return `true` if the subject is an object, or otherwise `false`.
7 | */
8 | export function isObject( subject: unknown ): subject is object {
9 | return subject !== null && typeof subject === 'object';
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/utils/isObject/test/isObject.test.ts:
--------------------------------------------------------------------------------
1 | import { isObject } from '../isObject';
2 |
3 |
4 | describe( 'isObject', () => {
5 | test( 'can return `true` if the subject is an object.', () => {
6 | [ {}, { a: 1 }, new Map(), [] ].forEach( subject => {
7 | expect( isObject( subject ) ).toBe( true );
8 | } );
9 | } );
10 |
11 | test( 'can return `false` if the subject is not an object.', () => {
12 | [ 1, true, '1', () => 1, null, undefined, NaN, BigInt( 1 ) ].forEach( subject => {
13 | expect( isObject( subject ) ).toBe( false );
14 | } );
15 | } );
16 | } );
17 |
--------------------------------------------------------------------------------
/src/lib/utils/merge/merge.test.ts:
--------------------------------------------------------------------------------
1 | import { merge } from './merge';
2 |
3 |
4 | describe( 'merge', () => {
5 | test( 'can merge 2 objects.', () => {
6 | const object = { a: 1, b: '2' };
7 | const source = { a: 2, c: true };
8 |
9 | expect( merge( object, source ) ).toStrictEqual( { a: 2, b: '2', c: true } );
10 |
11 | // Should not change the source
12 | expect( source ).toStrictEqual( { a: 2, c: true } );
13 | } );
14 |
15 | test( 'can merge 2 objects recursively.', () => {
16 | const object = { a: 1, b: { c: 2, d: 3 } };
17 | const source = { b: { d: 4, e: 5 }, f: true };
18 |
19 | expect( merge( object, source ) ).toStrictEqual( {
20 | a: 1,
21 | b: { c: 2, d: 4, e: 5 },
22 | f: true,
23 | } );
24 | } );
25 | } );
26 |
--------------------------------------------------------------------------------
/src/lib/utils/merge/merge.ts:
--------------------------------------------------------------------------------
1 | import { forOwn } from '../forOwn/forOwn';
2 | import { isObject } from '../isObject/isObject';
3 |
4 |
5 | /**
6 | * Merges U to T.
7 | *
8 | * @typeParam T - An object to merge U into.
9 | * @typeParam U - An object to merge properties from.
10 | *
11 | * @return An merged object type.
12 | */
13 | export type Merge = Omit & {
14 | [ K in ( keyof T & keyof U ) ]: U[ K ] extends object
15 | ? U[ K ] extends any[]
16 | ? U[ K ]
17 | : T[ K ] extends object
18 | ? Merge extends infer A ? Cast : never
19 | : U[ K ]
20 | : U[ K ];
21 | } & Omit;
22 |
23 | type Cast = T extends U ? T : U;
24 |
25 | /**
26 | * Recursively merges source properties to the object.
27 | * Be aware that this method does not merge arrays. They are just duplicated by `slice()`.
28 | *
29 | * @param object - An object to merge properties to.
30 | * @param source - A source object to merge properties from.
31 | *
32 | * @return A new object with merged properties.
33 | */
34 | export function merge( object: T, source: U ): Merge {
35 | const merged = object as any;
36 |
37 | forOwn( source, ( value, key ) => {
38 | if ( Array.isArray( value ) ) {
39 | merged[ key ] = value.slice();
40 | } else if ( isObject( value ) ) {
41 | merged[ key ] = merge( isObject( merged[ key ] ) ? merged[ key ] : {}, value );
42 | } else {
43 | merged[ key ] = value;
44 | }
45 | } );
46 |
47 | return merged as Merge;
48 | }
49 |
--------------------------------------------------------------------------------
/src/routes/components/BasicExample.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
Basic
23 |
24 |
console.log( e.detail.splide.length ) }
28 | on:move={ e => console.log( 'move to', e.detail.index ) }
29 | >
30 | { #each slides as slide }
31 |
32 |
33 |
34 | { /each }
35 |
36 |
--------------------------------------------------------------------------------
/src/routes/index.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/routes/utils/generateSlides/generateSlides.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Return an array with objects containing data of sample images.
3 | *
4 | * @param length - Optional. A number of slides.
5 | * @param sig - Optional. The signature for getting a different image.
6 | *
7 | * @return An array with objects for sample images.
8 | */
9 | export function generateSlides( length = 10, sig = 0 ): Array<{ src: string, alt: string }> {
10 | return Array.from( { length } ).map( ( _, index ) => {
11 | index = sig || index;
12 |
13 | return {
14 | src: `https://source.unsplash.com/random/800x450?sig=${ index }`,
15 | alt: `Image ${ index }`,
16 | };
17 | } );
18 | }
19 |
--------------------------------------------------------------------------------
/src/routes/utils/index.ts:
--------------------------------------------------------------------------------
1 | export { generateSlides } from './generateSlides/generateSlides';
2 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Splidejs/svelte-splide/72d805bdcb32fc738a225d6373853f9b5c710361/static/favicon.png
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import preprocess from 'svelte-preprocess';
2 | import adapter from '@sveltejs/adapter-static';
3 |
4 |
5 | /** @type {import('@sveltejs/kit').Config} */
6 | const config = {
7 | preprocess: preprocess(),
8 |
9 | kit: {
10 | adapter: adapter(),
11 | prerender: {
12 | default: true,
13 | },
14 | },
15 | };
16 |
17 | export default config;
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "moduleResolution": "node",
5 | "module": "es2020",
6 | "lib": [
7 | "es2020",
8 | "DOM"
9 | ],
10 | "target": "es2020",
11 | "importsNotUsedAsValues": "error",
12 | "isolatedModules": true,
13 | "resolveJsonModule": true,
14 | "sourceMap": true,
15 | "esModuleInterop": true,
16 | "skipLibCheck": true,
17 | "forceConsistentCasingInFileNames": true,
18 | "baseUrl": ".",
19 | "allowJs": true,
20 | "checkJs": true,
21 | "paths": {
22 | "$lib": [
23 | "src/lib"
24 | ],
25 | "$lib/*": [
26 | "src/lib/*"
27 | ]
28 | }
29 | },
30 | "include": [
31 | "src/**/*.d.ts",
32 | "src/**/*.js",
33 | "src/**/*.ts",
34 | "src/**/*.svelte"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------