Skip to content

Commit 5788dad

Browse files
committed
Implement #202.
1 parent 3d1ec89 commit 5788dad

19 files changed

+333
-134
lines changed

packages/embla-carousel/src/components/Animations.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export type AnimationsUpdateType = (engine: EngineType) => void
66
export type AnimationsRenderType = (engine: EngineType, alpha: number) => void
77

88
export type AnimationsType = {
9-
init: () => void
9+
init: (ownerWindow: WindowType) => void
1010
destroy: () => void
1111
start: () => void
1212
stop: () => void
@@ -15,19 +15,21 @@ export type AnimationsType = {
1515
}
1616

1717
export function Animations(
18-
ownerDocument: Document,
19-
ownerWindow: WindowType,
2018
update: () => void,
2119
render: (alpha: number) => void
2220
): AnimationsType {
2321
const documentVisibleHandler = EventStore()
2422
const fixedTimeStep = 1000 / 60
2523

24+
let windowInstance: WindowType
2625
let lastTimeStamp: number | null = null
2726
let accumulatedTime = 0
2827
let animationId = 0
2928

30-
function init(): void {
29+
function init(ownerWindow: WindowType): void {
30+
const ownerDocument = ownerWindow.document
31+
windowInstance = ownerWindow
32+
3133
documentVisibleHandler.add(ownerDocument, 'visibilitychange', () => {
3234
if (ownerDocument.hidden) reset()
3335
})
@@ -59,17 +61,17 @@ export function Animations(
5961
render(alpha)
6062

6163
if (animationId) {
62-
animationId = ownerWindow.requestAnimationFrame(animate)
64+
animationId = windowInstance.requestAnimationFrame(animate)
6365
}
6466
}
6567

6668
function start(): void {
6769
if (animationId) return
68-
animationId = ownerWindow.requestAnimationFrame(animate)
70+
animationId = windowInstance.requestAnimationFrame(animate)
6971
}
7072

7173
function stop(): void {
72-
ownerWindow.cancelAnimationFrame(animationId)
74+
windowInstance.cancelAnimationFrame(animationId)
7375
lastTimeStamp = null
7476
accumulatedTime = 0
7577
animationId = 0

packages/embla-carousel/src/components/Axis.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NodeRectType } from './NodeRects'
1+
import { NodeRectType } from './NodeHandler'
22

33
export type AxisOptionType = 'x' | 'y'
44
export type AxisDirectionOptionType = 'ltr' | 'rtl'
@@ -9,6 +9,7 @@ export type AxisType = {
99
cross: AxisOptionType
1010
startEdge: AxisEdgeType
1111
endEdge: AxisEdgeType
12+
isRightToLeft: boolean
1213
measureSize: (nodeRect: NodeRectType) => number
1314
direction: (n: number) => number
1415
}
@@ -17,11 +18,11 @@ export function Axis(
1718
axis: AxisOptionType,
1819
contentDirection: AxisDirectionOptionType
1920
): AxisType {
20-
const isRightToLeft = contentDirection === 'rtl'
2121
const isVertical = axis === 'y'
2222
const scroll = isVertical ? 'y' : 'x'
2323
const cross = isVertical ? 'x' : 'y'
24-
const sign = !isVertical && isRightToLeft ? -1 : 1
24+
const isRightToLeft = contentDirection === 'rtl' && !isVertical
25+
const sign = isRightToLeft ? -1 : 1
2526
const startEdge = getStartEdge()
2627
const endEdge = getEndEdge()
2728

@@ -49,6 +50,7 @@ export function Axis(
4950
cross,
5051
startEdge,
5152
endEdge,
53+
isRightToLeft,
5254
measureSize,
5355
direction
5456
}

packages/embla-carousel/src/components/DragHandler.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
} from './utils'
2222

2323
export type DragHandlerType = {
24-
init: () => void
24+
init: (windowInstance: WindowType) => void
2525
destroy: () => void
2626
pointerDown: () => boolean
2727
}
@@ -30,8 +30,6 @@ export function DragHandler(
3030
active: boolean,
3131
axis: AxisType,
3232
rootNode: HTMLElement,
33-
ownerDocument: Document,
34-
ownerWindow: WindowType,
3533
target: Vector1DType,
3634
dragTracker: DragTrackerType,
3735
location: Vector1DType,
@@ -58,6 +56,8 @@ export function DragHandler(
5856
const freeForceBoost = { mouse: 500, touch: 600 }
5957
const baseSpeed = dragFree ? 43 : 25
6058

59+
let ownerDocument: Document
60+
let ownerWindow: WindowType
6161
let isMoving = false
6262
let startScroll = 0
6363
let startCross = 0
@@ -66,9 +66,14 @@ export function DragHandler(
6666
let preventClick = false
6767
let isMouse = false
6868

69-
function init(): void {
69+
function init(windowInstance: WindowType): void {
7070
if (!active) return
7171

72+
ownerDocument = windowInstance.document
73+
ownerWindow = windowInstance
74+
75+
dragTracker.init(windowInstance)
76+
7277
const node = rootNode
7378
initEvents
7479
.add(node, 'dragstart', (evt) => evt.preventDefault(), nonPassiveEvent)

packages/embla-carousel/src/components/DragTracker.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ type PointerCoordType = keyof Touch | keyof MouseEvent
55
export type PointerEventType = TouchEvent | MouseEvent
66

77
export type DragTrackerType = {
8+
init: (windowInstance: WindowType) => void
89
pointerDown: (evt: PointerEventType) => number
910
pointerMove: (evt: PointerEventType) => number
1011
pointerUp: (evt: PointerEventType) => number
1112
readPoint: (evt: PointerEventType, evtAxis?: AxisOptionType) => number
1213
}
1314

14-
export function DragTracker(
15-
axis: AxisType,
16-
ownerWindow: WindowType
17-
): DragTrackerType {
15+
export function DragTracker(axis: AxisType): DragTrackerType {
1816
const logInterval = 170
1917

18+
let ownerWindow: WindowType
2019
let startEvent: PointerEventType
2120
let lastEvent: PointerEventType
2221

22+
function init(windowInstance: WindowType): void {
23+
ownerWindow = windowInstance
24+
}
25+
2326
function readTime(evt: PointerEventType): number {
2427
return evt.timeStamp
2528
}
@@ -57,6 +60,7 @@ export function DragTracker(
5760
}
5861

5962
const self: DragTrackerType = {
63+
init,
6064
pointerDown,
6165
pointerMove,
6266
pointerUp,

packages/embla-carousel/src/components/EmblaCarousel.ts

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { EventStore } from './EventStore'
33
import { WatchHandler, WatchHandlerType } from './WatchHandler'
44
import { EventHandler, EventHandlerType } from './EventHandler'
55
import { defaultOptions, EmblaOptionsType, OptionsType } from './Options'
6+
import { NodeHandler, NodeHandlerType } from './NodeHandler'
67
import { OptionsHandler } from './OptionsHandler'
78
import { PluginsHandler } from './PluginsHandler'
89
import { EmblaPluginsType, EmblaPluginType } from './Plugins'
9-
import { isNumber, isString, WindowType } from './utils'
1010
import { ScrollToDirectionType } from './ScrollTo'
11+
import { isNumber, isSSR } from './utils'
12+
import { SsrHandler, SsrHandlerType } from './SsrHandler'
1113

1214
export type EmblaCarouselType = {
1315
canScrollNext: () => boolean
@@ -43,16 +45,15 @@ export type EmblaCarouselType = {
4345
jump?: boolean,
4446
direction?: ScrollToDirectionType
4547
) => void
48+
ssrStyles: () => string
4649
}
4750

4851
function EmblaCarousel(
4952
root: HTMLElement,
5053
userOptions?: EmblaOptionsType,
5154
userPlugins?: EmblaPluginType[]
5255
): EmblaCarouselType {
53-
const ownerDocument = root.ownerDocument
54-
const ownerWindow = <WindowType>ownerDocument.defaultView
55-
const optionsHandler = OptionsHandler(ownerWindow)
56+
const optionsHandler = OptionsHandler()
5657
const pluginsHandler = PluginsHandler(optionsHandler)
5758
const mediaHandlers = EventStore()
5859
const watchHandler = WatchHandler()
@@ -64,6 +65,8 @@ function EmblaCarousel(
6465

6566
let destroyed = false
6667
let engine: EngineType
68+
let nodeHandler: NodeHandlerType
69+
let ssrHandler: SsrHandlerType
6770
let optionsBase = mergeOptions(defaultOptions, EmblaCarousel.globalOptions)
6871
let options = mergeOptions(optionsBase)
6972
let pluginList: EmblaPluginType[] = []
@@ -72,35 +75,24 @@ function EmblaCarousel(
7275
let container: HTMLElement
7376
let slides: HTMLElement[]
7477

75-
function storeElements(): void {
76-
const { container: userContainer, slides: userSlides } = options
77-
78-
const customContainer = isString(userContainer)
79-
? root.querySelector(userContainer)
80-
: userContainer
81-
container = <HTMLElement>(customContainer || root.children[0])
82-
83-
const customSlides = isString(userSlides)
84-
? container.querySelectorAll(userSlides)
85-
: userSlides
86-
slides = <HTMLElement[]>[].slice.call(customSlides || container.children)
87-
}
88-
89-
function createEngine(options: OptionsType): EngineType {
78+
function createEngine(
79+
options: OptionsType,
80+
container: HTMLElement,
81+
slides: HTMLElement[]
82+
): EngineType {
9083
const engine = Engine(
9184
root,
9285
container,
9386
slides,
94-
ownerDocument,
95-
ownerWindow,
9687
options,
88+
nodeHandler,
9789
eventHandler,
9890
watchHandler
9991
)
10092

10193
if (options.loop && !engine.slideLooper.canLoop()) {
10294
const optionsWithoutLoop = Object.assign({}, options, { loop: false })
103-
return createEngine(optionsWithoutLoop)
95+
return createEngine(optionsWithoutLoop, container, slides)
10496
}
10597
return engine
10698
}
@@ -111,32 +103,50 @@ function EmblaCarousel(
111103
): void {
112104
if (destroyed) return
113105

106+
nodeHandler = NodeHandler(root)
107+
const { ownerWindow } = nodeHandler
108+
109+
optionsHandler.init(ownerWindow)
114110
optionsBase = mergeOptions(optionsBase, withOptions)
115111
options = optionsAtMedia(optionsBase)
116112
pluginList = withPlugins || pluginList
117113

118-
storeElements()
114+
const nodes = nodeHandler.getNodes(options)
115+
container = nodes.container
116+
slides = nodes.slides
117+
engine = createEngine(options, container, slides)
119118

120-
engine = createEngine(options)
119+
ssrHandler = SsrHandler(
120+
container,
121+
engine.axis,
122+
nodeHandler,
123+
optionsBase,
124+
mergeOptions,
125+
createEngine
126+
)
121127

122128
optionsMediaQueries([
123129
optionsBase,
124130
...pluginList.map(({ options }) => options)
125131
]).forEach((query) => mediaHandlers.add(query, 'change', reActivate))
126132

127133
if (!options.active) return
134+
if (!ownerWindow) return
135+
if (isSSR()) return
128136

129137
engine.translate.to(engine.location.get())
130-
engine.animation.init()
131-
engine.slidesInView.init()
132-
engine.slideFocus.init()
133-
engine.resizeHandler.init()
134-
engine.slidesHandler.init()
138+
engine.animation.init(ownerWindow)
139+
engine.resizeHandler.init(ownerWindow)
140+
engine.slidesInView.init(ownerWindow)
141+
engine.slidesHandler.init(ownerWindow)
135142
engine.eventHandler.init(self)
136143
engine.watchHandler.init(self)
144+
engine.slideFocus.init()
137145

138146
if (engine.options.loop) engine.slideLooper.loop()
139-
if (container.offsetParent && slides.length) engine.dragHandler.init()
147+
if (container.offsetParent && slides.length) {
148+
engine.dragHandler.init(ownerWindow)
149+
}
140150

141151
pluginApis = pluginsHandler.init(self, pluginList)
142152
}
@@ -180,6 +190,7 @@ function EmblaCarousel(
180190
direction?: ScrollToDirectionType
181191
): void {
182192
if (!options.active || destroyed) return
193+
183194
engine.scrollBody
184195
.useBaseFriction()
185196
.useDuration(jump === true ? 0 : options.duration)
@@ -245,6 +256,10 @@ function EmblaCarousel(
245256
return pluginApis
246257
}
247258

259+
function ssrStyles(): string {
260+
return ssrHandler.getStyles()
261+
}
262+
248263
function internalEngine(): EngineType {
249264
return engine
250265
}
@@ -286,11 +301,12 @@ function EmblaCarousel(
286301
slideNodes,
287302
slidesInView,
288303
slidesNotInView,
289-
snapList
304+
snapList,
305+
ssrStyles
290306
}
291307

292308
activate(userOptions, userPlugins)
293-
setTimeout(() => eventHandler.emit('init', null), 0)
309+
setTimeout(() => eventHandler.emit('init', null), 0) // TODO: Won't work in SSR
294310
return self
295311
}
296312

0 commit comments

Comments
 (0)