Skip to content

Commit

Permalink
#416 - Add watchDrag option
Browse files Browse the repository at this point in the history
  • Loading branch information
davidjerleke committed Apr 24, 2023
1 parent 00a460a commit 4d8953b
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function ClassNames(userOptions: ClassNamesOptionsType = {}): ClassNamesType {

root = carousel.rootNode()
slides = carousel.slideNodes()
const isDraggable = carousel.internalEngine().options.draggable
const isDraggable = !!carousel.internalEngine().options.watchDrag

if (isDraggable) {
addClass(root, options.draggable)
Expand Down
29 changes: 18 additions & 11 deletions packages/embla-carousel-docs/src/content/pages/api/options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -231,15 +231,6 @@ Set scroll duration when triggered by any of the API methods. Higher numbers ena

---

### draggable

Type: <BrandPrimaryText>`boolean`</BrandPrimaryText>
Default: <BrandSecondaryText>`true`</BrandSecondaryText>

Enables for scrolling the carousel with mouse and touch interactions.

---

### inViewThreshold

Type: <BrandPrimaryText>`number`</BrandPrimaryText>
Expand Down Expand Up @@ -310,12 +301,28 @@ Set the initial scroll snap to the given number. First snap index starts at `0`.

---

### watchDrag

Type: <BrandPrimaryText>`boolean | (event: MouseEvent | TouchEvent, emblaApi: EmblaCarouselType) => boolean | void`</BrandPrimaryText>
Default: <BrandSecondaryText>`true`</BrandSecondaryText>

Enables for scrolling the carousel with mouse and touch interactions. Set this to `false` to disable drag events or pass a custom callback to add your own drag logic.

<Admonition type="note">
**Note:** When passing a custom callback it will run **before** the default
Embla drag behaviour. Return `true` in your callback if you want Embla to run
its default drag behaviour after your callback, or return `false` if you want
to disable it.
</Admonition>

---

### watchResize

Type: <BrandPrimaryText>`boolean | (entries: ResizeObserverEntry[], emblaApi: EmblaCarouselType) => boolean | void`</BrandPrimaryText>
Default: <BrandSecondaryText>`true`</BrandSecondaryText>

Embla automatically watches the [container](/api/methods/#containernode/) and [slides](/api/methods/#slidenodes/) for size changes and runs [reInit](/api/methods/#reinit/) when any size has changed. Set this to `false` to disable this behaviour or pass a custom callback to write your own resize logic.
Embla automatically watches the [container](/api/methods/#containernode/) and [slides](/api/methods/#slidenodes/) for size changes and runs [reInit](/api/methods/#reinit/) when any size has changed. Set this to `false` to disable this behaviour or pass a custom callback to add your own resize logic.

<Admonition type="note">
**Note:** When passing a custom callback it will run **before** the default
Expand All @@ -331,7 +338,7 @@ Embla automatically watches the [container](/api/methods/#containernode/) and [s
Type: <BrandPrimaryText>`boolean | (mutations: MutationRecord[], emblaApi: EmblaCarouselType) => boolean | void`</BrandPrimaryText>
Default: <BrandSecondaryText>`true`</BrandSecondaryText>

Embla automatically watches the [container](/api/methods/#containernode/) for **added** and/or **removed** slides and runs [reInit](/api/methods/#reinit/) if needed. Set this to `false` to disable this behaviour or pass a custom callback to write your own resize logic.
Embla automatically watches the [container](/api/methods/#containernode/) for **added** and/or **removed** slides and runs [reInit](/api/methods/#reinit/) if needed. Set this to `false` to disable this behaviour or pass a custom callback to add your own slides changed logic.

<Admonition type="note">
**Note:** When passing a custom callback it will run **before** the default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This guide will show you **how** to **add previous and next buttons** using the

## Button placement

Assuming your carousel is [draggable](/api/options/#draggable), it's important to note that the **root node** will **respond to pointer events**. The root node is the one that is passed to the `EmblaCarousel` initializer. In the following example, it has the class name `embla`:
Assuming your carousel is [draggable](/api/options/#watchdrag), it's important to note that the **root node** will **respond to pointer events**. The root node is the one that is passed to the `EmblaCarousel` initializer. In the following example, it has the class name `embla`:

```html
<div class="embla">
Expand Down
27 changes: 22 additions & 5 deletions packages/embla-carousel/src/components/DragHandler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EmblaCarouselType } from './EmblaCarousel'
import { AnimationType } from './Animation'
import { CounterType } from './Counter'
import { DirectionType } from './Direction'
Expand All @@ -9,12 +10,19 @@ import { ScrollBodyType } from './ScrollBody'
import { ScrollTargetType } from './ScrollTarget'
import { ScrollToType } from './ScrollTo'
import { Vector1D, Vector1DType } from './Vector1d'
import { deltaAbs, factorAbs, mathAbs, mathSign } from './utils'
import { deltaAbs, factorAbs, isBoolean, mathAbs, mathSign } from './utils'
import { PercentOfViewType } from './PercentOfView'
import { Limit } from './Limit'

type DragHandlerCallbackType = (
evt: PointerEventType,
emblaApi: EmblaCarouselType,
) => boolean | void

export type DragHandlerOptionType = boolean | DragHandlerCallbackType

export type DragHandlerType = {
init: () => void
init: (emblaApi: EmblaCarouselType, watchDrag: DragHandlerOptionType) => void
destroy: () => void
pointerDown: () => boolean
}
Expand Down Expand Up @@ -55,14 +63,23 @@ export function DragHandler(
let preventClick = false
let isMouse = false

function init(): void {
function init(
emblaApi: EmblaCarouselType,
watchDrag: DragHandlerOptionType,
): void {
if (!watchDrag) return

function downIfAllowed(evt: PointerEventType): void {
if (isBoolean(watchDrag) || watchDrag(evt, emblaApi)) down(evt)
}

const node = rootNode
initEvents
.add(node, 'dragstart', (evt) => evt.preventDefault(), nonPassiveEvent)
.add(node, 'touchmove', () => undefined, nonPassiveEvent)
.add(node, 'touchend', () => undefined)
.add(node, 'touchstart', down)
.add(node, 'mousedown', down)
.add(node, 'touchstart', downIfAllowed)
.add(node, 'mousedown', downIfAllowed)
.add(node, 'touchcancel', up)
.add(node, 'contextmenu', up)
.add(node, 'click', click, true)
Expand Down
4 changes: 2 additions & 2 deletions packages/embla-carousel/src/components/EmblaCarousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ function EmblaCarousel(
}
engine.slideLooper.loop()
}
if (options.draggable && container.offsetParent && slides.length) {
engine.dragHandler.init()
if (container.offsetParent && slides.length) {
engine.dragHandler.init(self, options.watchDrag)
}
}

Expand Down
5 changes: 3 additions & 2 deletions packages/embla-carousel/src/components/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AxisOptionType } from './Axis'
import { SlidesToScrollOptionType } from './SlidesToScroll'
import { DirectionOptionType } from './Direction'
import { ScrollContainOptionType } from './ScrollContain'
import { DragHandlerOptionType } from './DragHandler'
import { ResizeHandlerOptionType } from './ResizeHandler'
import { SlidesHandlerOptionType } from './SlidesHandler'

Expand All @@ -26,12 +27,12 @@ export type OptionsType = CreateOptionsType<{
direction: DirectionOptionType
slidesToScroll: SlidesToScrollOptionType
dragFree: boolean
draggable: boolean
inViewThreshold: number
loop: boolean
skipSnaps: boolean
duration: number
startIndex: number
watchDrag: DragHandlerOptionType
watchResize: ResizeHandlerOptionType
watchSlides: SlidesHandlerOptionType
}>
Expand All @@ -46,13 +47,13 @@ export const defaultOptions: OptionsType = {
slidesToScroll: 1,
breakpoints: {},
dragFree: false,
draggable: true,
inViewThreshold: 0,
loop: false,
skipSnaps: false,
duration: 25,
startIndex: 0,
active: true,
watchDrag: true,
watchResize: true,
watchSlides: true,
}
Expand Down
2 changes: 1 addition & 1 deletion packages/embla-carousel/src/components/ResizeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function ResizeHandler(
containerSize = readSize(container)
slideSizes = slides.map(readSize)

const defaultCallback = (entries: ResizeObserverEntry[]): void => {
function defaultCallback(entries: ResizeObserverEntry[]): void {
for (const entry of entries) {
const isContainer = entry.target === container
const slideIndex = slides.indexOf(<HTMLElement>entry.target)
Expand Down
2 changes: 1 addition & 1 deletion packages/embla-carousel/src/components/SlidesHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function SlidesHandler(container: HTMLElement): SlidesHandlerType {
): void {
if (!watchSlides) return

const defaultCallback = (mutations: MutationRecord[]): void => {
function defaultCallback(mutations: MutationRecord[]): void {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
emblaApi.reInit()
Expand Down

0 comments on commit 4d8953b

Please sign in to comment.