diff --git a/src/components/Carousel/Carousel.svelte b/src/components/Carousel/Carousel.svelte
index e32a4c0..e6dc87c 100644
--- a/src/components/Carousel/Carousel.svelte
+++ b/src/components/Carousel/Carousel.svelte
@@ -31,22 +31,18 @@
import { wait } from '../../utils/interval'
import { carouselEngine } from './carousel'
+ import { carousel2 } from './carousel2'
import { reactive } from './reactive'
- const data = reactive(
- {
- message: 'hello',
- someValue: 'some-value'
- },
- {
- renderFunction: (data) => {
- console.log('renderFunction watcher called', data.message)
- },
- }
- )
- console.log('console', data)
+ let currentPageIndex
- data.message = 'Hello!'
+ const [data, methods] = carousel2((key, value) => {
+ // console.log('onChange', key, value)
+ if (key === 'currentPageIndex') {
+ currentPageIndex = value
+ }
+ }) // put init data
+
const dispatch = createEventDispatcher()
@@ -76,7 +72,7 @@
*/
export let infinite
$: {
- setInfinite(infinite)
+ data.infinite = infinite
}
/**
@@ -151,13 +147,13 @@
throw new Error('pageIndex should be a number')
}
await showParticle(getParticleIndexByPageIndex({
- infinite,
+ infinite: data.infinite,
pageIndex,
- clonesCountHead: clonesCount.head,
- clonesCountTail: clonesCount.tail,
- particlesToScroll,
- particlesCount,
- particlesToShow,
+ clonesCountHead: data.clonesCountHead,
+ clonesCountTail: data.clonesCountTail,
+ particlesToScroll: data.particlesToScroll,
+ particlesCount: data.particlesCount,
+ particlesToShow: data.particlesToShow,
}), { animated })
}
@@ -171,44 +167,6 @@
await showNextPage({ animated })
}
-
- ///// ==========================
- let currentPageIndex
- let pagesCount
- let particlesCountWithoutClones
- let clonesCount
- let currentParticleIndex = 0
- let particlesCount = 0
- let _particlesToShow
- let _particlesToScroll
-
- const {
- setParticlesToShow,
- setParticlesToScroll,
- setParticlesCountWithoutClones,
- setPartialPageSize,
- setParticlesCount,
- setCurrentParticleIndex,
- setInitialPageIndex,
- setInfinite,
- prev,
- next,
- moveToParticle,
- } = carouselEngine((values, computed) => {
- // console.log('hello')
- currentPageIndex = computed.currentPageIndex
- pagesCount = computed.pagesCount
- particlesCountWithoutClones = values.particlesCountWithoutClones
- clonesCount = computed.clonesCount
- currentParticleIndex = values.currentParticleIndex
- particlesCount = values.particlesCount
- _particlesToShow = values.particlesToShow
- _particlesToScroll = values.particlesToScroll
- })
-
- ///// ==========================
-
-
let pageWindowWidth = 0
let particleWidth = 0
let offset = 0
@@ -220,7 +178,7 @@
width,
}) => {
pageWindowWidth = width
- particleWidth = pageWindowWidth / _particlesToShow
+ particleWidth = pageWindowWidth / data.particlesToShow
applyParticleSizes({
particlesContainerChildren: particlesContainer.children,
@@ -267,8 +225,8 @@
clonesToAppend,
clonesToPrepend,
} = getClones({
- clonesCountHead: clonesCount.head,
- clonesCountTail: clonesCount.tail,
+ clonesCountHead: data.clonesCountHead,
+ clonesCountTail: data.clonesCountTail,
particlesContainerChildren: particlesContainer.children,
})
applyClones({
@@ -281,9 +239,9 @@
async function applyAutoplayIfNeeded(autoplay) {
// prevent progress change if not infinite for first and last page
if (
- !infinite && (
- (autoplayDirection === NEXT && currentParticleIndex === particlesCount - 1) ||
- (autoplayDirection === PREV && currentParticleIndex === 0)
+ !data.infinite && (
+ (autoplayDirection === NEXT && data.currentParticleIndex === data.particlesCount - 1) ||
+ (autoplayDirection === PREV && data.currentParticleIndex === 0)
)
) {
progressManager.reset()
@@ -302,16 +260,16 @@
await tick()
cleanupFns.push(() => progressManager.reset())
if (particlesContainer && pageWindowElement) {
- setParticlesCountWithoutClones(particlesContainer.children.length)
- setParticlesToShow(particlesToShow)
- setParticlesToScroll(particlesToScroll)
+ data.particlesCountWithoutClones = particlesContainer.children.length
+ data.particlesToShow = particlesToShow
+ data.particlesToScroll = particlesToScroll
await tick()
- infinite && addClones()
+ data.infinite && addClones()
// call after adding clones
- setParticlesCount(particlesContainer.children.length)
- setInitialPageIndex(initialPageIndex)
+ data.particlesCount = particlesContainer.children.length
+ data.initialPageIndex = initialPageIndex
pageWindowElementResizeObserver.observe(pageWindowElement);
}
@@ -325,13 +283,13 @@
async function handlePageChange(pageIndex) {
await showParticle(getParticleIndexByPageIndex({
- infinite,
+ infinite: data.infinite,
pageIndex,
- clonesCountHead: clonesCount.head,
- clonesCountTail: clonesCount.tail,
- particlesToScroll,
- particlesCount,
- particlesToShow: _particlesToShow,
+ clonesCountHead: data.clonesCountHead,
+ clonesCountTail: data.clonesCountTail,
+ particlesToScroll: data.particlesToScroll,
+ particlesCount: data.particlesCount,
+ particlesToShow: data.particlesToShow,
}))
}
@@ -340,7 +298,7 @@
return new Promise((resolve) => {
// _duration is an offset animation time
_duration = animated ? duration : 0
- offset = -currentParticleIndex * particleWidth
+ offset = -data.currentParticleIndex * particleWidth
setTimeout(() => {
resolve()
}, _duration)
@@ -350,12 +308,12 @@
// makes delayed jump to 1st or last element
async function jumpIfNeeded() {
let jumped = false
- if (infinite) {
- if (currentParticleIndex === 0) {
- await showParticle(particlesCount - clonesCount.total, { animated: false })
+ if (data.infinite) {
+ if (data.currentParticleIndex === 0) {
+ await showParticle(data.particlesCount - data.clonesCountTotal, { animated: false })
jumped = true
- } else if (currentParticleIndex === particlesCount - clonesCount.tail) {
- await showParticle(clonesCount.head, { animated: false })
+ } else if (data.currentParticleIndex === data.particlesCount - data.clonesCountTail) {
+ await showParticle(data.clonesCountHead, { animated: false })
jumped = true
}
}
@@ -378,8 +336,9 @@
}
async function showParticle(particleIndex, options) {
+ console.log('showParticle => particleIndex', particleIndex)
await changePage(
- () => moveToParticle(particleIndex),
+ () => methods.moveToParticle(particleIndex),
options
)
}
@@ -387,7 +346,7 @@
if (disabled) return
await changePage(
- prev,
+ methods.prev,
options,
)
}
@@ -395,7 +354,7 @@
if (disabled) return
await changePage(
- next,
+ methods.next,
options,
)
}
@@ -415,7 +374,7 @@
}
function handleSwipeEnd() {
if (!swiping) return
- showParticle(currentParticleIndex)
+ showParticle(data.currentParticleIndex)
}
async function handleSwipeFailed() {
if (!swiping) return
@@ -437,7 +396,7 @@
@@ -481,7 +440,7 @@
@@ -492,11 +451,11 @@
handlePageChange(event.detail)}
>
diff --git a/src/components/Carousel/carousel2.js b/src/components/Carousel/carousel2.js
new file mode 100644
index 0000000..9134a1c
--- /dev/null
+++ b/src/components/Carousel/carousel2.js
@@ -0,0 +1,111 @@
+import { NEXT, PREV } from '../../direction'
+import {
+ applyParticleSizes,
+ getCurrentPageIndexByCurrentParticleIndex,
+ getPartialPageSize,
+ getPagesCountByParticlesCount,
+ getParticleIndexByPageIndex,
+ createResizeObserver,
+} from '../../utils/page'
+import { getClones, applyClones, getClonesCount } from '../../utils/clones'
+import { getAdjacentIndexes } from '../../utils/lazy'
+import { getValueInRange } from '../../utils/math'
+import { get } from '../../utils/object'
+import { ProgressManager } from '../../utils/ProgressManager'
+import { wait } from '../../utils/interval'
+import { reactive } from './reactive'
+
+// return only getters
+export const carousel2 = (onChange) => {
+ return reactive(
+ {
+ particlesCountWithoutClones: 0,
+ particlesToShow: 1,
+ particlesToScroll: 1,
+ initialPageIndex: 1,
+ particlesCount: 1,
+ currentParticleIndex: 1,
+ infinite: false,
+ clonesCountHead: 0,
+ clonesCountTail: 0,
+ clonesCountTotal: 0,
+ partialPageSize: 1,
+ currentPageIndex: 1,
+ pagesCount: 1,
+ },
+ {
+ setCurrentPageIndex: (data) => {
+ const ind = getCurrentPageIndexByCurrentParticleIndex({
+ currentParticleIndex: data.currentParticleIndex,
+ particlesCount: data.particlesCount,
+ clonesCountHead: data.clonesCountHead,
+ clonesCountTotal: data.clonesCountTotal,
+ infinite: data.initialPageIndex,
+ particlesToScroll: data.particlesToScroll,
+ })
+ data.currentPageIndex = ind
+ console.log('===> data.currentPageIndex', ind)
+ },
+ setPartialPageSize: (data) => {
+ data.partialPageSize = getPartialPageSize({
+ particlesToScroll: data.particlesToScroll,
+ particlesToShow: data.particlesToShow,
+ particlesCountWithoutClones: data.particlesCountWithoutClones,
+ })
+ },
+ setClonesCount: (data) => {
+ const { head, tail } = getClonesCount({
+ infinite: data.infinite,
+ particlesToShow: data.particlesToShow,
+ partialPageSize: data.partialPageSize,
+ })
+
+ data.clonesCountHead = head
+ data.clonesCountTail = tail
+ data.clonesCountTotal = head + tail
+ },
+ setPagesCount: (data) => {
+ data.pagesCount = getPagesCountByParticlesCount({
+ infinite: data.infinite,
+ particlesCountWithoutClones: data.particlesCountWithoutClones,
+ particlesToScroll: data.particlesToScroll,
+ })
+ },
+ },
+ {
+ prev: (data) => {
+ const newCurrentParticleIndex = getParticleIndexByPageIndex({
+ infinite: data.infinite,
+ pageIndex: data.currentPageIndex - 1,
+ clonesCountHead: data.clonesCountHead,
+ clonesCountTail: data.clonesCountTail,
+ particlesToScroll: data.particlesToScroll,
+ particlesCount: data.particlesCount,
+ particlesToShow: data.particlesToShow,
+ })
+ data.currentParticleIndex = newCurrentParticleIndex
+ },
+ next: (data) => {
+ const newCurrentParticleIndex = getParticleIndexByPageIndex({
+ infinite: data.infinite,
+ pageIndex: data.currentPageIndex + 1,
+ clonesCountHead: data.clonesCountHead,
+ clonesCountTail: data.clonesCountTail,
+ particlesToScroll: data.particlesToScroll,
+ particlesCount: data.particlesCount,
+ particlesToShow: data.particlesToShow,
+ })
+ data.currentParticleIndex = newCurrentParticleIndex
+ },
+ moveToParticle: (data, particleIndex) => {
+ const newCurrentParticleIndex = getValueInRange(
+ 0,
+ particleIndex,
+ data.particlesCount - 1
+ )
+ data.currentParticleIndex = newCurrentParticleIndex
+ },
+ },
+ onChange
+ )
+}
diff --git a/src/components/Carousel/reactive.js b/src/components/Carousel/reactive.js
index cb0518b..cfab51f 100644
--- a/src/components/Carousel/reactive.js
+++ b/src/components/Carousel/reactive.js
@@ -1,80 +1,116 @@
-// let data = {
-// message: '',
-// }
-
-// let methods = {
-// changeMessage: function () {
-// data.message = document.getElementById('messageInput').value
-// },
-// }
-
// Code that has to run when a
// reactive property changes it's value.
-let target = null
-class Dep {
- constructor() {
- this.subscribers = []
- }
- depend() {
- // Saves target function into subscribers array
- if (target && !this.subscribers.includes(target)) {
- this.subscribers.push(target)
+const objectsAreSame = (x, y) => {
+ // return false
+ let _objectsAreSame = true
+ for (let propertyName in x) {
+ if (Number.isNaN(x[propertyName]) || Number.isNaN(y[propertyName])) {
+ continue
+ }
+ if (x[propertyName] !== y[propertyName]) {
+ _objectsAreSame = false
+ break
}
}
- notify() {
- // Replays target functions saved in the subscribers array
- this.subscribers.forEach((sub) => sub())
+
+ return _objectsAreSame
+}
+
+const getObject = (oldData, newData) => {
+ const newDeps = {}
+
+ Object.entries(oldData).forEach(([key, value]) => {
+ // console.log('oldData', key, value)
+ newDeps[key] = newData[key]
+ })
+ // console.log('isDiff', oldData, newDeps)
+
+ return newDeps
+}
+
+const useSubscription = () => {
+ const subscribers = {}
+
+ const memoDependency = (target, dep) => {
+ const { watcherName, fn } = target
+ const { key, value } = dep
+
+ if (!subscribers[watcherName]) {
+ subscribers[watcherName] = {
+ deps: {},
+ fn,
+ }
+ }
+ subscribers[watcherName].deps[key] = value
+ }
+
+ return {
+ subscribe: (target, dep) => {
+ if (target) {
+ memoDependency(target, dep)
+ }
+ },
+ notify: (data) => {
+ Object.entries(subscribers).forEach(([watcherName, { deps }]) => {
+ const newDeps = getObject(deps, data)
+ if (!objectsAreSame(deps, newDeps)) {
+ subscribers[watcherName].deps = newDeps
+ subscribers[watcherName].fn()
+ }
+ })
+ },
}
}
-let watch = function (func) {
- // Here, a watcher is a function that encapsulates the code
- // that needs to recorded/watched.
- // PS: It just runs once, because after that, the target code is stored
- // in the subscriber's list of the Dep() instance.
- target = func // Then it assigns the function to target
- target() // Run the target function
- target = null // Reset target to null
+const useWatcher = () => {
+ let target = null
+
+ return {
+ watch: (watcherName, fn) => {
+ target = {
+ watcherName,
+ fn,
+ }
+ target.fn()
+ target = null
+ },
+ getTarget: () => {
+ return target
+ },
+ }
}
-// reactive(
-// {
-// message: '',
-// },
-// {
-// renderFunction: (data) => {
-// console.log(data.message)
-// },
-// }
-// )
+export const reactive = (data, watchers, methods, onChange) => {
+ const { subscribe, notify } = useSubscription()
+ const { watch, getTarget } = useWatcher()
-export const reactive = (data, watchers, methods) => {
const _data = {}
Object.keys(data).forEach((key) => {
- let internalValue = data[key]
-
- // Each property gets a dependency instance
- const dep = new Dep()
+ let currentValue = data[key]
Object.defineProperty(_data, key, {
get() {
- console.log(`Getting value, ${internalValue}`)
- dep.depend() // Saves the target function into the subscribers array
- return internalValue
+ subscribe(getTarget(), { key, value: currentValue })
+ return currentValue
},
set(newVal) {
- console.log(`Setting the internalValue to ${newVal}`)
- internalValue = newVal
- dep.notify() // Reruns saved target functions in the subscribers array
+ currentValue = newVal
+ onChange && onChange(key, newVal)
+ notify(_data)
},
})
})
Object.entries(watchers).forEach(([watcherName, watcher]) => {
- watch(() => watcher(_data))
+ watch(watcherName, () => watcher(_data))
})
- return _data
+ const _methods = {}
+ Object.entries(methods).forEach(([methodName, method]) => {
+ _methods[methodName] = (args) => method(_data, args)
+ })
+
+ return [_data, _methods]
}