1 | import {
|
2 | createEffect,
|
3 | createMemo,
|
4 | createSignal,
|
5 | onCleanup,
|
6 | onMount,
|
7 | Show,
|
8 | splitProps,
|
9 | children,
|
10 | } from 'solid-js';
|
11 | import SwiperCore from 'swiper';
|
12 | import { SwiperContext } from './context.js';
|
13 | import { getChangedParams } from '../components-shared/get-changed-params.js';
|
14 | import { getChildren } from './get-children.js';
|
15 | import { getParams } from '../components-shared/get-params.js';
|
16 | import { calcLoopedSlides, renderLoop } from './loop.js';
|
17 | import { mountSwiper } from '../components-shared/mount-swiper.js';
|
18 | import { updateSwiper } from '../components-shared/update-swiper.js';
|
19 | import {
|
20 | extend,
|
21 | needsNavigation,
|
22 | needsPagination,
|
23 | needsScrollbar,
|
24 | uniqueClasses,
|
25 | } from '../components-shared/utils.js';
|
26 | import { renderVirtual } from './virtual.js';
|
27 | import { updateOnVirtualData } from '../components-shared/update-on-virtual-data.js';
|
28 |
|
29 | const Swiper = (props) => {
|
30 | let eventsAssigned = false;
|
31 | const [containerClasses, setContainerClasses] = createSignal('swiper');
|
32 | const [virtualData, setVirtualData] = createSignal(null);
|
33 | const [, setBreakpointChanged] = createSignal(false);
|
34 |
|
35 |
|
36 | let initializedRef = false;
|
37 | let swiperElRef = null;
|
38 | let swiperRef = null;
|
39 | let oldPassedParamsRef = null;
|
40 | let oldSlides = null;
|
41 |
|
42 | let nextElRef = null;
|
43 | let prevElRef = null;
|
44 | let paginationElRef = null;
|
45 | let scrollbarElRef = null;
|
46 |
|
47 | const [local, rest] = splitProps(props, [
|
48 | 'children',
|
49 | 'class',
|
50 | 'onSwiper',
|
51 | 'ref',
|
52 | 'tag',
|
53 | 'wrapperTag',
|
54 | ]);
|
55 |
|
56 | const params = createMemo(() => getParams(rest));
|
57 |
|
58 | const slidesSlots = children(() => getChildren(local.children));
|
59 |
|
60 | const onBeforeBreakpoint = () => {
|
61 | setBreakpointChanged((state) => !state);
|
62 | };
|
63 |
|
64 | Object.assign(params().params.on, {
|
65 | _containerClasses(swiper, classes) {
|
66 | setContainerClasses(classes);
|
67 | },
|
68 | });
|
69 |
|
70 | const initSwiper = () => {
|
71 |
|
72 | Object.assign(params().params.on, params().events);
|
73 | eventsAssigned = true;
|
74 | swiperRef = new SwiperCore(params().params);
|
75 | swiperRef.loopCreate = () => {};
|
76 | swiperRef.loopDestroy = () => {};
|
77 | if (params().params.loop) {
|
78 | swiperRef.loopedSlides = calcLoopedSlides(slidesSlots().slides, params().params);
|
79 | }
|
80 | if (swiperRef.virtual && swiperRef.params.virtual.enabled) {
|
81 | swiperRef.virtual.slides = slidesSlots().slides;
|
82 | const extendWith = {
|
83 | cache: false,
|
84 | slides: slidesSlots().slides,
|
85 | renderExternal: (data) => {
|
86 | setVirtualData(data);
|
87 | },
|
88 | renderExternalUpdate: true,
|
89 | };
|
90 | extend(swiperRef.params.virtual, extendWith);
|
91 | extend(swiperRef.originalParams.virtual, extendWith);
|
92 | }
|
93 | };
|
94 |
|
95 | if (!swiperElRef) {
|
96 | initSwiper();
|
97 | }
|
98 |
|
99 |
|
100 | if (swiperRef) {
|
101 | swiperRef.on('_beforeBreakpoint', onBeforeBreakpoint);
|
102 | }
|
103 |
|
104 | const attachEvents = () => {
|
105 | if (eventsAssigned || !params().events || !swiperRef) return;
|
106 | Object.keys(params().events).forEach((eventName) => {
|
107 | swiperRef.on(eventName, params().events[eventName]);
|
108 | });
|
109 | };
|
110 |
|
111 | const detachEvents = () => {
|
112 | if (!params().events || !swiperRef) return;
|
113 | Object.keys(params().events).forEach((eventName) => {
|
114 | swiperRef.off(eventName, params().events[eventName]);
|
115 | });
|
116 | };
|
117 |
|
118 | onCleanup(() => {
|
119 | if (swiperRef) swiperRef.off('_beforeBreakpoint', onBeforeBreakpoint);
|
120 | });
|
121 |
|
122 |
|
123 | createEffect(() => {
|
124 | if (!initializedRef && swiperRef) {
|
125 | swiperRef.emitSlidesClasses();
|
126 | initializedRef = true;
|
127 | }
|
128 | });
|
129 |
|
130 |
|
131 | onMount(() => {
|
132 | if (local.ref) {
|
133 | if (typeof local.ref === 'function') {
|
134 | local.ref(swiperElRef);
|
135 | } else {
|
136 | local.ref = swiperElRef;
|
137 | }
|
138 | }
|
139 | if (!swiperElRef) return;
|
140 | if (swiperRef.destroyed) {
|
141 | initSwiper();
|
142 | }
|
143 |
|
144 | mountSwiper(
|
145 | {
|
146 | el: swiperElRef,
|
147 | nextEl: nextElRef,
|
148 | prevEl: prevElRef,
|
149 | paginationEl: paginationElRef,
|
150 | scrollbarEl: scrollbarElRef,
|
151 | swiper: swiperRef,
|
152 | },
|
153 | params().params,
|
154 | );
|
155 |
|
156 | if (local.onSwiper) local.onSwiper(swiperRef);
|
157 | });
|
158 |
|
159 | onCleanup(() => {
|
160 | if (swiperRef && !swiperRef.destroyed) {
|
161 | swiperRef.destroy(true, false);
|
162 | }
|
163 | });
|
164 |
|
165 |
|
166 | createEffect(() => {
|
167 | attachEvents();
|
168 | const { passedParams } = params();
|
169 | const changedParams = getChangedParams(
|
170 | passedParams,
|
171 | oldPassedParamsRef,
|
172 | slidesSlots().slides,
|
173 | oldSlides,
|
174 | (c) => c.key,
|
175 | );
|
176 | oldPassedParamsRef = passedParams;
|
177 | oldSlides = slidesSlots().slides;
|
178 | if (changedParams.length && swiperRef && !swiperRef.destroyed) {
|
179 | updateSwiper({
|
180 | swiper: swiperRef,
|
181 | slides: slidesSlots().slides,
|
182 | passedParams,
|
183 | changedParams,
|
184 | nextEl: nextElRef,
|
185 | prevEl: prevElRef,
|
186 | scrollbarEl: scrollbarElRef,
|
187 | paginationEl: paginationElRef,
|
188 | });
|
189 | }
|
190 | onCleanup(detachEvents);
|
191 | });
|
192 |
|
193 |
|
194 | createEffect(() => {
|
195 | updateOnVirtualData(swiperRef);
|
196 | setTimeout(() => {
|
197 | updateOnVirtualData(swiperRef);
|
198 | });
|
199 | });
|
200 |
|
201 |
|
202 | function renderSlides() {
|
203 | if (params().params.virtual) {
|
204 | return renderVirtual(swiperRef, slidesSlots().slides, virtualData());
|
205 | }
|
206 | if (!params().params.loop || (swiperRef && swiperRef.destroyed)) {
|
207 | return slidesSlots().slides;
|
208 | }
|
209 | return renderLoop(swiperRef, slidesSlots().slides, params().params);
|
210 | }
|
211 |
|
212 |
|
213 |
|
214 |
|
215 | return (
|
216 | <div
|
217 | ref={swiperElRef}
|
218 | class={uniqueClasses(`${containerClasses()}${local.class ? ` ${local.class}` : ''}`)}
|
219 | {...params().rest}
|
220 | >
|
221 | <SwiperContext.Provider value={swiperRef}>
|
222 | {slidesSlots().slots['container-start']}
|
223 |
|
224 | <div class="swiper-wrapper">
|
225 | {slidesSlots().slots['wrapper-start']}
|
226 | {renderSlides()}
|
227 | {slidesSlots().slots['wrapper-end']}
|
228 | </div>
|
229 |
|
230 | <Show when={needsNavigation(params().params)}>
|
231 | <div ref={prevElRef} class="swiper-button-prev" />
|
232 | <div ref={nextElRef} class="swiper-button-next" />
|
233 | </Show>
|
234 | <Show when={needsScrollbar(params().params)}>
|
235 | <div ref={scrollbarElRef} class="swiper-scrollbar" />
|
236 | </Show>
|
237 | <Show when={needsPagination(params().params)}>
|
238 | <div ref={paginationElRef} class="swiper-pagination" />
|
239 | </Show>
|
240 |
|
241 | {slidesSlots().slots['container-end']}
|
242 | </SwiperContext.Provider>
|
243 | </div>
|
244 | );
|
245 | };
|
246 |
|
247 | export { Swiper };
|