@via-profit/ui-kit 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Accordion/AccordionActions.d.ts +1 -1
- package/Accordion/AccordionActions.js +2 -1
- package/Accordion/AccordionContainer.d.ts +1 -1
- package/Accordion/AccordionContainer.js +2 -14
- package/Accordion/AccordionContent.d.ts +1 -1
- package/Accordion/AccordionContent.js +5 -1
- package/Accordion/AccordionHeader.d.ts +2 -2
- package/Accordion/AccordionHeader.js +6 -2
- package/Accordion/index.d.ts +9 -9
- package/Accordion/index.js +18 -9
- package/Autocomplete/AutocompleteContainer.d.ts +2 -2
- package/Autocomplete/AutocompleteContainer.js +17 -7
- package/Autocomplete/AutocompleteItem.js +2 -1
- package/Autocomplete/context.d.ts +3 -3
- package/Autocomplete/index.d.ts +2 -2
- package/Avatar/AvatarContainer.d.ts +2 -2
- package/Avatar/AvatarPicture.d.ts +2 -2
- package/Avatar/index.js +1 -2
- package/Badge/BadgeBase.d.ts +1 -1
- package/Badge/BadgeContainer.d.ts +1 -1
- package/Badge/BadgeDeleteButton.d.ts +2 -2
- package/Badge/BadgeStyled.js +1 -1
- package/Badge/index.d.ts +1 -1
- package/Badge/index.js +1 -2
- package/Button/ButtonBase.d.ts +2 -2
- package/Button/ButtonContainer.d.ts +4 -4
- package/Button/ButtonContainer.js +22 -5
- package/Button/ButtonIconWrapper.d.ts +1 -1
- package/Button/ButtonStyled.d.ts +1 -1
- package/Button/ButtonTextWrapper.d.ts +1 -1
- package/Button/buttonVariants.d.ts +1 -1
- package/Button/buttonVariants.js +3 -2
- package/Button/index.d.ts +1 -1
- package/Button/index.js +1 -20
- package/ButtonGroup/index.js +4 -3
- package/CHANGELOG.md +49 -1
- package/Calendar/CalendarComponent.js +18 -9
- package/Calendar/CalendarControlButton.d.ts +2 -2
- package/Calendar/CalendarPaper.js +1 -1
- package/Calendar/CalendarWeekDayLabel.d.ts +2 -2
- package/Calendar/CalendarWeekRowButton.d.ts +1 -1
- package/Calendar/IconChevronDown.js +17 -7
- package/Calendar/index.d.ts +1 -1
- package/Calendar/index.js +17 -7
- package/Checkbox/CheckboxAsterisk.js +17 -7
- package/Checkbox/CheckboxBox.d.ts +2 -2
- package/Checkbox/CheckboxBox.js +1 -1
- package/Checkbox/CheckboxContainer.d.ts +2 -2
- package/Checkbox/CheckboxErrorText.js +17 -7
- package/Checkbox/index.d.ts +10 -10
- package/Checkbox/index.js +1 -2
- package/Checkbox/useCheckboxColor.d.ts +1 -1
- package/ClickOutside/index.js +5 -2
- package/DatePicker/index.d.ts +1 -1
- package/ErrorBoundary/RenderError.js +17 -7
- package/ErrorBoundary/index.d.ts +1 -1
- package/Grid/index.d.ts +17 -5
- package/Grid/index.js +7 -2
- package/Highlighted/index.js +1 -2
- package/LoadingIndicator/LoadingOverlay.js +17 -7
- package/LoadingIndicator/Spinner.js +17 -7
- package/LoadingIndicator/SpinnerCircle.d.ts +2 -3
- package/Menu/MenuContainer.d.ts +2 -2
- package/Menu/MenuContainer.js +19 -10
- package/Menu/MenuItem.js +5 -1
- package/Menu/MenuList.js +1 -1
- package/Menu/context.d.ts +1 -1
- package/Menu/index.d.ts +1 -1
- package/Modal/BaseModal/ModalInner.js +2 -0
- package/Modal/BaseModal/ModalWrapper.js +30 -37
- package/Modal/BaseModal/context.d.ts +1 -1
- package/Modal/BaseModal/index.js +1 -2
- package/Modal/ConfirmBox/ConfirmBoxContent.js +5 -1
- package/Modal/ConfirmBox/ConfirmBoxFooter.js +5 -1
- package/Modal/ConfirmBox/ConfirmBoxHeader.js +5 -1
- package/Modal/ConfirmBox/index.js +1 -2
- package/Modal/Dialog/DialogInner.js +5 -1
- package/Modal/Dialog/index.js +18 -9
- package/Modal/Drawer/DrawerCloseIcon.js +17 -7
- package/Modal/Drawer/DrawerFooter.js +5 -1
- package/Modal/Drawer/DrawerHeader.d.ts +4 -4
- package/Modal/Drawer/DrawerHeader.js +5 -1
- package/Modal/Drawer/index.js +18 -9
- package/Modal/MessageBox/MessageBoxContent.js +5 -1
- package/Modal/MessageBox/MessageBoxFooter.js +5 -1
- package/Modal/MessageBox/MessageBoxHeader.js +5 -1
- package/Modal/MessageBox/index.js +18 -9
- package/Modal/index.js +17 -7
- package/Pagination/PaginationContainer.d.ts +9 -0
- package/Pagination/PaginationContainer.js +34 -0
- package/Pagination/PaginationGap.d.ts +4 -0
- package/Pagination/PaginationGap.js +22 -0
- package/Pagination/PaginationIcons.d.ts +6 -0
- package/Pagination/PaginationIcons.js +21 -0
- package/Pagination/PaginationItem.d.ts +44 -0
- package/Pagination/PaginationItem.js +59 -0
- package/Pagination/getPaginationItems.d.ts +22 -0
- package/Pagination/getPaginationItems.js +42 -0
- package/Pagination/index.d.ts +104 -0
- package/Pagination/index.js +98 -0
- package/Pagination/usePagination.d.ts +105 -0
- package/Pagination/usePagination.js +66 -0
- package/PhoneField/CountryFlagComponent.d.ts +1 -1
- package/PhoneField/UnknownFlag.d.ts +0 -1
- package/PhoneField/flags/BY.js +17 -7
- package/PhoneField/flags/CN.js +17 -7
- package/PhoneField/flags/IL.js +17 -7
- package/PhoneField/flags/JP.js +17 -7
- package/PhoneField/flags/KZ.js +17 -7
- package/PhoneField/flags/RU.js +17 -7
- package/PhoneField/flags/UA.js +17 -7
- package/PhoneField/flags/US.js +17 -7
- package/PhoneField/flags/Unknown.js +17 -7
- package/PhoneField/templates.d.ts +2 -2
- package/Popper/Popper.js +1 -2
- package/Radio/RadioBox.d.ts +1 -1
- package/Radio/RadioBox.js +1 -1
- package/Radio/RadioContainer.d.ts +2 -2
- package/Radio/index.d.ts +5 -5
- package/Radio/index.js +1 -2
- package/Radio/useRadioColor.d.ts +1 -1
- package/RadioGroup/RadioGroupAsterisk.js +17 -7
- package/RadioGroup/RadioGroupErrorText.js +17 -7
- package/RadioGroup/RadioGroupItems.d.ts +1 -1
- package/RadioGroup/index.d.ts +11 -11
- package/RadioGroup/index.js +1 -2
- package/Selectbox/SelectboxButton.d.ts +4 -4
- package/Selectbox/SelectboxButton.js +25 -10
- package/Selectbox/SelectboxButtonWrapper.d.ts +2 -2
- package/Selectbox/SelectboxButtonWrapper.js +19 -10
- package/Selectbox/SelectboxMenu.d.ts +2 -2
- package/Selectbox/SelectboxMenu.js +17 -7
- package/Selectbox/index.d.ts +2 -2
- package/Selectbox/index.js +18 -9
- package/Slider/SliderRail.d.ts +1 -1
- package/Slider/SliderThumb.d.ts +1 -1
- package/Slider/SliderTrack.d.ts +1 -1
- package/Slider/index.js +1 -2
- package/Slider/useSliderColor.d.ts +1 -1
- package/Stack/index.d.ts +18 -6
- package/Stack/index.js +7 -2
- package/Surface/SurfaceContainer.d.ts +3 -3
- package/Surface/SurfaceContainer.js +1 -1
- package/Surface/SurfaceContent.d.ts +2 -2
- package/Surface/SurfaceContent.js +18 -11
- package/Surface/SurfaceFooter.d.ts +2 -2
- package/Surface/SurfaceFooter.js +5 -1
- package/Surface/SurfaceHeader.d.ts +2 -2
- package/Surface/SurfaceHeader.js +6 -2
- package/Surface/SurfaceSubheader.d.ts +2 -2
- package/Surface/SurfaceSubheader.js +6 -2
- package/Surface/index.d.ts +10 -10
- package/Surface/index.js +18 -9
- package/Swiper/Swiper.d.ts +83 -15
- package/Swiper/Swiper.js +285 -143
- package/Swiper/SwiperContainer.d.ts +2 -2
- package/Swiper/SwiperSlide.js +20 -7
- package/Swiper/SwiperSlidesRenderer.d.ts +4 -0
- package/Swiper/SwiperSlidesRenderer.js +19 -8
- package/Swiper/SwiperTrack.d.ts +22 -2
- package/Swiper/SwiperTrack.js +45 -12
- package/Swiper/SwiperWrapper.d.ts +5 -2
- package/Swiper/SwiperWrapper.js +22 -11
- package/Switch/SwitchAsterisk.js +17 -7
- package/Switch/SwitchContainer.d.ts +2 -2
- package/Switch/SwitchDot.d.ts +1 -1
- package/Switch/SwitchDot.js +2 -4
- package/Switch/SwitchErrorText.js +17 -7
- package/Switch/SwitchTrack.d.ts +1 -1
- package/Switch/index.d.ts +9 -9
- package/Switch/index.js +1 -2
- package/Switch/useSwitchColor.d.ts +1 -1
- package/Table/Table.d.ts +1 -1
- package/Table/Table.js +1 -1
- package/Table/TableCaption.js +5 -1
- package/Table/TableCell.js +6 -2
- package/Table/TableFooter.js +2 -1
- package/Table/TableHeaderCell.js +6 -2
- package/Tabs/Tab.js +4 -1
- package/Tabs/TabPanel.d.ts +1 -1
- package/Tabs/Tabs.d.ts +7 -7
- package/Tabs/Tabs.js +1 -2
- package/Tabs/useTabsColor.d.ts +1 -1
- package/TextArea/TextAreaIconWrapper.d.ts +3 -3
- package/TextArea/TextAreaIconWrapper.js +17 -7
- package/TextArea/TextAreaInput.js +23 -8
- package/TextArea/index.js +18 -9
- package/TextField/TextFieldContainer.js +17 -7
- package/TextField/TextFieldErrorText.js +17 -7
- package/TextField/TextFieldIconWrapper.d.ts +3 -3
- package/TextField/TextFieldIconWrapper.js +17 -7
- package/TextField/TextFieldInput.js +23 -8
- package/TextField/TextFieldInputWrapper.d.ts +5 -5
- package/TextField/TextFieldInputWrapper.js +22 -9
- package/TextField/TextFieldLabel.js +17 -7
- package/TextField/TextFieldLabelAsterisk.js +17 -7
- package/TextField/index.d.ts +1 -1
- package/TextField/index.js +18 -9
- package/ThemeProvider/createTheme.js +7 -3
- package/ThemeProvider/index.d.ts +45 -12
- package/ThemeProvider/index.js +1 -4
- package/ThemeProvider/tokens.d.ts +54 -3
- package/ThemeProvider/tokens.js +61 -3
- package/Toast/ToastCard.js +5 -2
- package/Toast/ToastContainer.js +1 -2
- package/Tooltip/TooltipContainer.js +2 -0
- package/Tooltip/index.js +3 -4
- package/Typography/Base.d.ts +2 -3
- package/Typography/Blockquote.d.ts +2 -3
- package/Typography/List.d.ts +6 -7
- package/Typography/Paragraph.d.ts +1 -1
- package/Typography/Paragraph.js +17 -7
- package/Typography/SectionDescription.d.ts +2 -3
- package/Typography/U.d.ts +2 -3
- package/esm/Accordion/AccordionActions.js +2 -1
- package/esm/Accordion/AccordionContainer.js +2 -14
- package/esm/Accordion/AccordionContent.js +5 -1
- package/esm/Accordion/AccordionHeader.js +7 -3
- package/esm/Accordion/index.js +1 -2
- package/esm/Autocomplete/AutocompleteItem.js +2 -1
- package/esm/Avatar/index.js +1 -2
- package/esm/Badge/BadgeStyled.js +2 -2
- package/esm/Badge/index.js +1 -2
- package/esm/Button/ButtonContainer.js +23 -6
- package/esm/Button/buttonVariants.js +3 -2
- package/esm/Button/index.js +1 -20
- package/esm/ButtonGroup/index.js +4 -3
- package/esm/Calendar/CalendarComponent.js +1 -2
- package/esm/Calendar/CalendarPaper.js +1 -1
- package/esm/Checkbox/CheckboxBox.js +2 -2
- package/esm/Checkbox/index.js +1 -2
- package/esm/ClickOutside/index.js +5 -2
- package/esm/Grid/index.js +7 -2
- package/esm/Highlighted/index.js +1 -2
- package/esm/Menu/MenuContainer.js +2 -3
- package/esm/Menu/MenuItem.js +5 -1
- package/esm/Menu/MenuList.js +1 -1
- package/esm/Modal/BaseModal/ModalInner.js +2 -0
- package/esm/Modal/BaseModal/ModalWrapper.js +30 -37
- package/esm/Modal/BaseModal/index.js +1 -2
- package/esm/Modal/ConfirmBox/ConfirmBoxContent.js +5 -1
- package/esm/Modal/ConfirmBox/ConfirmBoxFooter.js +5 -1
- package/esm/Modal/ConfirmBox/ConfirmBoxHeader.js +5 -1
- package/esm/Modal/ConfirmBox/index.js +1 -2
- package/esm/Modal/Dialog/DialogInner.js +5 -1
- package/esm/Modal/Dialog/index.js +1 -2
- package/esm/Modal/Drawer/DrawerFooter.js +5 -1
- package/esm/Modal/Drawer/DrawerHeader.js +5 -1
- package/esm/Modal/Drawer/index.js +1 -2
- package/esm/Modal/MessageBox/MessageBoxContent.js +5 -1
- package/esm/Modal/MessageBox/MessageBoxFooter.js +5 -1
- package/esm/Modal/MessageBox/MessageBoxHeader.js +5 -1
- package/esm/Modal/MessageBox/index.js +1 -2
- package/esm/Pagination/PaginationContainer.js +29 -0
- package/esm/Pagination/PaginationGap.js +17 -0
- package/esm/Pagination/PaginationIcons.js +15 -0
- package/esm/Pagination/PaginationItem.js +54 -0
- package/esm/Pagination/getPaginationItems.js +40 -0
- package/esm/Pagination/index.js +77 -0
- package/esm/Pagination/usePagination.js +61 -0
- package/esm/Popper/Popper.js +1 -2
- package/esm/Radio/RadioBox.js +2 -2
- package/esm/Radio/index.js +1 -2
- package/esm/RadioGroup/index.js +1 -2
- package/esm/Selectbox/SelectboxButton.js +8 -3
- package/esm/Selectbox/SelectboxButtonWrapper.js +2 -3
- package/esm/Selectbox/index.js +1 -2
- package/esm/Slider/index.js +1 -2
- package/esm/Stack/index.js +7 -2
- package/esm/Surface/SurfaceContainer.js +1 -1
- package/esm/Surface/SurfaceContent.js +18 -11
- package/esm/Surface/SurfaceFooter.js +5 -1
- package/esm/Surface/SurfaceHeader.js +6 -2
- package/esm/Surface/SurfaceSubheader.js +6 -2
- package/esm/Surface/index.js +1 -2
- package/esm/Swiper/Swiper.js +268 -136
- package/esm/Swiper/SwiperSlide.js +3 -0
- package/esm/Swiper/SwiperSlidesRenderer.js +2 -1
- package/esm/Swiper/SwiperTrack.js +28 -5
- package/esm/Swiper/SwiperWrapper.js +5 -4
- package/esm/Switch/SwitchDot.js +2 -4
- package/esm/Switch/index.js +1 -2
- package/esm/Table/Table.js +1 -1
- package/esm/Table/TableCaption.js +5 -1
- package/esm/Table/TableCell.js +6 -2
- package/esm/Table/TableFooter.js +2 -1
- package/esm/Table/TableHeaderCell.js +6 -2
- package/esm/Tabs/Tab.js +5 -2
- package/esm/Tabs/Tabs.js +1 -2
- package/esm/TextArea/TextAreaInput.js +6 -1
- package/esm/TextArea/index.js +1 -2
- package/esm/TextField/TextFieldInput.js +6 -1
- package/esm/TextField/TextFieldInputWrapper.js +5 -2
- package/esm/TextField/index.js +1 -2
- package/esm/ThemeProvider/createTheme.js +7 -3
- package/esm/ThemeProvider/index.js +0 -2
- package/esm/ThemeProvider/tokens.js +55 -2
- package/esm/Toast/ToastCard.js +6 -3
- package/esm/Toast/ToastContainer.js +1 -2
- package/esm/Tooltip/TooltipContainer.js +2 -0
- package/esm/Tooltip/index.js +3 -4
- package/esm/utils/getElementRef.js +13 -0
- package/package.json +46 -11
- package/utils/getElementRef.d.ts +8 -0
- package/utils/getElementRef.js +18 -0
- package/ThemeProvider/components.d.ts +0 -79
- package/ThemeProvider/components.js +0 -3
- package/ThemeProvider/useThemeProps.d.ts +0 -7
- package/ThemeProvider/useThemeProps.js +0 -34
- package/esm/ThemeProvider/components.js +0 -2
- package/esm/ThemeProvider/useThemeProps.js +0 -29
package/esm/Swiper/Swiper.js
CHANGED
|
@@ -14,47 +14,66 @@ import Container from './SwiperContainer';
|
|
|
14
14
|
import Wrapper from './SwiperWrapper';
|
|
15
15
|
import Track from './SwiperTrack';
|
|
16
16
|
import SwiperSlidesRenderer from './SwiperSlidesRenderer';
|
|
17
|
-
import useThemeProps from '../ThemeProvider/useThemeProps';
|
|
18
17
|
export * from './SwiperSlide';
|
|
19
18
|
const defaultSlideLabel = (index, total) => `${index + 1} / ${total}`;
|
|
19
|
+
const prefersReducedMotion = () => typeof window !== 'undefined' &&
|
|
20
|
+
typeof window.matchMedia === 'function' &&
|
|
21
|
+
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
20
22
|
export const Swiper = React.forwardRef((props, ref) => {
|
|
21
|
-
const
|
|
23
|
+
const { children, dragThreshold = 240, snap = true, draggable: draggableProp = true, overrides, initialIndex = 0, infinite = false, onSlideChange, autoplay = false, autoplayInterval = 3000, pauseOnHover = true, threshold = 20, resistance = true, slidesPerView: slidesPerViewProp = 1, centered = false, direction = 'horizontal', effect = 'slide', speed = 300, autoScroll, keyboardControl: keyboardControlProp = true, slideLabel = defaultSlideLabel } = props, restProps = __rest(props, ["children", "dragThreshold", "snap", "draggable", "overrides", "initialIndex", "infinite", "onSlideChange", "autoplay", "autoplayInterval", "pauseOnHover", "threshold", "resistance", "slidesPerView", "centered", "direction", "effect", "speed", "autoScroll", "keyboardControl", "slideLabel"]);
|
|
24
|
+
const isFade = effect === 'fade';
|
|
25
|
+
const isTicker = typeof autoScroll === 'number' && autoScroll > 0 && !isFade;
|
|
26
|
+
const isVertical = direction === 'vertical';
|
|
27
|
+
const slidesPerView = isFade ? 1 : Math.max(slidesPerViewProp, 0.1);
|
|
28
|
+
const draggable = draggableProp && !isTicker;
|
|
29
|
+
const keyboardControl = keyboardControlProp && !isTicker;
|
|
30
|
+
// The current slide is moved to the middle of the view by this number of slides
|
|
31
|
+
const centerShift = centered && !isFade ? (slidesPerView - 1) / 2 : 0;
|
|
22
32
|
// #region Slides
|
|
23
|
-
const slides = React.useMemo(() => {
|
|
33
|
+
const { slides, clones } = React.useMemo(() => {
|
|
24
34
|
// toArray skips null/false and keeps the user keys (prefixed), so the slides are not remounted
|
|
25
35
|
// when a slide is added to the start
|
|
26
36
|
const childrenSlides = React.Children.toArray(children).filter(React.isValidElement);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
// The fade effect does not move the track, the loop does not need the copies
|
|
38
|
+
if (!(infinite || isTicker) || isFade) {
|
|
39
|
+
return { slides: childrenSlides, clones: 0 };
|
|
40
|
+
}
|
|
41
|
+
// The copies on each side cover the whole view (also its partially visible slides)
|
|
42
|
+
// and the part of the view in front of the centered slide
|
|
43
|
+
const count = Math.ceil(slidesPerView) + Math.ceil(centerShift);
|
|
44
|
+
if (childrenSlides.length < Math.max(2, count)) {
|
|
45
|
+
console.error(`For infinite loop with slidesPerView=${slidesPerView}${centered ? ' and centered' : ''}, need at least ${Math.max(2, count)} slides`);
|
|
46
|
+
return { slides: childrenSlides, clones: 0 };
|
|
47
|
+
}
|
|
48
|
+
const headClones = childrenSlides.slice(-count).map((slide, i) => React.cloneElement(slide, {
|
|
49
|
+
key: `clone-head-${i}`,
|
|
50
|
+
'data-clone': 'head',
|
|
51
|
+
}));
|
|
52
|
+
const tailClones = childrenSlides.slice(0, count).map((slide, i) => React.cloneElement(slide, {
|
|
53
|
+
key: `clone-tail-${i}`,
|
|
54
|
+
'data-clone': 'tail',
|
|
55
|
+
}));
|
|
56
|
+
return { slides: [...headClones, ...childrenSlides, ...tailClones], clones: count };
|
|
57
|
+
}, [children, infinite, isTicker, isFade, slidesPerView, centerShift, centered]);
|
|
58
|
+
// The infinite loop by the copies of the slides (slide effect and ticker)
|
|
59
|
+
const isLoop = clones > 0;
|
|
60
|
+
// The fade effect loops by the index alone
|
|
61
|
+
const isFadeLoop = isFade && infinite && slides.length > 1;
|
|
49
62
|
const total = slides.length;
|
|
50
|
-
const realSlidesCount =
|
|
51
|
-
|
|
63
|
+
const realSlidesCount = total - 2 * clones;
|
|
64
|
+
// Without the loop the last position shows the last slide at the end of the view
|
|
65
|
+
// (in the middle of the view when centered). With a fractional slidesPerView it is not a whole
|
|
66
|
+
// slide: the index goes up to the next whole number and the track stops at the last position
|
|
67
|
+
const lastPosition = isFade || centerShift > 0 ? Math.max(0, total - 1) : Math.max(0, total - slidesPerView);
|
|
68
|
+
const maxIndex = Math.ceil(lastPosition - 0.001);
|
|
69
|
+
// The index while the track is between the slides (drag, free mode) without the loop
|
|
70
|
+
const maxFreeIndex = Math.floor(lastPosition + 0.001);
|
|
52
71
|
// #region States
|
|
53
72
|
const [index, setIndex] = React.useState(() => {
|
|
54
|
-
if (!
|
|
73
|
+
if (!isLoop) {
|
|
55
74
|
return Math.max(0, Math.min(initialIndex, maxIndex));
|
|
56
75
|
}
|
|
57
|
-
return initialIndex +
|
|
76
|
+
return initialIndex + clones;
|
|
58
77
|
});
|
|
59
78
|
const [offset, setOffset] = React.useState(0);
|
|
60
79
|
// The long decelerating transition after a free swipe (snap=false)
|
|
@@ -68,8 +87,8 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
68
87
|
const isPaused = isPausedByApi || isHovered || isFocused;
|
|
69
88
|
// #region Refs
|
|
70
89
|
const dragging = React.useRef(false);
|
|
71
|
-
const
|
|
72
|
-
const
|
|
90
|
+
const startCoord = React.useRef(0);
|
|
91
|
+
const lastCoord = React.useRef(0);
|
|
73
92
|
const lastTime = React.useRef(0);
|
|
74
93
|
const velocity = React.useRef(0);
|
|
75
94
|
const wrapperRef = React.useRef(null);
|
|
@@ -77,12 +96,13 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
77
96
|
const isAnimating = React.useRef(false);
|
|
78
97
|
const mounted = React.useRef(true);
|
|
79
98
|
const suppressClick = React.useRef(false);
|
|
99
|
+
const getCoord = React.useCallback((e) => (isVertical ? e.clientY : e.clientX), [isVertical]);
|
|
80
100
|
// #region Real Index
|
|
81
101
|
const realIndex = React.useMemo(() => {
|
|
82
|
-
if (!
|
|
102
|
+
if (!isLoop) {
|
|
83
103
|
return index;
|
|
84
104
|
}
|
|
85
|
-
const realIndex = index -
|
|
105
|
+
const realIndex = index - clones;
|
|
86
106
|
if (realIndex < 0) {
|
|
87
107
|
return realSlidesCount + realIndex;
|
|
88
108
|
}
|
|
@@ -91,7 +111,7 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
91
111
|
}
|
|
92
112
|
// In the infinite mode any slide can be the first visible one, so there is no clamp
|
|
93
113
|
return realIndex;
|
|
94
|
-
}, [index,
|
|
114
|
+
}, [index, isLoop, clones, realSlidesCount]);
|
|
95
115
|
const prevRealIndex = React.useRef(realIndex);
|
|
96
116
|
// #region Effects
|
|
97
117
|
React.useEffect(() => {
|
|
@@ -104,18 +124,18 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
104
124
|
if (!mounted.current)
|
|
105
125
|
return;
|
|
106
126
|
// The slides were removed: keep the index inside the allowed range
|
|
107
|
-
const lastIndex =
|
|
127
|
+
const lastIndex = isLoop ? total - clones : maxIndex;
|
|
108
128
|
if (index > lastIndex) {
|
|
109
|
-
setIndex(
|
|
129
|
+
setIndex(isLoop ? clones : maxIndex);
|
|
110
130
|
setOffset(0);
|
|
111
131
|
}
|
|
112
|
-
}, [index,
|
|
132
|
+
}, [index, isLoop, total, clones, maxIndex]);
|
|
113
133
|
// #region Normalization
|
|
114
134
|
const normalizeIndex = React.useCallback(() => {
|
|
115
|
-
if (!
|
|
135
|
+
if (!isLoop || !mounted.current)
|
|
116
136
|
return;
|
|
117
|
-
const firstRealIndex =
|
|
118
|
-
const lastRealIndex = total -
|
|
137
|
+
const firstRealIndex = clones;
|
|
138
|
+
const lastRealIndex = total - clones - 1;
|
|
119
139
|
if (index < firstRealIndex || index > lastRealIndex) {
|
|
120
140
|
// A clone position shows the same slides as the real position shifted by the slides count.
|
|
121
141
|
// Not always the first/last real slide: after several fast clicks the index may be deeper in the clones
|
|
@@ -135,7 +155,7 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
135
155
|
});
|
|
136
156
|
});
|
|
137
157
|
}
|
|
138
|
-
}, [index,
|
|
158
|
+
}, [index, isLoop, clones, total, realSlidesCount]);
|
|
139
159
|
// #region Navigation API
|
|
140
160
|
const indexRef = React.useRef(index);
|
|
141
161
|
React.useEffect(() => {
|
|
@@ -144,13 +164,13 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
144
164
|
const goToIndex = React.useCallback((i) => {
|
|
145
165
|
// In the infinite mode the index is normalized after the transition, so wait for it.
|
|
146
166
|
// In the regular mode the transition is simply retargeted
|
|
147
|
-
if (
|
|
167
|
+
if (isLoop && isAnimating.current)
|
|
148
168
|
return;
|
|
149
169
|
let targetIndex = i;
|
|
150
|
-
if (
|
|
151
|
-
targetIndex = i +
|
|
152
|
-
const minIndex =
|
|
153
|
-
const maxIndex =
|
|
170
|
+
if (isLoop) {
|
|
171
|
+
targetIndex = i + clones;
|
|
172
|
+
const minIndex = clones;
|
|
173
|
+
const maxIndex = clones + realSlidesCount - 1;
|
|
154
174
|
targetIndex = Math.max(minIndex, Math.min(maxIndex, targetIndex));
|
|
155
175
|
}
|
|
156
176
|
else {
|
|
@@ -164,17 +184,20 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
164
184
|
setOffset(0);
|
|
165
185
|
setIndex(targetIndex);
|
|
166
186
|
isAnimating.current = true;
|
|
167
|
-
}, [
|
|
187
|
+
}, [isLoop, clones, realSlidesCount, maxIndex]);
|
|
168
188
|
const next = React.useCallback(() => {
|
|
169
189
|
setDisableAnimation(false);
|
|
170
190
|
setIsMomentum(false);
|
|
171
191
|
setOffset(0);
|
|
172
192
|
setIndex(prev => {
|
|
173
193
|
let nextIndex;
|
|
174
|
-
if (
|
|
194
|
+
if (isLoop) {
|
|
175
195
|
// The last position is the first tail clone: it mirrors the first real slide.
|
|
176
196
|
// Further positions would show the empty space when slidesPerView > 1
|
|
177
|
-
nextIndex = Math.min(prev + 1, total -
|
|
197
|
+
nextIndex = Math.min(prev + 1, total - clones);
|
|
198
|
+
}
|
|
199
|
+
else if (isFadeLoop) {
|
|
200
|
+
nextIndex = (prev + 1) % total;
|
|
178
201
|
}
|
|
179
202
|
else {
|
|
180
203
|
nextIndex = Math.min(prev + 1, maxIndex);
|
|
@@ -186,50 +209,61 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
186
209
|
isAnimating.current = true;
|
|
187
210
|
return nextIndex;
|
|
188
211
|
});
|
|
189
|
-
}, [
|
|
212
|
+
}, [isLoop, isFadeLoop, maxIndex, total, clones]);
|
|
190
213
|
const prev = React.useCallback(() => {
|
|
191
214
|
setDisableAnimation(false);
|
|
192
215
|
setIsMomentum(false);
|
|
193
216
|
setOffset(0);
|
|
194
217
|
setIndex(prev => {
|
|
195
|
-
const nextIndex = Math.max(prev - 1, 0);
|
|
218
|
+
const nextIndex = isFadeLoop ? (prev - 1 + total) % total : Math.max(prev - 1, 0);
|
|
196
219
|
if (nextIndex === prev) {
|
|
197
220
|
return prev;
|
|
198
221
|
}
|
|
199
222
|
isAnimating.current = true;
|
|
200
223
|
return nextIndex;
|
|
201
224
|
});
|
|
202
|
-
}, []);
|
|
225
|
+
}, [isFadeLoop, total]);
|
|
203
226
|
// #region Position
|
|
204
|
-
// The position is the distance in pixels from the start of the track to the
|
|
205
|
-
// The state keeps it as index (whole slides) + offset (pixels)
|
|
206
|
-
const
|
|
227
|
+
// The position is the distance in pixels from the start of the track to the start of the view
|
|
228
|
+
// without the centering shift. The state keeps it as index (whole slides) + offset (pixels)
|
|
229
|
+
const getSlideSize = React.useCallback(() => {
|
|
230
|
+
const wrapper = wrapperRef.current;
|
|
231
|
+
const size = (isVertical ? wrapper === null || wrapper === void 0 ? void 0 : wrapper.clientHeight : wrapper === null || wrapper === void 0 ? void 0 : wrapper.clientWidth) || 0;
|
|
232
|
+
return size / slidesPerView;
|
|
233
|
+
}, [isVertical, slidesPerView]);
|
|
207
234
|
// The last allowed position. In the infinite mode it is the first tail clone
|
|
208
|
-
const maxPosition = React.useCallback(() => (
|
|
235
|
+
const maxPosition = React.useCallback(() => (isLoop ? total - clones : lastPosition) * getSlideSize(), [isLoop, total, clones, lastPosition, getSlideSize]);
|
|
236
|
+
// The index of the track: without the loop the track stops at the last position
|
|
237
|
+
// even if the index is the next whole number
|
|
238
|
+
const trackIndex = (isLoop ? index : Math.min(index, lastPosition)) - centerShift;
|
|
209
239
|
// The position on the screen right now, also in the middle of a transition
|
|
210
240
|
const readPosition = React.useCallback(() => {
|
|
211
241
|
const track = trackRef.current;
|
|
242
|
+
const size = getSlideSize();
|
|
212
243
|
if (track && typeof DOMMatrixReadOnly !== 'undefined') {
|
|
213
244
|
const { transform } = getComputedStyle(track);
|
|
214
245
|
if (transform && transform !== 'none') {
|
|
215
|
-
|
|
246
|
+
const matrix = new DOMMatrixReadOnly(transform);
|
|
247
|
+
return -(isVertical ? matrix.m42 : matrix.m41) + centerShift * size;
|
|
216
248
|
}
|
|
217
249
|
}
|
|
218
|
-
return
|
|
219
|
-
}, [
|
|
250
|
+
return (trackIndex + centerShift) * size - offset;
|
|
251
|
+
}, [trackIndex, centerShift, offset, getSlideSize, isVertical]);
|
|
220
252
|
// Infinite mode: the same view is shown by the real slides and by the clones,
|
|
221
253
|
// so the position is moved by the whole slides count when it comes close to the edge of the track
|
|
222
254
|
const wrapPosition = React.useCallback((position) => {
|
|
223
|
-
const
|
|
224
|
-
const span = realSlidesCount *
|
|
225
|
-
if (!
|
|
255
|
+
const size = getSlideSize();
|
|
256
|
+
const span = realSlidesCount * size;
|
|
257
|
+
if (!isLoop || size === 0)
|
|
226
258
|
return 0;
|
|
227
|
-
if (position <
|
|
259
|
+
if (position < size * 0.5)
|
|
228
260
|
return span;
|
|
229
|
-
if (position > maxPosition() -
|
|
261
|
+
if (position > maxPosition() - size * 0.5)
|
|
230
262
|
return -span;
|
|
231
263
|
return 0;
|
|
232
|
-
}, [
|
|
264
|
+
}, [isLoop, realSlidesCount, getSlideSize, maxPosition]);
|
|
265
|
+
// Without the loop the index between the slides does not go past the last position
|
|
266
|
+
const clampFreeIndex = React.useCallback((i) => (isLoop ? i : Math.max(0, Math.min(maxFreeIndex, i))), [isLoop, maxFreeIndex]);
|
|
233
267
|
const dragBasePosition = React.useRef(0);
|
|
234
268
|
const dragAnchorIndex = React.useRef(0);
|
|
235
269
|
const dragPosition = React.useRef(0);
|
|
@@ -240,49 +274,61 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
240
274
|
// Only the main mouse button, the touch or the pen
|
|
241
275
|
if (e.pointerType === 'mouse' && e.button !== 0)
|
|
242
276
|
return;
|
|
243
|
-
|
|
277
|
+
suppressClick.current = false;
|
|
278
|
+
dragging.current = true;
|
|
279
|
+
startCoord.current = getCoord(e);
|
|
280
|
+
lastCoord.current = getCoord(e);
|
|
281
|
+
lastTime.current = performance.now();
|
|
282
|
+
velocity.current = 0;
|
|
283
|
+
// The capture fails for a pointer that is already gone: the drag still works without it
|
|
284
|
+
try {
|
|
285
|
+
e.target.setPointerCapture(e.pointerId);
|
|
286
|
+
}
|
|
287
|
+
catch (_a) {
|
|
288
|
+
// nothing
|
|
289
|
+
}
|
|
290
|
+
// The fade does not move the track: the slide changes after the release
|
|
291
|
+
if (isFade)
|
|
292
|
+
return;
|
|
293
|
+
const size = getSlideSize();
|
|
244
294
|
// Grab the track where it is now: a running transition stops under the finger instead of jumping
|
|
245
295
|
let position = readPosition();
|
|
246
296
|
position += wrapPosition(position);
|
|
247
|
-
const anchor =
|
|
297
|
+
const anchor = clampFreeIndex(size > 0 ? Math.round(position / size) : index);
|
|
248
298
|
dragBasePosition.current = position;
|
|
249
299
|
dragPosition.current = position;
|
|
250
300
|
dragAnchorIndex.current = anchor;
|
|
251
|
-
suppressClick.current = false;
|
|
252
|
-
dragging.current = true;
|
|
253
301
|
isAnimating.current = false;
|
|
254
302
|
setDisableAnimation(true);
|
|
255
303
|
setIsMomentum(false);
|
|
256
304
|
setIsDragging(true);
|
|
257
305
|
setIndex(anchor);
|
|
258
|
-
setOffset(anchor *
|
|
259
|
-
|
|
260
|
-
lastX.current = e.clientX;
|
|
261
|
-
lastTime.current = performance.now();
|
|
262
|
-
velocity.current = 0;
|
|
263
|
-
e.target.setPointerCapture(e.pointerId);
|
|
264
|
-
}, [draggable, getSlideWidth, readPosition, wrapPosition, index]);
|
|
306
|
+
setOffset(anchor * size - position);
|
|
307
|
+
}, [draggable, isFade, getCoord, getSlideSize, readPosition, wrapPosition, clampFreeIndex, index]);
|
|
265
308
|
const onPointerMove = React.useCallback((e) => {
|
|
266
309
|
if (!dragging.current)
|
|
267
310
|
return;
|
|
311
|
+
const coord = getCoord(e);
|
|
268
312
|
const now = performance.now();
|
|
269
|
-
const
|
|
313
|
+
const delta = coord - lastCoord.current;
|
|
270
314
|
const dt = now - lastTime.current;
|
|
271
315
|
if (dt > 0) {
|
|
272
|
-
velocity.current =
|
|
316
|
+
velocity.current = delta / dt;
|
|
273
317
|
}
|
|
274
|
-
|
|
318
|
+
lastCoord.current = coord;
|
|
275
319
|
lastTime.current = now;
|
|
276
|
-
|
|
277
|
-
|
|
320
|
+
if (isFade)
|
|
321
|
+
return;
|
|
322
|
+
const size = getSlideSize();
|
|
323
|
+
let position = dragBasePosition.current - (coord - startCoord.current);
|
|
278
324
|
// Endless drag in the infinite mode: move the base together with the position
|
|
279
325
|
const shift = wrapPosition(position);
|
|
280
326
|
if (shift !== 0) {
|
|
281
327
|
dragBasePosition.current += shift;
|
|
282
|
-
dragAnchorIndex.current += Math.round(shift /
|
|
328
|
+
dragAnchorIndex.current += Math.round(shift / size);
|
|
283
329
|
position += shift;
|
|
284
330
|
}
|
|
285
|
-
if (!
|
|
331
|
+
if (!isLoop) {
|
|
286
332
|
const max = maxPosition();
|
|
287
333
|
if (position < 0) {
|
|
288
334
|
position = resistance ? position * 0.3 : 0;
|
|
@@ -294,27 +340,55 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
294
340
|
dragPosition.current = position;
|
|
295
341
|
// snap: the index stays the same during the drag, the slide changes after the release.
|
|
296
342
|
// free: the index follows the position, so onSlideChange reports the slide under the view
|
|
297
|
-
const nextIndex = snap
|
|
343
|
+
const nextIndex = snap
|
|
344
|
+
? dragAnchorIndex.current
|
|
345
|
+
: clampFreeIndex(Math.round(position / size));
|
|
298
346
|
setIndex(nextIndex);
|
|
299
|
-
setOffset(nextIndex *
|
|
300
|
-
}, [
|
|
347
|
+
setOffset(nextIndex * size - position);
|
|
348
|
+
}, [
|
|
349
|
+
getCoord,
|
|
350
|
+
isFade,
|
|
351
|
+
getSlideSize,
|
|
352
|
+
wrapPosition,
|
|
353
|
+
isLoop,
|
|
354
|
+
maxPosition,
|
|
355
|
+
resistance,
|
|
356
|
+
snap,
|
|
357
|
+
clampFreeIndex,
|
|
358
|
+
]);
|
|
301
359
|
const onPointerUp = React.useCallback((e) => {
|
|
302
360
|
if (!dragging.current)
|
|
303
361
|
return;
|
|
304
|
-
const
|
|
305
|
-
const position = dragPosition.current;
|
|
306
|
-
const delta = lastX.current - startX.current;
|
|
307
|
-
// The pointer stopped before the release: no inertia
|
|
308
|
-
const v = performance.now() - lastTime.current > 100 ? 0 : velocity.current;
|
|
309
|
-
const lastIndex = infinite ? total - slidesPerView : maxIndex;
|
|
362
|
+
const delta = lastCoord.current - startCoord.current;
|
|
310
363
|
// It was a drag, not a click: the click on a link or a button inside the slide must not fire
|
|
311
364
|
if (Math.abs(delta) > threshold) {
|
|
312
365
|
suppressClick.current = true;
|
|
313
366
|
}
|
|
367
|
+
dragging.current = false;
|
|
368
|
+
try {
|
|
369
|
+
e.target.releasePointerCapture(e.pointerId);
|
|
370
|
+
}
|
|
371
|
+
catch (_a) {
|
|
372
|
+
// nothing
|
|
373
|
+
}
|
|
374
|
+
if (isFade) {
|
|
375
|
+
if (delta < -threshold) {
|
|
376
|
+
next();
|
|
377
|
+
}
|
|
378
|
+
else if (delta > threshold) {
|
|
379
|
+
prev();
|
|
380
|
+
}
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const size = getSlideSize();
|
|
384
|
+
const position = dragPosition.current;
|
|
385
|
+
// The pointer stopped before the release: no inertia
|
|
386
|
+
const v = performance.now() - lastTime.current > 100 ? 0 : velocity.current;
|
|
387
|
+
const lastIndex = isLoop ? total - clones : maxIndex;
|
|
314
388
|
setDisableAnimation(false);
|
|
315
389
|
if (snap) {
|
|
316
390
|
const anchor = dragAnchorIndex.current;
|
|
317
|
-
const displacement = position - anchor *
|
|
391
|
+
const displacement = position - anchor * size;
|
|
318
392
|
const velocityFactor = Math.min(Math.abs(v) * 250, 0.65);
|
|
319
393
|
const dynamicThreshold = Math.max(threshold, Math.min(dragThreshold * (1 - velocityFactor), dragThreshold));
|
|
320
394
|
let nextIndex = anchor;
|
|
@@ -322,37 +396,42 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
322
396
|
// At least one slide, more if the slide was dragged further
|
|
323
397
|
nextIndex =
|
|
324
398
|
displacement > 0
|
|
325
|
-
? Math.max(anchor + 1, Math.round(position /
|
|
326
|
-
: Math.min(anchor - 1, Math.round(position /
|
|
399
|
+
? Math.max(anchor + 1, Math.round(position / size))
|
|
400
|
+
: Math.min(anchor - 1, Math.round(position / size));
|
|
327
401
|
}
|
|
328
402
|
nextIndex = Math.max(0, Math.min(lastIndex, nextIndex));
|
|
329
403
|
setIndex(nextIndex);
|
|
330
404
|
setOffset(0);
|
|
331
405
|
// A click without movement does not start a transition, so transitionend never comes
|
|
332
406
|
// and the flag would block autoplay and goToIndex forever
|
|
333
|
-
|
|
407
|
+
const target = (isLoop ? nextIndex : Math.min(nextIndex, lastPosition)) * size;
|
|
408
|
+
isAnimating.current = Math.abs(target - position) > 0.5;
|
|
334
409
|
}
|
|
335
410
|
else {
|
|
336
411
|
// Free mode: the track keeps moving by inertia and stops where it stops
|
|
337
|
-
const
|
|
338
|
-
const
|
|
412
|
+
const maxProjected = (isLoop ? lastIndex : lastPosition) * size;
|
|
413
|
+
const projected = Math.max(0, Math.min(maxProjected, position - v * 300));
|
|
414
|
+
const nextIndex = clampFreeIndex(size > 0 ? Math.round(projected / size) : index);
|
|
339
415
|
setIsMomentum(true);
|
|
340
416
|
setIndex(nextIndex);
|
|
341
|
-
setOffset(nextIndex *
|
|
417
|
+
setOffset(nextIndex * size - projected);
|
|
342
418
|
isAnimating.current = Math.abs(projected - position) > 0.5;
|
|
343
419
|
}
|
|
344
|
-
dragging.current = false;
|
|
345
420
|
setIsDragging(false);
|
|
346
|
-
e.target.releasePointerCapture(e.pointerId);
|
|
347
421
|
}, [
|
|
348
|
-
|
|
349
|
-
|
|
422
|
+
isFade,
|
|
423
|
+
next,
|
|
424
|
+
prev,
|
|
425
|
+
getSlideSize,
|
|
426
|
+
isLoop,
|
|
350
427
|
total,
|
|
351
|
-
|
|
428
|
+
clones,
|
|
352
429
|
maxIndex,
|
|
430
|
+
lastPosition,
|
|
353
431
|
threshold,
|
|
354
432
|
snap,
|
|
355
433
|
dragThreshold,
|
|
434
|
+
clampFreeIndex,
|
|
356
435
|
index,
|
|
357
436
|
]);
|
|
358
437
|
const onLostPointerCapture = React.useCallback((e) => {
|
|
@@ -364,7 +443,7 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
364
443
|
const autoplayStep = React.useRef(() => undefined);
|
|
365
444
|
autoplayStep.current = () => {
|
|
366
445
|
// Without the infinite loop the autoplay returns to the first slide instead of stopping at the end
|
|
367
|
-
if (!
|
|
446
|
+
if (!isLoop && !isFadeLoop && indexRef.current >= maxIndex) {
|
|
368
447
|
goToIndex(0);
|
|
369
448
|
}
|
|
370
449
|
else {
|
|
@@ -374,7 +453,7 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
374
453
|
const pause = React.useCallback(() => setIsPausedByApi(true), []);
|
|
375
454
|
const resume = React.useCallback(() => setIsPausedByApi(false), []);
|
|
376
455
|
React.useEffect(() => {
|
|
377
|
-
if (!autoplay || isPaused)
|
|
456
|
+
if (!autoplay || isTicker || isPaused)
|
|
378
457
|
return undefined;
|
|
379
458
|
const timer = setInterval(() => {
|
|
380
459
|
if (!dragging.current && !isAnimating.current && mounted.current) {
|
|
@@ -382,13 +461,57 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
382
461
|
}
|
|
383
462
|
}, autoplayInterval);
|
|
384
463
|
return () => clearInterval(timer);
|
|
385
|
-
}, [autoplay, autoplayInterval, isPaused]);
|
|
464
|
+
}, [autoplay, isTicker, autoplayInterval, isPaused]);
|
|
465
|
+
// #region Ticker
|
|
466
|
+
// The continuous scroll writes the transform directly: 60 renders per second are not needed for it.
|
|
467
|
+
// The position is kept in slides, so it stays in place when the size of the swiper changes
|
|
468
|
+
const tickerPosition = React.useRef(null);
|
|
469
|
+
React.useEffect(() => {
|
|
470
|
+
const track = trackRef.current;
|
|
471
|
+
if (!isTicker || !isLoop || !track)
|
|
472
|
+
return undefined;
|
|
473
|
+
if (isPaused || prefersReducedMotion())
|
|
474
|
+
return undefined;
|
|
475
|
+
let frame = 0;
|
|
476
|
+
let last = performance.now();
|
|
477
|
+
const step = (now) => {
|
|
478
|
+
var _a;
|
|
479
|
+
const size = getSlideSize();
|
|
480
|
+
if (size > 0) {
|
|
481
|
+
let position = (_a = tickerPosition.current) !== null && _a !== void 0 ? _a : clones;
|
|
482
|
+
position += ((autoScroll || 0) * (now - last)) / 1000 / size;
|
|
483
|
+
if (position >= clones + realSlidesCount) {
|
|
484
|
+
position -= realSlidesCount;
|
|
485
|
+
}
|
|
486
|
+
tickerPosition.current = position;
|
|
487
|
+
const translate = -(position - centerShift) * size;
|
|
488
|
+
track.style.transition = 'none';
|
|
489
|
+
track.style.transform = isVertical
|
|
490
|
+
? `translateY(${translate}px)`
|
|
491
|
+
: `translateX(${translate}px)`;
|
|
492
|
+
}
|
|
493
|
+
last = now;
|
|
494
|
+
frame = requestAnimationFrame(step);
|
|
495
|
+
};
|
|
496
|
+
frame = requestAnimationFrame(step);
|
|
497
|
+
return () => cancelAnimationFrame(frame);
|
|
498
|
+
}, [
|
|
499
|
+
isTicker,
|
|
500
|
+
isLoop,
|
|
501
|
+
isPaused,
|
|
502
|
+
autoScroll,
|
|
503
|
+
getSlideSize,
|
|
504
|
+
realSlidesCount,
|
|
505
|
+
clones,
|
|
506
|
+
centerShift,
|
|
507
|
+
isVertical,
|
|
508
|
+
]);
|
|
386
509
|
// #region Hover and focus
|
|
387
510
|
// The autoplay pauses while the pointer is over the swiper (pauseOnHover)
|
|
388
511
|
// and always while the focus is inside it, so the keyboard user is not interrupted
|
|
389
512
|
React.useEffect(() => {
|
|
390
513
|
const wrapper = wrapperRef.current;
|
|
391
|
-
if (!autoplay || !wrapper)
|
|
514
|
+
if (!(autoplay || isTicker) || !wrapper)
|
|
392
515
|
return undefined;
|
|
393
516
|
const handleMouseEnter = () => pauseOnHover && setIsHovered(true);
|
|
394
517
|
const handleMouseLeave = () => setIsHovered(false);
|
|
@@ -408,7 +531,7 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
408
531
|
wrapper.removeEventListener('focusin', handleFocusIn);
|
|
409
532
|
wrapper.removeEventListener('focusout', handleFocusOut);
|
|
410
533
|
};
|
|
411
|
-
}, [autoplay, pauseOnHover]);
|
|
534
|
+
}, [autoplay, isTicker, pauseOnHover]);
|
|
412
535
|
// #region Keyboard
|
|
413
536
|
const onKeyDown = React.useCallback((event) => {
|
|
414
537
|
if (!keyboardControl)
|
|
@@ -417,15 +540,15 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
417
540
|
const target = event.target;
|
|
418
541
|
if (target.closest('input, textarea, select, [contenteditable="true"]'))
|
|
419
542
|
return;
|
|
420
|
-
if (event.key === 'ArrowLeft') {
|
|
543
|
+
if (event.key === (isVertical ? 'ArrowUp' : 'ArrowLeft')) {
|
|
421
544
|
event.preventDefault();
|
|
422
545
|
prev();
|
|
423
546
|
}
|
|
424
|
-
if (event.key === 'ArrowRight') {
|
|
547
|
+
if (event.key === (isVertical ? 'ArrowDown' : 'ArrowRight')) {
|
|
425
548
|
event.preventDefault();
|
|
426
549
|
next();
|
|
427
550
|
}
|
|
428
|
-
}, [keyboardControl, prev, next]);
|
|
551
|
+
}, [keyboardControl, isVertical, prev, next]);
|
|
429
552
|
const onClickCapture = React.useCallback((event) => {
|
|
430
553
|
if (suppressClick.current) {
|
|
431
554
|
suppressClick.current = false;
|
|
@@ -444,14 +567,16 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
444
567
|
const track = trackRef.current;
|
|
445
568
|
if (!track)
|
|
446
569
|
return;
|
|
570
|
+
// The fade changes the opacity of the slides, the event bubbles up to the track
|
|
571
|
+
const property = isFade ? 'opacity' : 'transform';
|
|
447
572
|
const handleTransitionEnd = (e) => {
|
|
448
|
-
if (e.propertyName !==
|
|
573
|
+
if (e.propertyName !== property)
|
|
449
574
|
return;
|
|
450
575
|
isAnimating.current = false;
|
|
451
|
-
normalizeIndex();
|
|
576
|
+
normalizeIndex();
|
|
452
577
|
};
|
|
453
578
|
const handleTransitionCancel = (e) => {
|
|
454
|
-
if (e.propertyName !==
|
|
579
|
+
if (e.propertyName !== property)
|
|
455
580
|
return;
|
|
456
581
|
isAnimating.current = false;
|
|
457
582
|
};
|
|
@@ -461,7 +586,7 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
461
586
|
track.removeEventListener('transitionend', handleTransitionEnd);
|
|
462
587
|
track.removeEventListener('transitioncancel', handleTransitionCancel);
|
|
463
588
|
};
|
|
464
|
-
}, [normalizeIndex]);
|
|
589
|
+
}, [normalizeIndex, isFade]);
|
|
465
590
|
// #region Mount
|
|
466
591
|
React.useEffect(() => {
|
|
467
592
|
mounted.current = true;
|
|
@@ -486,34 +611,41 @@ export const Swiper = React.forwardRef((props, ref) => {
|
|
|
486
611
|
Wrapper: (overrides === null || overrides === void 0 ? void 0 : overrides.Wrapper) || Wrapper,
|
|
487
612
|
}), [overrides]);
|
|
488
613
|
const getSlideRealIndex = React.useCallback((domIndex) => {
|
|
489
|
-
if (!
|
|
614
|
+
if (!isLoop) {
|
|
490
615
|
return domIndex;
|
|
491
616
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
return totalSlides - slidesPerView + domIndex;
|
|
617
|
+
if (domIndex < clones) {
|
|
618
|
+
return realSlidesCount - clones + domIndex;
|
|
495
619
|
}
|
|
496
|
-
if (domIndex >= total -
|
|
497
|
-
return domIndex - (total -
|
|
620
|
+
if (domIndex >= total - clones) {
|
|
621
|
+
return domIndex - (total - clones);
|
|
498
622
|
}
|
|
499
|
-
return domIndex -
|
|
500
|
-
}, [
|
|
623
|
+
return domIndex - clones;
|
|
624
|
+
}, [isLoop, realSlidesCount, clones, total]);
|
|
501
625
|
// The slides at least partially in the view: they are not inert, so a partially visible slide
|
|
502
|
-
// can be clicked. Between the slides (drag, free mode)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
626
|
+
// can be clicked. Between the slides (drag, free mode), with a fractional slidesPerView
|
|
627
|
+
// and with the centering one more slide is partially visible
|
|
628
|
+
const wrapper = wrapperRef.current;
|
|
629
|
+
const slideSize = wrapper
|
|
630
|
+
? (isVertical ? wrapper.clientHeight : wrapper.clientWidth) / slidesPerView
|
|
631
|
+
: 0;
|
|
632
|
+
const viewPosition = slideSize > 0 ? trackIndex - offset / slideSize : trackIndex;
|
|
633
|
+
let firstVisibleDomIndex = Math.floor(viewPosition + 0.001);
|
|
634
|
+
let visibleCount = Math.ceil(viewPosition + slidesPerView - 0.001) - firstVisibleDomIndex;
|
|
635
|
+
if (isFade) {
|
|
636
|
+
firstVisibleDomIndex = index;
|
|
637
|
+
visibleCount = 1;
|
|
511
638
|
}
|
|
512
639
|
firstVisibleDomIndex = Math.max(0, Math.min(total - 1, firstVisibleDomIndex));
|
|
640
|
+
// The ticker moves without the state: all the slides are rendered
|
|
641
|
+
if (isTicker) {
|
|
642
|
+
firstVisibleDomIndex = clones;
|
|
643
|
+
visibleCount = realSlidesCount;
|
|
644
|
+
}
|
|
513
645
|
return (React.createElement(overridesMap.Container, Object.assign({ role: "region", "aria-roledescription": "carousel" }, restProps),
|
|
514
|
-
React.createElement(overridesMap.Wrapper, { ref: wrapperRef, draggable: draggable, slidesPerView: slidesPerView, tabIndex: keyboardControl ? 0 : undefined, "aria-live": autoplay && !isPaused ? 'off' : 'polite', onKeyDown: onKeyDown, onClickCapture: onClickCapture, onDragStart: onDragStart, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onLostPointerCapture: onLostPointerCapture },
|
|
515
|
-
React.createElement(overridesMap.Track, { ref: trackRef, dragging: isDragging, index:
|
|
516
|
-
React.createElement(SwiperSlidesRenderer, { slides: slides, slidesPerView: slidesPerView, realIndex: realIndex, firstVisibleIndex: getSlideRealIndex(firstVisibleDomIndex), visibleCount: visibleCount, realSlidesCount: realSlidesCount, getSlideRealIndex: getSlideRealIndex, slideLabel: slideLabel })))));
|
|
646
|
+
React.createElement(overridesMap.Wrapper, { ref: wrapperRef, draggable: draggable, slidesPerView: slidesPerView, vertical: isVertical, tabIndex: keyboardControl ? 0 : undefined, "aria-live": (autoplay || isTicker) && !isPaused ? 'off' : 'polite', onKeyDown: onKeyDown, onClickCapture: onClickCapture, onDragStart: onDragStart, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onLostPointerCapture: onLostPointerCapture },
|
|
647
|
+
React.createElement(overridesMap.Track, { ref: trackRef, dragging: isDragging, index: isFade ? 0 : trackIndex, offset: isFade ? 0 : offset, disableAnimation: disableAnimation, momentum: isMomentum, slidesPerView: slidesPerView, vertical: isVertical, effect: effect, speed: speed },
|
|
648
|
+
React.createElement(SwiperSlidesRenderer, { slides: slides, slidesPerView: slidesPerView, realIndex: realIndex, firstVisibleIndex: getSlideRealIndex(firstVisibleDomIndex), visibleCount: visibleCount, realSlidesCount: realSlidesCount, getSlideRealIndex: getSlideRealIndex, slideLabel: slideLabel, activeDomIndex: isFade ? index : null })))));
|
|
517
649
|
});
|
|
518
650
|
Swiper.displayName = 'Swiper';
|
|
519
651
|
export default Swiper;
|