Merge pull request #65 from vadimkorr/feature/#56_Split-handlers

feature/#56 Fix touchable handlers
This commit is contained in:
Vadim
2021-08-16 22:37:07 +03:00
committed by GitHub
14 changed files with 68 additions and 144 deletions

View File

@@ -86,7 +86,7 @@ npm install svelte-carousel -D
| `autoplay` | `boolean` | `false` | Enables autoplay of pages |
| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
| `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 |
| `dots` | `boolean` | `true` | Current page indicator dots |
| `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function |

View File

@@ -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)
}

View File

@@ -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)
},
}
}

View File

@@ -1 +0,0 @@
export * from './focusable'

View 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)
}

View 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)
},
}
}

View File

@@ -0,0 +1 @@
export * from './hoverable'

View File

@@ -1 +0,0 @@
export * from './pausable'

View File

@@ -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
}
}
}

View File

@@ -70,6 +70,7 @@ export function swipeable(node, { thresholdProvider }) {
}
function handleUp(event) {
event.preventDefault();
removeEndEventListener(window, handleUp)
removeMoveEventListener(window, handleMove)

View File

@@ -1,5 +1,4 @@
import { createDispatcher } from '../../utils/event'
import { get } from '../../utils/object'
import { getDistance } from '../../utils/math'
import {
addFocusinEventListener,
@@ -15,9 +14,8 @@ import {
/**
* tappable events are for touchable devices only
*/
export function tappable(node, options) {
// pass custom dispatch fn in order to re-translate dispatched event
const dispatch = get(options, 'dispatch', createDispatcher(node))
export function tappable(node) {
const dispatch = createDispatcher(node)
let tapStartedAt = 0
let tapStartPos = { x: 0, y: 0 }
@@ -44,6 +42,7 @@ export function tappable(node, options) {
}
function handleTapend(event) {
event.preventDefault();
removeFocusoutEventListener(node, handleTapend)
const touch = event.changedTouches[0]

View File

@@ -6,7 +6,8 @@
import Progress from '../Progress/Progress.svelte'
import { NEXT, PREV } from '../../direction'
import { swipeable } from '../../actions/swipeable'
import { pausable } from '../../actions/pausable'
import { hoverable } from '../../actions/hoverable'
import { tappable } from '../../actions/tappable'
import {
addResizeEventListener,
removeResizeEventListener
@@ -310,13 +311,12 @@
await offsetPage({ animated: true })
}
function handlePausedToggle(event) {
if (event.detail.isTouchable) {
focused = !focused
return
}
function handleHovered(event) {
focused = event.detail.value
}
function handleTapped(event) {
focused = !focused
}
</script>
<div class="sc-carousel__carousel-container">
@@ -336,8 +336,11 @@
class="sc-carousel__pages-window"
bind:this={pageWindowElement}
use:pausable
on:pausedToggle={handlePausedToggle}
use:hoverable
on:hovered={handleHovered}
use:tappable
on:tapped={handleTapped}
>
<div
class="sc-carousel__pages-container"

View File

@@ -102,8 +102,8 @@
<Divider />
## 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 non-touchable devices** - hover over the carousel to pause the autoplay.
<Carousel
autoplay
@@ -271,7 +271,7 @@ Import component:
| `autoplay` | `boolean` | `false` | Enables auto play of pages |
| `autoplayDuration` | `number` | `3000` | Autoplay change interval (ms) |
| `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 |
| `dots` | `boolean` | `true` | Current page indicator dots |
| `timingFunction` | `string` | `'ease-in-out'` | CSS animation timing function |

View File

@@ -1,5 +1,3 @@
import { setIntervalImmediate } from './interval'
// resize event
export function addResizeEventListener(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)
}
}