Scroll actions
a69638341827e9b8ad9ebb318c90e32228da21f6
@@ -12073,6 +12073,7 @@
|
||||
"client/web/divkit/src/utils/mask/baseInputMask.ts":"divkit/public/client/web/divkit/src/utils/mask/baseInputMask.ts",
|
||||
"client/web/divkit/src/utils/mask/currencyInputMask.ts":"divkit/public/client/web/divkit/src/utils/mask/currencyInputMask.ts",
|
||||
"client/web/divkit/src/utils/mask/fixedLengthInputMask.ts":"divkit/public/client/web/divkit/src/utils/mask/fixedLengthInputMask.ts",
|
||||
"client/web/divkit/src/utils/nonNegativeModulo.ts":"divkit/public/client/web/divkit/src/utils/nonNegativeModulo.ts",
|
||||
"client/web/divkit/src/utils/padLeft.ts":"divkit/public/client/web/divkit/src/utils/padLeft.ts",
|
||||
"client/web/divkit/src/utils/prepareBase64.ts":"divkit/public/client/web/divkit/src/utils/prepareBase64.ts",
|
||||
"client/web/divkit/src/utils/propToString.ts":"divkit/public/client/web/divkit/src/utils/propToString.ts",
|
||||
@@ -13326,6 +13327,8 @@
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/base-properties/firefoxMobile/step8.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/base-properties/firefoxMobile/step8.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step0.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step0.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step1.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step1.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step10.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step10.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step11.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step11.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step2.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step2.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step3.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step3.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step4.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step4.png",
|
||||
@@ -13336,6 +13339,8 @@
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step9.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/chromeMobile/step9.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step0.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step0.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step1.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step1.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step10.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step10.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step11.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step11.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step2.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step2.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step3.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step3.png",
|
||||
"client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step4.png":"divkit/public/client/web/divkit/tests/hermione/screens/crossplatform/interactions/div-gallery/select-elements/firefoxMobile/step4.png",
|
||||
@@ -14267,6 +14272,7 @@
|
||||
"client/web/divkit/tests/utils/joinTemplatesSize.test.ts":"divkit/public/client/web/divkit/tests/utils/joinTemplatesSize.test.ts",
|
||||
"client/web/divkit/tests/utils/lerp.test.ts":"divkit/public/client/web/divkit/tests/utils/lerp.test.ts",
|
||||
"client/web/divkit/tests/utils/makeStyle.test.ts":"divkit/public/client/web/divkit/tests/utils/makeStyle.test.ts",
|
||||
"client/web/divkit/tests/utils/nonNegativeModulo.test.ts":"divkit/public/client/web/divkit/tests/utils/nonNegativeModulo.test.ts",
|
||||
"client/web/divkit/tests/utils/propToString.test.ts":"divkit/public/client/web/divkit/tests/utils/propToString.test.ts",
|
||||
"client/web/divkit/tests/utils/pxToEm.test.ts":"divkit/public/client/web/divkit/tests/utils/pxToEm.test.ts",
|
||||
"client/web/divkit/tests/utils/simpleCheckInput.test.ts":"divkit/public/client/web/divkit/tests/utils/simpleCheckInput.test.ts",
|
||||
|
||||
@@ -454,55 +454,75 @@
|
||||
}
|
||||
}
|
||||
|
||||
function setCurrentItem(id: string | null, item: string | null): void {
|
||||
if (!id || !item) {
|
||||
throw new Error('Missing data for "set-current-item" action');
|
||||
function switchElementAction(
|
||||
type: 'set_current_item' | 'set_previous_item' | 'set_next_item' | 'scroll_to_start' |
|
||||
'scroll_to_end' | 'scroll_backward' | 'scroll_forward' | 'scroll_to_position',
|
||||
id: string | null,
|
||||
{
|
||||
item,
|
||||
step,
|
||||
overflow
|
||||
}: {
|
||||
item?: string | null;
|
||||
step?: string | null;
|
||||
overflow?: string | null;
|
||||
}
|
||||
|
||||
if (Number.isNaN(Number(item))) {
|
||||
throw new Error('Incorrect item for "set-current-item" action');
|
||||
}
|
||||
|
||||
const instance = getInstance<SwitchElements>(id);
|
||||
|
||||
if (instance) {
|
||||
instance.setCurrentItem(Number(item));
|
||||
}
|
||||
}
|
||||
|
||||
function setPreviousItem(id: string | null, overflow: string | null): void {
|
||||
): void {
|
||||
if (!id) {
|
||||
throw new Error('Missing id for "set-previous-item" action');
|
||||
throw new Error(`Missing id for "${type}" action`);
|
||||
}
|
||||
|
||||
const itemVal = Number(item);
|
||||
if (type === 'set_current_item' && Number.isNaN(itemVal)) {
|
||||
throw new Error(`Incorrect item for "${type}" action`);
|
||||
}
|
||||
|
||||
let stepVal = Number(step);
|
||||
if (!step && (type === 'set_previous_item' || type === 'set_next_item')) {
|
||||
stepVal = 1;
|
||||
}
|
||||
if (
|
||||
!step && (type === 'scroll_backward' || type === 'scroll_forward' || type === 'scroll_to_position') ||
|
||||
Number.isNaN(stepVal)
|
||||
) {
|
||||
throw new Error(`Incorrect step value for "${type}" action`);
|
||||
}
|
||||
|
||||
if (overflow && overflow !== 'clamp' && overflow !== 'ring') {
|
||||
throw new Error('Incorrect overflow value for "set-previous-item" action');
|
||||
throw new Error(`Incorrect overflow value for "${type}" action`);
|
||||
}
|
||||
|
||||
overflow = overflow || 'clamp';
|
||||
|
||||
const instance = getInstance<SwitchElements>(id);
|
||||
|
||||
if (instance) {
|
||||
instance.setPreviousItem(overflow as Overflow);
|
||||
}
|
||||
}
|
||||
|
||||
function setNextItem(id: string | null, overflow: string | null): void {
|
||||
if (!id) {
|
||||
throw new Error('Missing id for "set-next-item" action');
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (overflow && overflow !== 'clamp' && overflow !== 'ring') {
|
||||
throw new Error('Incorrect overflow value for "set-next-item" action');
|
||||
}
|
||||
|
||||
overflow = overflow || 'clamp';
|
||||
|
||||
const instance = getInstance<SwitchElements>(id);
|
||||
|
||||
if (instance) {
|
||||
instance.setNextItem(overflow as Overflow);
|
||||
switch (type) {
|
||||
case 'set_current_item':
|
||||
instance.setCurrentItem(itemVal);
|
||||
return;
|
||||
case 'set_previous_item':
|
||||
instance.setPreviousItem(stepVal, overflow as Overflow);
|
||||
return;
|
||||
case 'set_next_item':
|
||||
instance.setNextItem(stepVal, overflow as Overflow);
|
||||
return;
|
||||
case 'scroll_to_start':
|
||||
instance.scrollToStart?.();
|
||||
return;
|
||||
case 'scroll_to_end':
|
||||
instance.scrollToEnd?.();
|
||||
return;
|
||||
case 'scroll_backward':
|
||||
instance.scrollBackward?.(stepVal, overflow as Overflow);
|
||||
return;
|
||||
case 'scroll_forward':
|
||||
instance.scrollForward?.(stepVal, overflow as Overflow);
|
||||
return;
|
||||
case 'scroll_to_position':
|
||||
instance.scrollToPosition?.(stepVal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,13 +738,18 @@
|
||||
setState(params.get('state_id'));
|
||||
break;
|
||||
case 'set_current_item':
|
||||
setCurrentItem(params.get('id'), params.get('item'));
|
||||
break;
|
||||
case 'set_previous_item':
|
||||
setPreviousItem(params.get('id'), params.get('overflow'));
|
||||
break;
|
||||
case 'set_next_item':
|
||||
setNextItem(params.get('id'), params.get('overflow'));
|
||||
case 'scroll_to_start':
|
||||
case 'scroll_to_end':
|
||||
case 'scroll_backward':
|
||||
case 'scroll_forward':
|
||||
case 'scroll_to_position':
|
||||
switchElementAction(parts[1], params.get('id'), {
|
||||
item: params.get('item'),
|
||||
step: params.get('step'),
|
||||
overflow: params.get('overflow')
|
||||
});
|
||||
break;
|
||||
case 'set_variable':
|
||||
const name = params.get('name');
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
import { joinTemplateSizes } from '../../utils/joinTemplateSizes';
|
||||
import { debounce } from '../../utils/debounce';
|
||||
import { Truthy } from '../../utils/truthy';
|
||||
import { nonNegativeModulo } from '../../utils/nonNegativeModulo';
|
||||
|
||||
export let componentContext: ComponentContext<DivGalleryData>;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
@@ -287,10 +288,19 @@
|
||||
return res;
|
||||
}
|
||||
|
||||
function scrollTo(offset: number, behavior: ScrollBehavior = 'smooth'): void {
|
||||
const isHorizontal = orientation === 'horizontal';
|
||||
const scrollDirection: keyof ScrollToOptions = isHorizontal ? 'left' : 'top';
|
||||
|
||||
scroller.scroll({
|
||||
[scrollDirection]: offset,
|
||||
behavior
|
||||
});
|
||||
}
|
||||
|
||||
function scrollToGalleryItem(galleryElements: HTMLElement[], index: number, behavior: ScrollBehavior = 'smooth'): void {
|
||||
const isHorizontal = orientation === 'horizontal';
|
||||
const elementOffset: keyof HTMLElement = isHorizontal ? 'offsetLeft' : 'offsetTop';
|
||||
const scrollDirection: keyof ScrollToOptions = isHorizontal ? 'left' : 'top';
|
||||
|
||||
// 0.01 forces Chromium to use scroll-snap (exact correct scroll position will not trigger it)
|
||||
// Chromium will save scroll-snapped value and will not save exact one
|
||||
@@ -299,10 +309,14 @@
|
||||
const elem = galleryElements[index];
|
||||
|
||||
if (elem) {
|
||||
scroller.scroll({
|
||||
[scrollDirection]: Math.max(0, elem[elementOffset] + .01 - itemSpacing / 2),
|
||||
behavior
|
||||
});
|
||||
let offset;
|
||||
if ($direction === 'ltr' || !isHorizontal) {
|
||||
offset = elem[elementOffset] + .01 - itemSpacing / 2;
|
||||
} else {
|
||||
const scrollWrapperSize = scroller.offsetWidth;
|
||||
offset = (elem[elementOffset] + elem.offsetWidth + .01 - itemSpacing / 2) - scrollWrapperSize;
|
||||
}
|
||||
scrollTo(offset, behavior);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,21 +383,23 @@
|
||||
|
||||
scrollToGalleryItem(galleryElements, item);
|
||||
},
|
||||
setPreviousItem(overflow: Overflow) {
|
||||
setPreviousItem(step: number, overflow: Overflow) {
|
||||
const currentElementIndex = calculateCurrentElementIndex('prev');
|
||||
const galleryElements = getItems();
|
||||
let previousItem = currentElementIndex - 1;
|
||||
let previousItem = currentElementIndex - step;
|
||||
|
||||
if (previousItem < 0) {
|
||||
previousItem = overflow === 'ring' ? galleryElements.length - 1 : currentElementIndex;
|
||||
previousItem = overflow === 'ring' ? nonNegativeModulo(previousItem, galleryElements.length) : 0;
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, previousItem);
|
||||
},
|
||||
setNextItem(overflow: Overflow) {
|
||||
setNextItem(step: number, overflow: Overflow) {
|
||||
const isHorizontal = orientation === 'horizontal';
|
||||
const directionMultiplier = ($direction === 'ltr' || !isHorizontal) ? 1 : -1;
|
||||
// Go to scroller start, if we reached right/bottom edge of scroller
|
||||
const isEdgeScroll = orientation === 'horizontal' ? (
|
||||
scroller.scrollLeft + scroller.offsetWidth === scroller.scrollWidth
|
||||
const isEdgeScroll = isHorizontal ? (
|
||||
scroller.scrollLeft * directionMultiplier + scroller.offsetWidth === scroller.scrollWidth
|
||||
) : (
|
||||
scroller.scrollTop + scroller.offsetHeight === scroller.scrollHeight
|
||||
);
|
||||
@@ -394,14 +410,61 @@
|
||||
}
|
||||
|
||||
const currentElementIndex = calculateCurrentElementIndex('next');
|
||||
let nextItem = currentElementIndex + 1;
|
||||
let nextItem = currentElementIndex + step;
|
||||
|
||||
if (nextItem > galleryElements.length - 1) {
|
||||
nextItem = overflow === 'ring' ? 0 : currentElementIndex;
|
||||
nextItem = overflow === 'ring' ? nonNegativeModulo(nextItem, galleryElements.length) : galleryElements.length - 1;
|
||||
}
|
||||
|
||||
scrollToGalleryItem(galleryElements, nextItem);
|
||||
}
|
||||
},
|
||||
scrollToStart() {
|
||||
scrollTo(0);
|
||||
},
|
||||
scrollToEnd() {
|
||||
scrollTo(($direction === 'ltr' || orientation !== 'horizontal') ? 1e6 : -1e6);
|
||||
},
|
||||
scrollBackward(step: number, overflow: Overflow) {
|
||||
const isHorizontal = orientation === 'horizontal';
|
||||
const directionMultiplier = ($direction === 'ltr' || !isHorizontal) ? 1 : -1;
|
||||
const currentOffset = isHorizontal ?
|
||||
scroller.scrollLeft :
|
||||
scroller.scrollTop;
|
||||
const maxOffset = isHorizontal ?
|
||||
scroller.scrollWidth - scroller.offsetWidth :
|
||||
scroller.scrollHeight - scroller.offsetHeight;
|
||||
let newOffset = currentOffset * directionMultiplier - step;
|
||||
if (newOffset < 0) {
|
||||
if (overflow === 'clamp') {
|
||||
newOffset = 0;
|
||||
} else if (overflow === 'ring') {
|
||||
newOffset = nonNegativeModulo(newOffset, maxOffset);
|
||||
}
|
||||
}
|
||||
scrollTo(newOffset * directionMultiplier);
|
||||
},
|
||||
scrollForward(step: number, overflow: Overflow) {
|
||||
const isHorizontal = orientation === 'horizontal';
|
||||
const directionMultiplier = ($direction === 'ltr' || !isHorizontal) ? 1 : -1;
|
||||
const currentOffset = isHorizontal ?
|
||||
scroller.scrollLeft :
|
||||
scroller.scrollTop;
|
||||
const maxOffset = isHorizontal ?
|
||||
scroller.scrollWidth - scroller.offsetWidth :
|
||||
scroller.scrollHeight - scroller.offsetHeight;
|
||||
let newOffset = currentOffset * directionMultiplier + step;
|
||||
if (newOffset > maxOffset) {
|
||||
if (overflow === 'clamp') {
|
||||
newOffset = maxOffset;
|
||||
} else if (overflow === 'ring') {
|
||||
newOffset = nonNegativeModulo(newOffset, maxOffset);
|
||||
}
|
||||
}
|
||||
scrollTo(newOffset * directionMultiplier);
|
||||
},
|
||||
scrollToPosition(step) {
|
||||
scrollTo(($direction === 'ltr' || orientation !== 'horizontal') ? step : -step);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
import { isNonNegativeNumber } from '../../utils/isNonNegativeNumber';
|
||||
import { debounce } from '../../utils/debounce';
|
||||
import { Truthy } from '../../utils/truthy';
|
||||
import { nonNegativeModulo } from '../../utils/nonNegativeModulo';
|
||||
|
||||
export let componentContext: ComponentContext<DivPagerData>;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
@@ -233,21 +234,21 @@
|
||||
currentItem = index;
|
||||
}
|
||||
|
||||
function setPreviousItem(overflow: Overflow) {
|
||||
let previousItem = currentItem - 1;
|
||||
function setPreviousItem(step: number, overflow: Overflow) {
|
||||
let previousItem = currentItem - step;
|
||||
|
||||
if (previousItem < 0) {
|
||||
previousItem = overflow === 'ring' ? items.length - 1 : currentItem;
|
||||
previousItem = overflow === 'ring' ? nonNegativeModulo(previousItem, items.length) : 0;
|
||||
}
|
||||
|
||||
scrollToPagerItem(previousItem);
|
||||
}
|
||||
|
||||
function setNextItem(overflow: Overflow) {
|
||||
let nextItem = currentItem + 1;
|
||||
function setNextItem(step: number, overflow: Overflow) {
|
||||
let nextItem = currentItem + step;
|
||||
|
||||
if (nextItem > items.length - 1) {
|
||||
nextItem = overflow === 'ring' ? 0 : currentItem;
|
||||
nextItem = overflow === 'ring' ? nonNegativeModulo(nextItem, items.length) : items.length - 1;
|
||||
}
|
||||
|
||||
scrollToPagerItem(nextItem);
|
||||
@@ -270,7 +271,13 @@
|
||||
scrollToPagerItem(item);
|
||||
},
|
||||
setPreviousItem,
|
||||
setNextItem
|
||||
setNextItem,
|
||||
scrollToStart() {
|
||||
scrollToPagerItem(0);
|
||||
},
|
||||
scrollToEnd() {
|
||||
scrollToPagerItem(items.length - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -328,7 +335,7 @@
|
||||
{#if hasScrollLeft && shouldCheckArrows}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="{leftClass || `${css.pager__arrow} ${arrowsCss.arrow} ${arrowsCss.arrow_left}`}" on:click={() => ($direction === 'ltr' ? setPreviousItem : setNextItem)('clamp')}>
|
||||
<div class="{leftClass || `${css.pager__arrow} ${arrowsCss.arrow} ${arrowsCss.arrow_left}`}" on:click={() => ($direction === 'ltr' ? setPreviousItem : setNextItem)(1, 'clamp')}>
|
||||
{#if !leftClass}
|
||||
<svg class={arrowsCss.arrow__icon} xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
|
||||
<path class={css['pager__arrow-icon-path']} d="m10 16 8.3 8 1.03-1-4-6-.7-1 .7-1 4-6-1.03-1z"/>
|
||||
@@ -339,7 +346,7 @@
|
||||
{#if hasScrollRight && shouldCheckArrows}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="{rightClass || `${css.pager__arrow} ${arrowsCss.arrow} ${arrowsCss.arrow_right}`}" on:click={() => ($direction === 'ltr' ? setNextItem : setPreviousItem)('clamp')}>
|
||||
<div class="{rightClass || `${css.pager__arrow} ${arrowsCss.arrow} ${arrowsCss.arrow_right}`}" on:click={() => ($direction === 'ltr' ? setNextItem : setPreviousItem)(1, 'clamp')}>
|
||||
{#if !rightClass}
|
||||
<svg class={arrowsCss.arrow__icon} xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
|
||||
<path class={css['pager__arrow-icon-path']} d="M22 16l-8.3 8-1.03-1 4-6 .7-1-.7-1-4-6 1.03-1 8.3 8z"/>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
import { correctNonNegativeNumber } from '../../utils/correctNonNegativeNumber';
|
||||
import { edgeInsertsToCss } from '../../utils/edgeInsertsToCss';
|
||||
import { filterEnabledActions } from '../../utils/filterEnabledActions';
|
||||
import { nonNegativeModulo } from '../../utils/nonNegativeModulo';
|
||||
|
||||
export let componentContext: ComponentContext<DivTabsData>;
|
||||
export let layoutParams: LayoutParams | undefined = undefined;
|
||||
@@ -611,24 +612,30 @@
|
||||
|
||||
setSelected(item);
|
||||
},
|
||||
setPreviousItem(overflow: Overflow) {
|
||||
let previousItem = selected - 1;
|
||||
setPreviousItem(step: number, overflow: Overflow) {
|
||||
let previousItem = selected - step;
|
||||
|
||||
if (previousItem < 0) {
|
||||
previousItem = overflow === 'ring' ? items.length - 1 : selected;
|
||||
previousItem = overflow === 'ring' ? nonNegativeModulo(previousItem, items.length) : 0;
|
||||
}
|
||||
|
||||
setSelected(previousItem);
|
||||
},
|
||||
setNextItem(overflow: Overflow) {
|
||||
let nextItem = selected + 1;
|
||||
setNextItem(step: number, overflow: Overflow) {
|
||||
let nextItem = selected + step;
|
||||
|
||||
if (nextItem > items.length - 1) {
|
||||
nextItem = overflow === 'ring' ? 0 : selected;
|
||||
nextItem = overflow === 'ring' ? nonNegativeModulo(nextItem, items.length) : items.length - 1;
|
||||
}
|
||||
|
||||
setSelected(nextItem);
|
||||
}
|
||||
},
|
||||
scrollToStart() {
|
||||
setSelected(0);
|
||||
},
|
||||
scrollToEnd() {
|
||||
setSelected(items.length - 1);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@ export type Overflow = 'clamp' | 'ring';
|
||||
|
||||
export interface SwitchElements {
|
||||
setCurrentItem(item: number): void;
|
||||
setPreviousItem(overflow: Overflow): void;
|
||||
setNextItem(overflow: Overflow): void;
|
||||
setPreviousItem(step: number, overflow: Overflow): void;
|
||||
setNextItem(step: number, overflow: Overflow): void;
|
||||
scrollToStart?: () => void;
|
||||
scrollToEnd?: () => void;
|
||||
scrollBackward?: (step: number, overflow: Overflow) => void;
|
||||
scrollForward?: (step: number, overflow: Overflow) => void;
|
||||
scrollToPosition?: (step: number) => void;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export function nonNegativeModulo(value: number, mod: number): number {
|
||||
let res = value % mod;
|
||||
if (res < 0) {
|
||||
res += mod;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 459 KiB After Width: | Height: | Size: 460 KiB |
|
Before Width: | Height: | Size: 457 KiB After Width: | Height: | Size: 459 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 146 KiB |
@@ -0,0 +1,12 @@
|
||||
import { nonNegativeModulo } from '../../src/utils/nonNegativeModulo';
|
||||
|
||||
describe('nonNegativeModulo', () => {
|
||||
test('simple', () => {
|
||||
expect(nonNegativeModulo(3, 10)).toBe(3);
|
||||
expect(nonNegativeModulo(23, 10)).toBe(3);
|
||||
expect(nonNegativeModulo(-3, 10)).toBe(7);
|
||||
expect(nonNegativeModulo(-13, 10)).toBe(7);
|
||||
expect(nonNegativeModulo(0, 10)).toBe(0);
|
||||
expect(nonNegativeModulo(10, 10)).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"description": "TODO: https://nda.ya.ru/t/MMvpmt855oXgre",
|
||||
"platforms": [
|
||||
"android"
|
||||
"android",
|
||||
"web"
|
||||
],
|
||||
"div_data": {
|
||||
"templates": {
|
||||
|
||||
@@ -399,7 +399,7 @@
|
||||
"text": "<",
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "gallery1/scroll_backward by 150dp",
|
||||
"log_id": "gallery1/scroll_backward by 50dp",
|
||||
"url": "div-action://scroll_backward?id=gallery1&step=50"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -218,6 +218,61 @@
|
||||
"content_alignment_horizontal": "center",
|
||||
"alignment_horizontal": "center",
|
||||
"type": "container"
|
||||
},
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "scroll_click_1",
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "scroll_to_start",
|
||||
"url": "div-action://scroll_to_start?id=my_pager"
|
||||
}
|
||||
],
|
||||
"text": "<<",
|
||||
"text_alignment_horizontal": "center",
|
||||
"type": "button"
|
||||
},
|
||||
{
|
||||
"id": "scroll_click_2",
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "prev_by_2",
|
||||
"url": "div-action://set_previous_item?id=my_pager&step=2"
|
||||
}
|
||||
],
|
||||
"text": "<",
|
||||
"text_alignment_horizontal": "center",
|
||||
"type": "button"
|
||||
},
|
||||
{
|
||||
"id": "scroll_click_3",
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "next_by_2",
|
||||
"url": "div-action://set_next_item?id=my_pager&step=2"
|
||||
}
|
||||
],
|
||||
"text": ">",
|
||||
"text_alignment_horizontal": "center",
|
||||
"type": "button"
|
||||
},
|
||||
{
|
||||
"id": "scroll_click_4",
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "scroll_to_end",
|
||||
"url": "div-action://scroll_to_end?id=my_pager"
|
||||
}
|
||||
],
|
||||
"text": ">>",
|
||||
"type": "button"
|
||||
}
|
||||
],
|
||||
"orientation": "horizontal",
|
||||
"content_alignment_horizontal": "center",
|
||||
"alignment_horizontal": "center",
|
||||
"type": "container"
|
||||
}
|
||||
],
|
||||
"orientation": "vertical",
|
||||
|
||||
@@ -220,6 +220,57 @@
|
||||
"orientation": "horizontal",
|
||||
"content_alignment_horizontal": "center",
|
||||
"type": "container"
|
||||
},
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "scroll_to_start",
|
||||
"url": "div-action://scroll_to_start?id=my_tabs"
|
||||
}
|
||||
],
|
||||
"text": "<<",
|
||||
"text_alignment_horizontal": "center",
|
||||
"type": "button"
|
||||
},
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "prev_by_2",
|
||||
"url": "div-action://set_previous_item?id=my_tabs&step=2"
|
||||
}
|
||||
],
|
||||
"text": "<",
|
||||
"text_alignment_horizontal": "center",
|
||||
"type": "button"
|
||||
},
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "next_by_2",
|
||||
"url": "div-action://set_next_item?id=my_tabs&step=2"
|
||||
}
|
||||
],
|
||||
"text": ">",
|
||||
"text_alignment_horizontal": "center",
|
||||
"type": "button"
|
||||
},
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"log_id": "scroll_to_end",
|
||||
"url": "div-action://scroll_to_end?id=my_tabs"
|
||||
}
|
||||
],
|
||||
"text": ">>",
|
||||
"text_alignment_horizontal": "center",
|
||||
"type": "button"
|
||||
}
|
||||
],
|
||||
"orientation": "horizontal",
|
||||
"content_alignment_horizontal": "center",
|
||||
"type": "container"
|
||||
}
|
||||
],
|
||||
"orientation": "vertical",
|
||||
|
||||