@longlost/app-carousel
Advanced tools
Comparing version 2.2.4 to 2.3.0
@@ -103,2 +103,3 @@ | ||
return { | ||
// Sets the proportion of width to height. | ||
@@ -110,7 +111,13 @@ // 'classic', 'fill', 'landscape', 'portrait' or 'square' | ||
}, | ||
// Set true to have carousel iterate | ||
// through sections automatically. | ||
autoplay: Boolean, | ||
// Disable scrolling when true. | ||
disabled: Boolean, | ||
// Display navigation dots when true. | ||
dots: Boolean, | ||
// How many ms to wait between each flip. | ||
@@ -121,4 +128,6 @@ flipTime: { | ||
}, | ||
// Set to true to have clickable navigation arrows. | ||
nav: Boolean, | ||
// Where to place items relative to scroll container. | ||
@@ -129,2 +138,3 @@ position: { | ||
}, | ||
// Currently centered item. Not used internally. | ||
@@ -136,4 +146,6 @@ // Fired in 'app-carousel-centered-item-changed' event. | ||
}, | ||
// Debounce IntersectionObserver callback changes. | ||
_debouncedItems: Object, | ||
// Controls how many dots stamp out and | ||
@@ -145,4 +157,6 @@ // which one gets the selected class. | ||
}, | ||
// Cached, reused instance of IntersectionObserver. | ||
_intersectionObserver: Object, | ||
// IntersectionObserver options threshold prop. | ||
@@ -154,2 +168,3 @@ // Expected values are any float between 0 and 1. | ||
}, | ||
// The items that are that are contained inside | ||
@@ -162,2 +177,3 @@ // parent at any given time according to | ||
}, | ||
// The maximum number of items that are contained inside | ||
@@ -172,10 +188,14 @@ // parent at any given time according to | ||
_maxIntersecting: Number, | ||
// Used by __resizeHandler method to reset carousel | ||
// after screen resizes. | ||
_oldSectionIndex: Number, | ||
// IntersectionObserver observed items. | ||
// Keyed by item index. | ||
_observedItems: Object, | ||
// Current playing state. | ||
_isPlaying: Boolean, | ||
// The slotted elements contained in the carousel. | ||
@@ -186,2 +206,3 @@ _items: { | ||
}, | ||
// Number of slotted dom nodes. | ||
@@ -192,5 +213,14 @@ _itemCount: { | ||
}, | ||
// Used for window 'resize' events. | ||
// An observer watches this index number | ||
// as well as the _sections prop to ensure | ||
// section dom is rendered before attempting | ||
// and animation. | ||
_resizeIndex: Number, | ||
// Cached #scrollContainer element. | ||
// Used to dynamically measure bbox for calculations. | ||
_scrollContainer: Object, | ||
// Section count is smaller than item count if | ||
@@ -202,2 +232,3 @@ // displaying more multiple items at a time. | ||
}, | ||
// Fired in 'app-carousel-section-index-changed' event. | ||
@@ -214,2 +245,3 @@ // Section items can differ from slotted items | ||
}, | ||
// Fired in 'app-carousel-sections-changed' event. | ||
@@ -225,2 +257,3 @@ // Section items can differ from slotted items | ||
}, | ||
// Used by container on-up/on-down handlers. | ||
@@ -240,4 +273,6 @@ // If carousel was playing, stop anytime user | ||
'__centeredItemChanged(_centeredItem)', | ||
'__disabledChanged(disabled)', | ||
'__intersectingItemsChanged(_intersectingItems)', | ||
'__observedItemsChanged(_observedItems.*)', | ||
'__resizeIndexSectionsChanged(_resizeIndex, _sections)', | ||
'__sectionsChanged(_sections)' | ||
@@ -257,6 +292,9 @@ ]; | ||
super.connectedCallback(); | ||
// Used to dynamically measure bbox for calculations. | ||
this._scrollContainer = this.$.scrollContainer; | ||
// Correct for screen resizes. | ||
window.addEventListener('resize', this.__resizeHandler.bind(this)); | ||
// Scroll options polyfill for safari, supports {behavior: 'smooth'} | ||
@@ -271,2 +309,3 @@ // for all scroll functions (ie. window.scrollTo, element.scrollIntoVeiw). | ||
} | ||
// Array of all observed elements | ||
@@ -276,2 +315,3 @@ // with a true isIntersecting prop. | ||
if (!observed) { return; } | ||
// Ignore items that are ouside of scroller. | ||
@@ -289,2 +329,3 @@ | ||
} | ||
// Not used internally. Only for consumer. | ||
@@ -294,4 +335,6 @@ // Fired in 'app-carousel-centered-item-changed' event. | ||
if (!intersectingItems || !container) { return; } | ||
// Dynamically measure scroll container to catch resizes. | ||
const containerBBox = container.getBoundingClientRect(); | ||
// Use real measurements instead of relying on the item carouselIndex | ||
@@ -301,2 +344,3 @@ // for cases where items have been rearranged but not reordered. | ||
const {target} = item; | ||
// Cannot rely on bbox measurements that come with each | ||
@@ -310,10 +354,14 @@ // entry since an intersecting element can be intersecting | ||
const distance = Math.abs(containerCenter - itemCenter); | ||
return {...item, boundingClientRect, distance}; | ||
}); | ||
// Find the fully intersecting item that is closest to center. | ||
const centered = distances.reduce((prev, curr) => { | ||
const {distance} = prev; | ||
if (typeof distance !== 'number') { // First iteration. | ||
return curr; | ||
} | ||
// Closest item to center of container. | ||
@@ -323,2 +371,3 @@ if (distance >= curr.distance) { | ||
} | ||
return prev; | ||
@@ -351,2 +400,3 @@ }, {}); | ||
} | ||
// Position center. | ||
@@ -368,2 +418,3 @@ // The number of sections is determined by the maximum | ||
__computeSections(observed, sectionCount, position) { | ||
// Noop if items is undefined or if | ||
@@ -382,5 +433,7 @@ // sectionCount is undefined or less than 1. | ||
if (position === 'start') { | ||
// Remove the dfference between total items | ||
// and sections from the end of items array. | ||
const endRemoved = items.slice(0, sectionCount); | ||
return endRemoved; | ||
@@ -392,7 +445,10 @@ } | ||
if (position === 'end') { | ||
// Remove the dfference between total items | ||
// and sections from the beginning of items array. | ||
const startRemoved = items.slice(count - sectionCount); | ||
return startRemoved; | ||
} | ||
// The difference between items count and | ||
@@ -405,4 +461,6 @@ // sectionCount should always be and even number. | ||
const endIndex = count - diff; | ||
// Chop off end of items array first. | ||
const endRemoved = items.slice(0, endIndex); | ||
const endRemoved = items.slice(0, endIndex); | ||
// Remove from start of new array. | ||
@@ -424,2 +482,3 @@ const startRemoved = endRemoved.slice(diff); | ||
const {carouselIndex} = item; | ||
return sections.findIndex(section => | ||
@@ -430,4 +489,6 @@ section.carouselIndex === carouselIndex); | ||
if (position === 'start') { | ||
// Always use first intersecting item with 'start'. | ||
const item = head(intersecting); | ||
return sectionIndexFromIntersectingItem(item); | ||
@@ -437,4 +498,6 @@ } | ||
if (position === 'end') { | ||
// Always use first intersecting item with 'end'. | ||
const item = tail(intersecting); | ||
return sectionIndexFromIntersectingItem(item); | ||
@@ -445,2 +508,3 @@ } | ||
const intersectingIsOdd = isOdd(intersectingCount); | ||
// Take the middle item's carouselIndex to determine section. | ||
@@ -450,2 +514,3 @@ if (intersectingIsOdd) { | ||
const item = intersecting[middleIndex]; | ||
return sectionIndexFromIntersectingItem(item); | ||
@@ -455,2 +520,3 @@ } | ||
const firstIntersecting = head(intersecting); | ||
// First element is a special case. | ||
@@ -462,2 +528,3 @@ // If it's fully visible then we must be | ||
} | ||
// Since the carousel moves LTR, use the first | ||
@@ -467,2 +534,3 @@ // element to the right of dead center. | ||
const item = intersecting[middleishIndex]; | ||
return sectionIndexFromIntersectingItem(item); | ||
@@ -474,2 +542,3 @@ } | ||
const array = []; | ||
for (let i = 0; i < count; i += 1) { | ||
@@ -482,2 +551,3 @@ const obj = {selected: ''}; | ||
} | ||
return array; | ||
@@ -495,2 +565,3 @@ } | ||
const callback = entries => { | ||
entries.forEach(entry => { | ||
@@ -500,2 +571,3 @@ const {carouselIndex} = entry.target; | ||
const currData = toObj(entry); | ||
// Keep carouselIndex from __itemsChanged. | ||
@@ -517,2 +589,3 @@ this.set( | ||
await this.debounce('app-carousel-slot-debounce', 200); | ||
const nodes = this.slotNodes('#slot'); | ||
@@ -530,3 +603,4 @@ this._items = nodes.filter(node => | ||
__itemsChanged(items, oldItems) { | ||
__itemsChanged(items, oldItems) { | ||
if (Array.isArray(oldItems)) { | ||
@@ -539,7 +613,11 @@ oldItems.forEach(item => { | ||
if (Array.isArray(items)) { | ||
// Hack!! See notes in properties definition above. | ||
this._maxIntersecting = undefined; | ||
// Create/clear cached vals. | ||
this._observedItems = {}; | ||
items.forEach((item, carouselIndex) => { | ||
// Build a dictionary of observed elements | ||
@@ -551,2 +629,3 @@ // so we can keep track of state. | ||
item.carouselIndex = carouselIndex; | ||
// Not using Polymer's set api so we don't trigger | ||
@@ -559,2 +638,3 @@ // computed properties and other observers. | ||
} | ||
// Cannot use a computed here because we need | ||
@@ -565,2 +645,3 @@ // to latch this method to only set the | ||
__intersectingItemsChanged(items) { | ||
// Hack!! Only run once to maintain stability. | ||
@@ -574,2 +655,3 @@ // Otherwise this becomes unreliable when the user | ||
} | ||
// Ignore circumstances where the carousel | ||
@@ -589,2 +671,3 @@ // itself is not on screen (ie. no intersecting items). | ||
) { return; } | ||
// Allow asynchronous IntersectionObserver callbacks to settle. | ||
@@ -616,3 +699,15 @@ await this.debounce('app-carousel-observed-debounce', 200); | ||
__disabledChanged(disabled) { | ||
if (disabled) { | ||
this.$.scrollContainer.style['pointer-events'] = 'none'; | ||
} | ||
else { | ||
this.$.scrollContainer.style['pointer-events'] = 'auto'; | ||
} | ||
} | ||
__sectionIndexChanged(index, oldIndex) { | ||
// Cache old index for screen resizes. | ||
@@ -623,2 +718,3 @@ // Used by __resizeHandler method. | ||
if (typeof index !== 'number') { return; } | ||
this.fire('app-carousel-section-index-changed', {value: index}); | ||
@@ -630,8 +726,19 @@ } | ||
if (!sections) { return; } | ||
this.fire('app-carousel-sections-changed', {value: sections}); | ||
} | ||
// This observer ensures that there are stamped | ||
// sections when a 'resize' event is fired. | ||
__resizeIndexSectionsChanged(index, sections) { | ||
if (typeof index !== 'number' || !sections) { return; } | ||
this._resizeIndex = undefined; | ||
this.animateToSection(index); | ||
} | ||
__play() { | ||
this._isPlaying = true; | ||
// Reset each time play is called. | ||
@@ -644,2 +751,3 @@ window.clearInterval(this._playTimerId); | ||
} | ||
// Interrupt playing and reset timer if | ||
@@ -658,2 +766,3 @@ // carousel was previously playing. | ||
} | ||
// Stop playing anytime user is | ||
@@ -667,2 +776,3 @@ // manually scrolling the carousel. | ||
} | ||
// Resume playing when user is | ||
@@ -714,4 +824,6 @@ // done manually scrolling carousel. | ||
__goToSection(index, behavior = 'smooth') { | ||
// Get the section referenced by the index. | ||
const sectionItem = this._sections[index]; | ||
// Dynamically measure scroller and target elements | ||
@@ -738,5 +850,7 @@ // in order to catch all resizes. | ||
if (this.position === 'center') { | ||
// Find centers since widths can vary. | ||
const targetCenter = getCenter(bbox); | ||
const containerCenter = getCenter(containerBBox); | ||
// Use the distance between centers to pass in to scrollBy. | ||
@@ -774,2 +888,3 @@ return targetCenter - containerCenter; | ||
} | ||
// Sometimes the resize puts items in a state where none are | ||
@@ -779,9 +894,9 @@ // intersecting, so reset carousel to last known good index. | ||
try { | ||
await this.debounce('app-carousel-resize-debounce', 500); | ||
await this.debounce('app-carousel-resize-debounce', 10); | ||
if (typeof this._sectionIndex === 'number') { | ||
this.animateToSection(this._sectionIndex); | ||
this._resizeIndex = this._sectionIndex; | ||
} | ||
else if (typeof this._oldSectionIndex === 'number') { | ||
this.animateToSection(this._oldSectionIndex); | ||
this._resizeIndex = this._oldSectionIndex; | ||
} | ||
@@ -817,2 +932,3 @@ } | ||
nextItem(direction = 'right', recycle = '') { | ||
// When user is scrolling/dragging items | ||
@@ -824,4 +940,6 @@ if (typeof this._sectionIndex !== 'number') { | ||
if (direction === 'right') { | ||
// go back to first section if at last section | ||
if (this._sectionIndex + 1 >= this._sectionCount) { | ||
if (recycle === 'recycle') { | ||
@@ -839,4 +957,6 @@ this.animateToSection(0); | ||
else if (direction === 'left') { | ||
// go back to last section if at first section | ||
if (this._sectionIndex - 1 < 0) { | ||
if (recycle === 'recycle') { | ||
@@ -843,0 +963,0 @@ this.animateToSection(this._sectionCount - 1); |
{ | ||
"name": "@longlost/app-carousel", | ||
"version": "2.2.4", | ||
"version": "2.3.0", | ||
"description": "configurable carousel with autoplay, swipe, optional nav and av buttons", | ||
@@ -20,6 +20,6 @@ "main": "app-carousel.js", | ||
"dependencies": { | ||
"@longlost/app-element": "^1.0.6", | ||
"@longlost/app-element": "^1.1.1", | ||
"@longlost/app-icons": "^1.0.11", | ||
"@longlost/app-shared-styles": "^2.0.11", | ||
"@longlost/lambda": "^2.0.5", | ||
"@longlost/app-shared-styles": "^2.0.13", | ||
"@longlost/lambda": "^2.2.0", | ||
"@longlost/utils": "^1.3.5", | ||
@@ -35,7 +35,7 @@ "@polymer/iron-icon": "^3.0.1", | ||
"@polymer/test-fixture": "^4.0.2", | ||
"@webcomponents/webcomponentsjs": "^2.4.1", | ||
"@webcomponents/webcomponentsjs": "^2.4.3", | ||
"chai": "^4.2.0", | ||
"mocha": "^7.0.1", | ||
"mocha": "^7.1.1", | ||
"wct-mocha": "^1.0.1" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
39951
739