Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add watchDrag option #461

Merged
merged 1 commit into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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