Merge pull request #35 from vadimkorr/feature/#33_Change-pages-programmatically
Feature/#33 Change pages programmatically
This commit is contained in:
@@ -8,4 +8,6 @@ storybook-static
|
||||
# dist
|
||||
scripts
|
||||
|
||||
.test.js
|
||||
src/**/*.test.js
|
||||
|
||||
DEPLOYMENT.md
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import './styles.css'
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
|
||||
47
.storybook/styles.css
Normal file
47
.storybook/styles.css
Normal file
@@ -0,0 +1,47 @@
|
||||
.sb-container {
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: #d2d2d2;
|
||||
}
|
||||
|
||||
span.sb-title {
|
||||
color: #3e3e3e;
|
||||
display: block;
|
||||
margin: 5px;
|
||||
font-size: 16px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.sb-divider {
|
||||
max-width: 100%;
|
||||
border-bottom: solid 3px #ffffff;
|
||||
margin: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sb-button {
|
||||
width: 150px;
|
||||
height: 35px;
|
||||
margin: 5px;
|
||||
padding: 0px 10px;
|
||||
border-radius: 5px;
|
||||
background-color: #009800;
|
||||
border: none;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sb-input[type=text],
|
||||
.sb-input[type=number] {
|
||||
width: 150px;
|
||||
height: 35px;
|
||||
margin: 5px;
|
||||
padding: 0px 10px;
|
||||
border-radius: 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #9f9f9f;
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
14
DEPLOYMENT.md
Normal file
14
DEPLOYMENT.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# How to publish new feature:
|
||||
|
||||
1. Update unit tests
|
||||
2. Update storybook
|
||||
|
||||
3. Update version in `package.json`
|
||||
|
||||
4. Update docs in `README.md`
|
||||
5. Update docs in `src/docs`
|
||||
6. `yarn build:docs`
|
||||
|
||||
7. `npm publish`
|
||||
8. Merge feature branch
|
||||
9. Create release in GitHub
|
||||
81
README.md
81
README.md
@@ -138,3 +138,84 @@ Slot props:
|
||||
<!-- -->
|
||||
</Carousel>
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
### `goTo`
|
||||
Navigates to a page by index
|
||||
|
||||
Arguments:
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
|--------------------|-------------|---------|---------------------------------------|
|
||||
| `pageIndex` | `number` | | Page number |
|
||||
| `options.animated` | `boolean` | `true` | Should it be animated or not |
|
||||
|
||||
```jsx
|
||||
<script>
|
||||
// ...
|
||||
let carousel;
|
||||
function goToStartPage() {
|
||||
carousel.goTo(0, { animated: false })
|
||||
}
|
||||
</script>
|
||||
|
||||
<Carousel
|
||||
bind:this={carousel}
|
||||
>
|
||||
<!-- -->
|
||||
</Carousel>
|
||||
<button class="button" on:click={goToStartPage}>Go</button>
|
||||
```
|
||||
|
||||
### `goToPrev`
|
||||
Navigates to the previous page
|
||||
|
||||
Arguments:
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
|--------------------|-------------|---------|---------------------------------------|
|
||||
| `options.animated` | `boolean` | `true` | Should it be animated or not |
|
||||
|
||||
```jsx
|
||||
<script>
|
||||
// ...
|
||||
let carousel;
|
||||
function goToPrevPage() {
|
||||
carousel.goToPrev({ animated: false })
|
||||
}
|
||||
</script>
|
||||
|
||||
<Carousel
|
||||
bind:this={carousel}
|
||||
>
|
||||
<!-- -->
|
||||
</Carousel>
|
||||
<button class="button" on:click={goToPrevPage}>Go</button>
|
||||
```
|
||||
|
||||
### `goToNext`
|
||||
Navigates to the next page
|
||||
|
||||
Arguments:
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
|--------------------|-------------|---------|---------------------------------------|
|
||||
| `options.animated` | `boolean` | `true` | Should it be animated or not |
|
||||
|
||||
```jsx
|
||||
<script>
|
||||
// ...
|
||||
let carousel;
|
||||
function goToNextPage() {
|
||||
carousel.goToNext({ animated: false })
|
||||
}
|
||||
</script>
|
||||
|
||||
<Carousel
|
||||
bind:this={carousel}
|
||||
>
|
||||
<!-- -->
|
||||
</Carousel>
|
||||
<button class="button" on:click={goToNextPage}>Go</button>
|
||||
```
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
html,body{position:relative;width:100%;height:100%;margin:0;padding:0;box-sizing:border-box;font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;}
|
||||
code[class*="language-"],pre[class*="language-"] {color:#ccc;background:none;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;}pre[class*="language-"] {padding:1em;margin:.5em 0;overflow:auto;}:not(pre) > code[class*="language-"],pre[class*="language-"] {background:#2d2d2d;}:not(pre) > code[class*="language-"] {padding:.1em;border-radius:.3em;white-space:normal;}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata {color:#999;}.token.punctuation {color:#ccc;}.token.tag,.token.attr-name,.token.namespace,.token.deleted {color:#e2777a;}.token.function-name {color:#6196cc;}.token.boolean,.token.number,.token.function {color:#f08d49;}.token.property,.token.class-name,.token.constant,.token.symbol {color:#f8c555;}.token.selector,.token.important,.token.atrule,.token.keyword,.token.builtin {color:#cc99cd;}.token.string,.token.char,.token.attr-value,.token.regex,.token.variable {color:#7ec699;}.token.operator,.token.entity,.token.url {color:#67cdcc;}.token.important,.token.bold {font-weight:bold;}.token.italic {font-style:italic;}.token.entity {cursor:help;}.token.inserted {color:green;}
|
||||
.img-container.svelte-14lrqxf.svelte-14lrqxf{display:block;width:100%;height:200px}.img-container.svelte-14lrqxf>img.svelte-14lrqxf{width:100%;height:100%;object-fit:cover;-webkit-user-drag:none}.table-wrapper.svelte-14lrqxf.svelte-14lrqxf{max-width:100%;overflow-x:auto}table.svelte-14lrqxf.svelte-14lrqxf{border-collapse:collapse}tr.svelte-14lrqxf.svelte-14lrqxf{border-bottom:2px solid #009800}td.svelte-14lrqxf.svelte-14lrqxf{padding:2px 10px}th.svelte-14lrqxf.svelte-14lrqxf{padding:5px 10px}.custom-arrow.svelte-14lrqxf.svelte-14lrqxf{width:20px;background-color:#000000;opacity:0.3;position:absolute;top:0;bottom:0;z-index:1;transition:opacity 150ms ease;display:flex;align-items:center;justify-content:center;cursor:pointer;-webkit-tap-highlight-color:transparent}.custom-arrow.svelte-14lrqxf.svelte-14lrqxf:hover{opacity:0.5}.custom-arrow.svelte-14lrqxf>i.svelte-14lrqxf{border:solid #1e1e1e;border-width:0 5px 5px 0;padding:5px;position:relative}.custom-arrow-prev.svelte-14lrqxf.svelte-14lrqxf{left:0}.custom-arrow-prev.svelte-14lrqxf>i.svelte-14lrqxf{transform:rotate(135deg);right:-4px}.custom-arrow-next.svelte-14lrqxf.svelte-14lrqxf{right:0}.custom-arrow-next.svelte-14lrqxf>i.svelte-14lrqxf{transform:rotate(-45deg);left:-4px}.custom-dots.svelte-14lrqxf.svelte-14lrqxf{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;padding:0 20px}
|
||||
.color-container.svelte-1bsdhrs.svelte-1bsdhrs{height:150px;width:100%;display:flex;align-items:center;justify-content:center;user-select:none}.color-container.svelte-1bsdhrs>p.svelte-1bsdhrs{font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;font-style:italic;font-size:18px}
|
||||
.divider.svelte-1dny3ln{margin-top:30px;margin-bottom:30px;height:1px}
|
||||
.custom-dot__dot-container.svelte-1ufq367{height:25px;width:25px;background-color:#727272;border-radius:50%;opacity:0.7;display:flex;align-items:center;justify-content:center;margin:5px;cursor:pointer;-webkit-tap-highlight-color:transparent}.custom-dot__dot-container.svelte-1ufq367:hover{opacity:0.9}.custom-dot__dot-container_active.svelte-1ufq367{background-color:#009800}.custom-dot__symbol.svelte-1ufq367{font-size:14px;font-weight:bold;color:#eaeaea}
|
||||
.color-container.svelte-1bsdhrs.svelte-1bsdhrs{height:150px;width:100%;display:flex;align-items:center;justify-content:center;user-select:none}.color-container.svelte-1bsdhrs>p.svelte-1bsdhrs{font-family:'Segoe UI',Tahoma,Geneva,Verdana,sans-serif;font-style:italic;font-size:18px}
|
||||
.sc-carousel__carousel-container.svelte-1pac7rj{display:flex;width:100%;flex-direction:column;align-items:center}.sc-carousel__content-container.svelte-1pac7rj{position:relative;display:flex;width:100%}.sc-carousel__pages-window.svelte-1pac7rj{flex:1;display:flex;overflow:hidden;box-sizing:border-box}.sc-carousel__pages-container.svelte-1pac7rj{width:100%;display:flex;transition-property:transform}.sc-carousel__arrow-container.svelte-1pac7rj{padding:5px;box-sizing:border-box;display:flex;align-items:center;justify-content:center}
|
||||
.albums-container.svelte-tqqkfc.svelte-tqqkfc{display:flex;justify-content:center;flex-wrap:wrap}.album-container.svelte-tqqkfc.svelte-tqqkfc{width:250px;padding:10px;background-color:#c6c6c6;border-radius:5px;margin:5px}.album-title.svelte-tqqkfc.svelte-tqqkfc{font-size:16px}.album-size.svelte-tqqkfc.svelte-tqqkfc{font-size:10px;color:#585858}.album-tag.svelte-tqqkfc.svelte-tqqkfc{background-color:#8f8f8f;border-radius:5px;padding:1px 5px;color:#ffffff;margin-top:3px;margin-bottom:3px;display:inline-block;font-size:10px}.album-tag.svelte-tqqkfc.svelte-tqqkfc:not(:last-child){margin-right:3px}.album-arrow.svelte-tqqkfc.svelte-tqqkfc{width:20px;background-color:#000000;opacity:0;position:absolute;top:0;bottom:0;z-index:1;transition:opacity 150ms ease;display:flex;align-items:center;justify-content:center;cursor:pointer;-webkit-tap-highlight-color:transparent}.album-arrow.svelte-tqqkfc>i.svelte-tqqkfc{border:solid #1e1e1e;border-width:0 5px 5px 0;padding:5px;position:relative}.album-container.svelte-tqqkfc:hover .album-arrow.svelte-tqqkfc{opacity:0.5}.album-arrow-prev.svelte-tqqkfc.svelte-tqqkfc{left:0}.album-arrow-prev.svelte-tqqkfc>i.svelte-tqqkfc{transform:rotate(135deg);right:-4px}.album-arrow-next.svelte-tqqkfc.svelte-tqqkfc{right:0}.album-arrow-next.svelte-tqqkfc>i.svelte-tqqkfc{transform:rotate(-45deg);left:-4px}
|
||||
.docs__main-layout__main-container.svelte-17evj66.svelte-17evj66{background-color:#eaeaea}.docs__main-layout__header-container.svelte-17evj66.svelte-17evj66{display:flex;flex-direction:column;align-items:center;justify-content:center;height:300px;padding:10px;box-sizing:border-box;background-color:#f0e68c}.docs__main-layout__logo.svelte-17evj66.svelte-17evj66{height:80%;max-width:100%;object-fit:contain}.docs__main-layout__links-container.svelte-17evj66.svelte-17evj66{display:flex;justify-content:center;padding:10px}.docs__main-layout__links-container.svelte-17evj66>a.svelte-17evj66{text-decoration:none;color:#009800;font-size:18px}.docs__main-layout__links-container.svelte-17evj66>a.svelte-17evj66:not(:last-child){margin-right:10px}.docs__main-layout__content-container.svelte-17evj66.svelte-17evj66{margin:0 auto}@media screen and (min-width:0px){.docs__main-layout__content-container.svelte-17evj66.svelte-17evj66{width:95%}}@media screen and (min-width:768px){.docs__main-layout__content-container.svelte-17evj66.svelte-17evj66{width:70%}}@media screen and (min-width:992px){.docs__main-layout__content-container.svelte-17evj66.svelte-17evj66{width:60%}}@media screen and (min-width:1200px){.docs__main-layout__content-container.svelte-17evj66.svelte-17evj66{width:50%}}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "svelte-carousel",
|
||||
"version": "1.0.8",
|
||||
"version": "1.0.9",
|
||||
"description": "Svelte carousel",
|
||||
"main": "src/main.js",
|
||||
"author": "vadimkorr",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
removeResizeEventListener
|
||||
} from '../../utils/event'
|
||||
import { getAdjacentIndexes } from '../../utils/page'
|
||||
import { get } from '../../utils/object'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -52,7 +53,7 @@
|
||||
export let autoplay = false
|
||||
|
||||
/**
|
||||
* Auto play change interval
|
||||
* Auto play change interval (ms)
|
||||
*/
|
||||
export let autoplayDuration = 3000
|
||||
|
||||
@@ -71,6 +72,28 @@
|
||||
*/
|
||||
export let dots = true
|
||||
|
||||
export function goTo(pageIndex, options) {
|
||||
const animated = get(options, 'animated', true)
|
||||
if (typeof pageIndex !== 'number') {
|
||||
throw new Error('pageIndex should be a number')
|
||||
}
|
||||
showPage(pageIndex + Number(infinite), { offsetDelayMs: 0, animated })
|
||||
}
|
||||
|
||||
export function goToPrev(options) {
|
||||
const animated = get(options, 'animated', true)
|
||||
showPrevPage({
|
||||
animated
|
||||
})
|
||||
}
|
||||
|
||||
export function goToNext(options) {
|
||||
const animated = get(options, 'animated', true)
|
||||
showNextPage({
|
||||
animated
|
||||
})
|
||||
}
|
||||
|
||||
let store = createStore()
|
||||
let currentPageIndex = 0
|
||||
$: originalCurrentPageIndex = currentPageIndex - Number(infinite);
|
||||
@@ -160,7 +183,7 @@
|
||||
})
|
||||
|
||||
function handlePageChange(pageIndex) {
|
||||
showPage(pageIndex + Number(infinite), { offsetDelay: 0, animated: true })
|
||||
showPage(pageIndex + Number(infinite), { offsetDelayMs: 0, animated: true })
|
||||
}
|
||||
|
||||
function offsetPage(animated) {
|
||||
@@ -168,42 +191,48 @@
|
||||
offset = -currentPageIndex * pageWidth
|
||||
if (infinite) {
|
||||
if (currentPageIndex === 0) {
|
||||
showPage(pagesCount - 2, { offsetDelay: duration, animated: false })
|
||||
showPage(pagesCount - 2, { offsetDelayMs: duration, animated: false })
|
||||
} else if (currentPageIndex === pagesCount - 1) {
|
||||
showPage(1, { offsetDelay: duration, animated: false })
|
||||
showPage(1, { offsetDelayMs: duration, animated: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable page change while animation is in progress
|
||||
let disabled = false
|
||||
function safeChangePage(cb) {
|
||||
function safeChangePage(cb, options) {
|
||||
const animated = get(options, 'animated', true)
|
||||
if (disabled) return
|
||||
cb()
|
||||
disabled = true
|
||||
setTimeout(() => {
|
||||
disabled = false
|
||||
}, duration)
|
||||
}, animated ? duration : 0)
|
||||
}
|
||||
|
||||
function showPage(pageIndex, { offsetDelay, animated }) {
|
||||
function showPage(pageIndex, options) {
|
||||
const animated = get(options, 'animated', true)
|
||||
const offsetDelayMs = get(options, 'offsetDelayMs', true)
|
||||
safeChangePage(() => {
|
||||
store.moveToPage({ pageIndex, pagesCount })
|
||||
setTimeout(() => {
|
||||
offsetPage(animated)
|
||||
}, offsetDelay)
|
||||
})
|
||||
}, offsetDelayMs)
|
||||
}, { animated })
|
||||
}
|
||||
function showPrevPage() {
|
||||
function showPrevPage(options) {
|
||||
const animated = get(options, 'animated', true)
|
||||
safeChangePage(() => {
|
||||
store.prev({ infinite, pagesCount })
|
||||
offsetPage(true)
|
||||
})
|
||||
offsetPage(animated)
|
||||
}, { animated })
|
||||
}
|
||||
function showNextPage() {
|
||||
function showNextPage(options) {
|
||||
const animated = get(options, 'animated', true)
|
||||
safeChangePage(() => {
|
||||
store.next({ infinite, pagesCount })
|
||||
offsetPage(true)
|
||||
})
|
||||
offsetPage(animated)
|
||||
}, { animated })
|
||||
}
|
||||
|
||||
// gestures
|
||||
@@ -217,7 +246,7 @@
|
||||
offset += event.detail.dx
|
||||
}
|
||||
function handleSwipeEnd() {
|
||||
showPage(currentPageIndex, { offsetDelay: 0, animated: true })
|
||||
showPage(currentPageIndex, { offsetDelayMs: 0, animated: true })
|
||||
}
|
||||
function handleFocused(event) {
|
||||
focused = event.detail.value
|
||||
|
||||
@@ -1,27 +1,33 @@
|
||||
import CarouselView from './CarouselView.svelte';
|
||||
import CarouselViewCustomDots from './CarouselViewCustomDots.svelte';
|
||||
import CarouselViewCustomArrows from './CarouselViewCustomArrows.svelte';
|
||||
import CarouselView from './CarouselView.svelte'
|
||||
import CarouselViewCustomDots from './CarouselViewCustomDots.svelte'
|
||||
import CarouselViewCustomArrows from './CarouselViewCustomArrows.svelte'
|
||||
import CarouselViewMethods from './CarouselViewMethods.svelte'
|
||||
|
||||
export default {
|
||||
title: 'Carousel',
|
||||
component: CarouselView
|
||||
};
|
||||
component: CarouselView,
|
||||
}
|
||||
|
||||
const Template = ({ ...args }) => ({
|
||||
Component: CarouselView,
|
||||
props: args
|
||||
});
|
||||
export const Primary = Template.bind({});
|
||||
props: args,
|
||||
})
|
||||
export const Primary = Template.bind({})
|
||||
|
||||
const TemplateCustomDots = ({ ...args }) => ({
|
||||
Component: CarouselViewCustomDots,
|
||||
props: args
|
||||
});
|
||||
export const WithCustomDots = TemplateCustomDots.bind({});
|
||||
props: args,
|
||||
})
|
||||
export const WithCustomDots = TemplateCustomDots.bind({})
|
||||
|
||||
const TemplateCustomArrows = ({ ...args }) => ({
|
||||
Component: CarouselViewCustomArrows,
|
||||
props: args
|
||||
});
|
||||
export const WithCustomArrows = TemplateCustomArrows.bind({});
|
||||
props: args,
|
||||
})
|
||||
export const WithCustomArrows = TemplateCustomArrows.bind({})
|
||||
|
||||
const TemplateMethods = ({ ...args }) => ({
|
||||
Component: CarouselViewMethods,
|
||||
props: args,
|
||||
})
|
||||
export const WithMethods = TemplateMethods.bind({})
|
||||
|
||||
88
src/components/Carousel/stories/CarouselViewMethods.svelte
Normal file
88
src/components/Carousel/stories/CarouselViewMethods.svelte
Normal file
@@ -0,0 +1,88 @@
|
||||
<script>
|
||||
import {onMount} from 'svelte'
|
||||
import Carousel from '../Carousel.svelte'
|
||||
|
||||
const colors = [
|
||||
{ color: '#e5f9f0', text: '0' },
|
||||
{ color: '#ccf3e2', text: '1' },
|
||||
{ color: '#b2edd3', text: '2' },
|
||||
{ color: '#99e7c5', text: '3' },
|
||||
{ color: '#7fe1b7', text: '4' },
|
||||
{ color: '#66dba8', text: '5' },
|
||||
{ color: '#4cd59a', text: '6' },
|
||||
{ color: '#32cf8b', text: '7' },
|
||||
{ color: '#19c97d', text: '8' },
|
||||
{ color: '#00c36f', text: '9' }
|
||||
]
|
||||
|
||||
let carousel;
|
||||
|
||||
// goTo
|
||||
let pageIndex
|
||||
function handlePageChange(e) {
|
||||
pageIndex = Number(e.target.value)
|
||||
}
|
||||
function handleGoToClick() {
|
||||
carousel.goTo(pageIndex)
|
||||
}
|
||||
|
||||
// goToPrev
|
||||
function handleGoToPrevClick() {
|
||||
carousel.goToPrev()
|
||||
}
|
||||
|
||||
// goToNext
|
||||
function handleGoToNextClick() {
|
||||
carousel.goToNext()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="main-container">
|
||||
<Carousel
|
||||
bind:this={carousel}
|
||||
>
|
||||
{#each colors as { color, text } (color)}
|
||||
<div
|
||||
class="color-container"
|
||||
style="background-color: {color};"
|
||||
>
|
||||
<p>{text}</p>
|
||||
</div>
|
||||
{/each}
|
||||
</Carousel>
|
||||
|
||||
<div class="sb-container">
|
||||
<span class="sb-title">carousel.goTo</span>
|
||||
<input class="sb-input" type="number" on:change={handlePageChange} />
|
||||
<button class="sb-button" on:click={handleGoToClick}>Go</button>
|
||||
<div class="sb-divider"></div>
|
||||
|
||||
<span class="sb-title">carousel.goToPrev</span>
|
||||
<button class="sb-button" on:click={handleGoToPrevClick}>Go</button>
|
||||
<div class="sb-divider"></div>
|
||||
|
||||
<span class="sb-title">carousel.goToNext</span>
|
||||
<button class="sb-button" on:click={handleGoToNextClick}>Go</button>
|
||||
<div class="sb-divider"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.main-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
.color-container {
|
||||
height: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
}
|
||||
.color-container > p {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
font-style: italic;
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
@@ -186,6 +186,8 @@
|
||||
## Use case
|
||||
<AlbumsPreview />
|
||||
|
||||
<Divider />
|
||||
|
||||
# Installation
|
||||
```bash
|
||||
yarn add svelte-carousel
|
||||
@@ -202,7 +204,10 @@ Import component
|
||||
</script>
|
||||
```
|
||||
|
||||
<Divider />
|
||||
|
||||
# Props
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
@@ -220,7 +225,9 @@ Import component
|
||||
|
||||
</div>
|
||||
|
||||
# Event
|
||||
<Divider />
|
||||
|
||||
# Events
|
||||
|
||||
## `pageChange`
|
||||
Is dispatched on page change
|
||||
@@ -243,6 +250,8 @@ Is dispatched on page change
|
||||
</Carousel>
|
||||
```
|
||||
|
||||
<Divider />
|
||||
|
||||
# Slots
|
||||
|
||||
## `prev` and `next`
|
||||
@@ -329,6 +338,101 @@ Slot props:
|
||||
|
||||
<Divider />
|
||||
|
||||
# Methods
|
||||
|
||||
## `goTo`
|
||||
Navigates to a page by index
|
||||
|
||||
Arguments:
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
|--------------------|-------------|---------|---------------------------------------|
|
||||
| `pageIndex` | `number` | | Page number |
|
||||
| `options.animated` | `boolean` | `true` | Should it be animated or not |
|
||||
|
||||
</div>
|
||||
|
||||
```jsx
|
||||
<script>
|
||||
// ...
|
||||
let carousel;
|
||||
function goToStartPage() {
|
||||
carousel.goTo(0, { animated: false })
|
||||
}
|
||||
</script>
|
||||
|
||||
<Carousel
|
||||
bind:this={carousel}
|
||||
>
|
||||
<!-- -->
|
||||
</Carousel>
|
||||
<button class="button" on:click={goToStartPage}>Go</button>
|
||||
```
|
||||
|
||||
## `goToPrev`
|
||||
Navigates to the previous page
|
||||
|
||||
Arguments:
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
|--------------------|-------------|---------|---------------------------------------|
|
||||
| `options.animated` | `boolean` | `true` | Should it be animated or not |
|
||||
|
||||
</div>
|
||||
|
||||
```jsx
|
||||
<script>
|
||||
// ...
|
||||
let carousel;
|
||||
function goToPrevPage() {
|
||||
carousel.goToPrev({ animated: false })
|
||||
}
|
||||
</script>
|
||||
|
||||
<Carousel
|
||||
bind:this={carousel}
|
||||
>
|
||||
<!-- -->
|
||||
</Carousel>
|
||||
<button class="button" on:click={goToPrevPage}>Go</button>
|
||||
```
|
||||
|
||||
## `goToNext`
|
||||
Navigates to the next page
|
||||
|
||||
Arguments:
|
||||
|
||||
<div class="table-wrapper">
|
||||
|
||||
| Argument | Type | Default | Description |
|
||||
|--------------------|-------------|---------|---------------------------------------|
|
||||
| `options.animated` | `boolean` | `true` | Should it be animated or not |
|
||||
|
||||
</div>
|
||||
|
||||
```jsx
|
||||
<script>
|
||||
// ...
|
||||
let carousel;
|
||||
function goToNextPage() {
|
||||
carousel.goToNext({ animated: false })
|
||||
}
|
||||
</script>
|
||||
|
||||
<Carousel
|
||||
bind:this={carousel}
|
||||
>
|
||||
<!-- -->
|
||||
</Carousel>
|
||||
<button class="button" on:click={goToNextPage}>Go</button>
|
||||
```
|
||||
|
||||
<Divider />
|
||||
|
||||
<style>
|
||||
.img-container {
|
||||
display: block;
|
||||
|
||||
9
src/utils/object.js
Normal file
9
src/utils/object.js
Normal file
@@ -0,0 +1,9 @@
|
||||
export const get = (object, fieldName, defaultValue) => {
|
||||
if (object && object.hasOwnProperty(fieldName)) {
|
||||
return object[fieldName]
|
||||
}
|
||||
if (defaultValue === undefined) {
|
||||
throw new Error(`Required arg "${fieldName}" was not provided`)
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
65
src/utils/object.test.js
Normal file
65
src/utils/object.test.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
get,
|
||||
} from './object.js'
|
||||
|
||||
describe('get', () => {
|
||||
it('returns correct value if field exists', () => {
|
||||
const object = {
|
||||
field: 5,
|
||||
}
|
||||
const fieldName = 'field'
|
||||
const defaultValue = 10
|
||||
|
||||
expect(get(object, fieldName, defaultValue)).toBe(5)
|
||||
})
|
||||
|
||||
it('returns correct value if field exists and has falsy value 0', () => {
|
||||
const object = {
|
||||
field: 0,
|
||||
}
|
||||
const fieldName = 'field'
|
||||
const defaultValue = 10
|
||||
|
||||
expect(get(object, fieldName, defaultValue)).toBe(0)
|
||||
})
|
||||
|
||||
it('returns correct value if field exists and has falsy value null', () => {
|
||||
const object = {
|
||||
field: null,
|
||||
}
|
||||
const fieldName = 'field'
|
||||
const defaultValue = 10
|
||||
|
||||
expect(get(object, fieldName, defaultValue)).toBe(null)
|
||||
})
|
||||
|
||||
it('returns default value if is provided and field does not exist', () => {
|
||||
const object = {
|
||||
field: 5,
|
||||
}
|
||||
const fieldName = 'nonExistingField'
|
||||
const defaultValue = 10
|
||||
|
||||
expect(get(object, fieldName, defaultValue)).toBe(10)
|
||||
})
|
||||
|
||||
it('returns correct value if field exists and has falsy value undefined', () => {
|
||||
const object = {
|
||||
field: undefined,
|
||||
}
|
||||
const fieldName = 'field'
|
||||
const defaultValue = 10
|
||||
|
||||
expect(get(object, fieldName, defaultValue)).toBe(undefined)
|
||||
})
|
||||
|
||||
it('throws an error if there is no field and no default value', () => {
|
||||
const object = {
|
||||
field: 'value',
|
||||
}
|
||||
const fieldName = 'nonExistingField'
|
||||
expect(
|
||||
() => get(object, fieldName)
|
||||
).toThrowError('Required arg "nonExistingField" was not provided')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user