-
Notifications
You must be signed in to change notification settings - Fork 552
Expand file tree
/
Copy pathCarousel.js
More file actions
129 lines (121 loc) · 3.44 KB
/
Copy pathCarousel.js
File metadata and controls
129 lines (121 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import {
createCarouselComponent,
generateCarouselId,
} from 'instantsearch-ui-components';
import { createHooksStore } from '../util/hooks';
import { Fragment, isVue3, renderReactCompat } from '../util/vue-compat';
/**
* Vue wrapper around the shared `instantsearch-ui-components` Carousel.
*
* The shared Carousel is a hook-driven component (`useState` for scroll
* affordances, `useRef` for the list/buttons). Vue can't supply React hooks
* natively, so this component owns a `hooksStore` (see `util/hooks.js`) and
* drives it through its own render cycle — mirroring how React's
* `components/Carousel.tsx` uses `useState` / `useRef`.
*
* It's a real Vue child component (not a plain function) so it gets its own
* hook context, which matters because the layout is mounted/unmounted
* conditionally by the parent recommend widget.
*/
export default {
name: 'AisCarousel',
props: {
items: {
type: Array,
required: true,
},
itemComponent: {
type: Function,
required: false,
default: undefined,
},
sendEvent: {
type: Function,
required: false,
default: () => {},
},
classNames: {
type: Object,
required: false,
default: undefined,
},
translations: {
type: Object,
required: false,
default: undefined,
},
// Optional overrides used by the chat tools (custom header, no built-in
// navigation, custom scroll icons).
headerComponent: {
type: Function,
required: false,
default: undefined,
},
showNavigation: {
type: Boolean,
required: false,
default: true,
},
previousIconComponent: {
type: Function,
required: false,
default: undefined,
},
nextIconComponent: {
type: Function,
required: false,
default: undefined,
},
},
created() {
this.hooksStore = createHooksStore(() => this.$forceUpdate());
},
mounted() {
this.hooksStore.flushEffects();
},
updated() {
this.hooksStore.flushEffects();
},
[isVue3 ? 'beforeUnmount' : 'beforeDestroy']() {
this.hooksStore.cleanup();
},
render: renderReactCompat(function (h) {
const CarouselUiComponent = createCarouselComponent({
createElement: h,
Fragment,
});
const { useState, useRef } = this.hooksStore.hooks;
this.hooksStore.beginRender();
const [canScrollLeft, setCanScrollLeft] = useState(false);
const [canScrollRight, setCanScrollRight] = useState(true);
const listRef = useRef(null);
const nextButtonRef = useRef(null);
const previousButtonRef = useRef(null);
const carouselIdRef = useRef(generateCarouselId());
const tree = h(CarouselUiComponent, {
items: this.items,
itemComponent: this.itemComponent,
sendEvent: this.sendEvent,
translations: this.translations,
headerComponent: this.headerComponent,
showNavigation: this.showNavigation,
previousIconComponent: this.previousIconComponent,
nextIconComponent: this.nextIconComponent,
// The parent recommend widget forwards its own `list`/`item` classes.
classNames: this.classNames && {
list: this.classNames.list,
item: this.classNames.item,
},
listRef,
nextButtonRef,
previousButtonRef,
carouselIdRef,
canScrollLeft,
canScrollRight,
setCanScrollLeft,
setCanScrollRight,
});
this.hooksStore.endRender();
return tree;
}),
};