Merge pull request #65 from vadimkorr/feature/#56_Split-handlers
feature/#56 Fix touchable handlers
This commit is contained in:
@@ -86,7 +86,7 @@ npm install svelte-carousel -D
|
|||||||
| `autoplay` | `boolean` | `false` | Enables autoplay of pages |
|
| `autoplay` | `boolean` | `false` | Enables autoplay of pages |
|
||||||
| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
|
| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
|
||||||
| `autoplayDirection` | `string` | `'next'` | Autoplay change direction (`next` or `prev`) |
|
| `autoplayDirection` | `string` | `'next'` | Autoplay change direction (`next` or `prev`) |
|
||||||
| `pauseOnFocus` | `boolean` | `false` | Pauses autoplay on focus (for desktop - hover over the carousel to toggle the autoplay, for touchable devices - tap the carousel to toggle the autoplay) |
|
| `pauseOnFocus` | `boolean` | `false` | Pauses autoplay on focus (for touchable devices - tap the carousel to toggle the autoplay, for non-touchable devices - hover over the carousel to pause the autoplay) |
|
||||||
| `autoplayProgressVisible` | `boolean` | `false` | Shows autoplay duration progress indicator |
|
| `autoplayProgressVisible` | `boolean` | `false` | Shows autoplay duration progress indicator |
|
||||||
| `dots` | `boolean` | `true` | Current page indicator dots |
|
| `dots` | `boolean` | `true` | Current page indicator dots |
|
||||||
| `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function |
|
| `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function |
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
// focusin event
|
|
||||||
export function addFocusinEventListener(source, cb) {
|
|
||||||
source.addEventListener('mouseenter', cb)
|
|
||||||
}
|
|
||||||
export function removeFocusinEventListener(source, cb) {
|
|
||||||
source.removeEventListener('mouseenter', cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// focusout event
|
|
||||||
export function addFocusoutEventListener(source, cb) {
|
|
||||||
source.addEventListener('mouseleave', cb)
|
|
||||||
}
|
|
||||||
export function removeFocusoutEventListener(source, cb) {
|
|
||||||
source.removeEventListener('mouseleave', cb)
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { createDispatcher } from '../../utils/event'
|
|
||||||
import { get } from '../../utils/object'
|
|
||||||
import {
|
|
||||||
addFocusinEventListener,
|
|
||||||
removeFocusinEventListener,
|
|
||||||
addFocusoutEventListener,
|
|
||||||
removeFocusoutEventListener
|
|
||||||
} from './event'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* focusable events are for mouse events only
|
|
||||||
*/
|
|
||||||
export function focusable(node, options) {
|
|
||||||
// pass custom dispatch fn in order to re-translate dispatched event
|
|
||||||
const dispatch = get(options, 'dispatch', createDispatcher(node))
|
|
||||||
|
|
||||||
function handleFocusin() {
|
|
||||||
addFocusoutEventListener(node, handleFocusout)
|
|
||||||
dispatch('focused', { value: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleFocusout() {
|
|
||||||
dispatch('focused', { value: false })
|
|
||||||
removeFocusoutEventListener(node, handleFocusout)
|
|
||||||
}
|
|
||||||
|
|
||||||
addFocusinEventListener(node, handleFocusin)
|
|
||||||
|
|
||||||
return {
|
|
||||||
destroy() {
|
|
||||||
removeFocusinEventListener(node, handleFocusin)
|
|
||||||
removeFocusoutEventListener(node, handleFocusout)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './focusable'
|
|
||||||
15
src/actions/hoverable/event.js
Normal file
15
src/actions/hoverable/event.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// in event
|
||||||
|
export function addHoverInEventListener(source, cb) {
|
||||||
|
source.addEventListener('mouseenter', cb)
|
||||||
|
}
|
||||||
|
export function removeHoverInEventListener(source, cb) {
|
||||||
|
source.removeEventListener('mouseenter', cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// out event
|
||||||
|
export function addHoverOutEventListener(source, cb) {
|
||||||
|
source.addEventListener('mouseleave', cb)
|
||||||
|
}
|
||||||
|
export function removeHoverOutEventListener(source, cb) {
|
||||||
|
source.removeEventListener('mouseleave', cb)
|
||||||
|
}
|
||||||
33
src/actions/hoverable/hoverable.js
Normal file
33
src/actions/hoverable/hoverable.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { createDispatcher } from '../../utils/event'
|
||||||
|
import {
|
||||||
|
addHoverInEventListener,
|
||||||
|
removeHoverInEventListener,
|
||||||
|
addHoverOutEventListener,
|
||||||
|
removeHoverOutEventListener
|
||||||
|
} from './event'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hoverable events are for mouse events only
|
||||||
|
*/
|
||||||
|
export function hoverable(node) {
|
||||||
|
const dispatch = createDispatcher(node)
|
||||||
|
|
||||||
|
function handleHoverIn() {
|
||||||
|
addHoverOutEventListener(node, handleHoverOut)
|
||||||
|
dispatch('hovered', { value: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHoverOut() {
|
||||||
|
dispatch('hovered', { value: false })
|
||||||
|
removeHoverOutEventListener(node, handleHoverOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
addHoverInEventListener(node, handleHoverIn)
|
||||||
|
|
||||||
|
return {
|
||||||
|
destroy() {
|
||||||
|
removeHoverInEventListener(node, handleHoverIn)
|
||||||
|
removeHoverOutEventListener(node, handleHoverOut)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/actions/hoverable/index.js
Normal file
1
src/actions/hoverable/index.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './hoverable'
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './pausable'
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import {
|
|
||||||
// addTouchableChangeEventListener,
|
|
||||||
getIsTouchable,
|
|
||||||
createDispatcher,
|
|
||||||
} from '../../utils/event'
|
|
||||||
import { focusable } from '../focusable'
|
|
||||||
import { tappable } from '../tappable'
|
|
||||||
|
|
||||||
function getHandler(isTouchable, node) {
|
|
||||||
const dispatch = createDispatcher(node)
|
|
||||||
|
|
||||||
if (isTouchable) {
|
|
||||||
return tappable(node, {
|
|
||||||
dispatch: (_, payload) => {
|
|
||||||
dispatch('pausedToggle', {
|
|
||||||
isTouchable: true,
|
|
||||||
...payload
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return focusable(node, {
|
|
||||||
dispatch: (_, payload) => {
|
|
||||||
dispatch('pausedToggle', {
|
|
||||||
isTouchable: false,
|
|
||||||
...payload
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pausable(node) {
|
|
||||||
let destroy
|
|
||||||
|
|
||||||
const handleTouchableChange = (isTouchable) => {
|
|
||||||
destroy && destroy() // destroy when touchable changed
|
|
||||||
destroy = getHandler(isTouchable, node).destroy
|
|
||||||
}
|
|
||||||
handleTouchableChange(getIsTouchable())
|
|
||||||
// in order to change handlers when browser was switched to mobile view and vice versa
|
|
||||||
// const removeTouchableChangeListener = addTouchableChangeEventListener(handleTouchableChange)
|
|
||||||
return {
|
|
||||||
destroy() {
|
|
||||||
// removeTouchableChangeListener()
|
|
||||||
destroy() // destroy here in case if touchable was not changed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -70,6 +70,7 @@ export function swipeable(node, { thresholdProvider }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleUp(event) {
|
function handleUp(event) {
|
||||||
|
event.preventDefault();
|
||||||
removeEndEventListener(window, handleUp)
|
removeEndEventListener(window, handleUp)
|
||||||
removeMoveEventListener(window, handleMove)
|
removeMoveEventListener(window, handleMove)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { createDispatcher } from '../../utils/event'
|
import { createDispatcher } from '../../utils/event'
|
||||||
import { get } from '../../utils/object'
|
|
||||||
import { getDistance } from '../../utils/math'
|
import { getDistance } from '../../utils/math'
|
||||||
import {
|
import {
|
||||||
addFocusinEventListener,
|
addFocusinEventListener,
|
||||||
@@ -15,9 +14,8 @@ import {
|
|||||||
/**
|
/**
|
||||||
* tappable events are for touchable devices only
|
* tappable events are for touchable devices only
|
||||||
*/
|
*/
|
||||||
export function tappable(node, options) {
|
export function tappable(node) {
|
||||||
// pass custom dispatch fn in order to re-translate dispatched event
|
const dispatch = createDispatcher(node)
|
||||||
const dispatch = get(options, 'dispatch', createDispatcher(node))
|
|
||||||
|
|
||||||
let tapStartedAt = 0
|
let tapStartedAt = 0
|
||||||
let tapStartPos = { x: 0, y: 0 }
|
let tapStartPos = { x: 0, y: 0 }
|
||||||
@@ -44,6 +42,7 @@ export function tappable(node, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleTapend(event) {
|
function handleTapend(event) {
|
||||||
|
event.preventDefault();
|
||||||
removeFocusoutEventListener(node, handleTapend)
|
removeFocusoutEventListener(node, handleTapend)
|
||||||
|
|
||||||
const touch = event.changedTouches[0]
|
const touch = event.changedTouches[0]
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
import Progress from '../Progress/Progress.svelte'
|
import Progress from '../Progress/Progress.svelte'
|
||||||
import { NEXT, PREV } from '../../direction'
|
import { NEXT, PREV } from '../../direction'
|
||||||
import { swipeable } from '../../actions/swipeable'
|
import { swipeable } from '../../actions/swipeable'
|
||||||
import { pausable } from '../../actions/pausable'
|
import { hoverable } from '../../actions/hoverable'
|
||||||
|
import { tappable } from '../../actions/tappable'
|
||||||
import {
|
import {
|
||||||
addResizeEventListener,
|
addResizeEventListener,
|
||||||
removeResizeEventListener
|
removeResizeEventListener
|
||||||
@@ -310,13 +311,12 @@
|
|||||||
await offsetPage({ animated: true })
|
await offsetPage({ animated: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePausedToggle(event) {
|
function handleHovered(event) {
|
||||||
if (event.detail.isTouchable) {
|
|
||||||
focused = !focused
|
|
||||||
return
|
|
||||||
}
|
|
||||||
focused = event.detail.value
|
focused = event.detail.value
|
||||||
}
|
}
|
||||||
|
function handleTapped(event) {
|
||||||
|
focused = !focused
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="sc-carousel__carousel-container">
|
<div class="sc-carousel__carousel-container">
|
||||||
@@ -336,8 +336,11 @@
|
|||||||
class="sc-carousel__pages-window"
|
class="sc-carousel__pages-window"
|
||||||
bind:this={pageWindowElement}
|
bind:this={pageWindowElement}
|
||||||
|
|
||||||
use:pausable
|
use:hoverable
|
||||||
on:pausedToggle={handlePausedToggle}
|
on:hovered={handleHovered}
|
||||||
|
|
||||||
|
use:tappable
|
||||||
|
on:tapped={handleTapped}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="sc-carousel__pages-container"
|
class="sc-carousel__pages-container"
|
||||||
|
|||||||
@@ -102,8 +102,8 @@
|
|||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
## Autoplay with pause on focus!anchorId:features-autoplay-pause-on-focus;
|
## Autoplay with pause on focus!anchorId:features-autoplay-pause-on-focus;
|
||||||
**For desktop** - hover over the carousel to toggle the autoplay.
|
|
||||||
**For touchable devices** - tap the carousel to toggle the autoplay.
|
**For touchable devices** - tap the carousel to toggle the autoplay.
|
||||||
|
**For non-touchable devices** - hover over the carousel to pause the autoplay.
|
||||||
|
|
||||||
<Carousel
|
<Carousel
|
||||||
autoplay
|
autoplay
|
||||||
@@ -271,7 +271,7 @@ Import component:
|
|||||||
| `autoplay` | `boolean` | `false` | Enables auto play of pages |
|
| `autoplay` | `boolean` | `false` | Enables auto play of pages |
|
||||||
| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
|
| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
|
||||||
| `autoplayDirection` | `string` | `'next'` | Autoplay change direction (`next` or `prev`) |
|
| `autoplayDirection` | `string` | `'next'` | Autoplay change direction (`next` or `prev`) |
|
||||||
| `pauseOnFocus` | `boolean` | `false` | Pauses autoplay on focus (for desktop - hover over the carousel to toggle the autoplay, for touchable devices - tap the carousel to toggle the autoplay) |
|
| `pauseOnFocus` | `boolean` | `false` | Pauses autoplay on focus (for touchable devices - tap the carousel to toggle the autoplay, for non-touchable devices - hover over the carousel to pause the autoplay) |
|
||||||
| `autoplayProgressVisible` | `boolean` | `false` | Shows autoplay duration progress indicator |
|
| `autoplayProgressVisible` | `boolean` | `false` | Shows autoplay duration progress indicator |
|
||||||
| `dots` | `boolean` | `true` | Current page indicator dots |
|
| `dots` | `boolean` | `true` | Current page indicator dots |
|
||||||
| `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function |
|
| `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function |
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { setIntervalImmediate } from './interval'
|
|
||||||
|
|
||||||
// resize event
|
// resize event
|
||||||
export function addResizeEventListener(cb) {
|
export function addResizeEventListener(cb) {
|
||||||
window.addEventListener('resize', cb)
|
window.addEventListener('resize', cb)
|
||||||
@@ -17,29 +15,3 @@ export function createDispatcher(source) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getIsTouchable() {
|
|
||||||
return (
|
|
||||||
('ontouchstart' in window)
|
|
||||||
// || // not changing value during browser view switching (mobile <-> desktop)
|
|
||||||
// (navigator.maxTouchPoints > 0) ||
|
|
||||||
// (navigator.msMaxTouchPoints > 0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addTouchableChangeEventListener(cb) {
|
|
||||||
let isTouchable = null
|
|
||||||
|
|
||||||
function handleTouchableChange() {
|
|
||||||
const isTouchableNext = getIsTouchable();
|
|
||||||
if (isTouchable !== isTouchableNext) {
|
|
||||||
cb(isTouchableNext)
|
|
||||||
isTouchable = isTouchableNext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const interval = setIntervalImmediate(handleTouchableChange, 500);
|
|
||||||
return () => {
|
|
||||||
clearInterval(interval)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user