solidjs-swiper
Version:
A simple image swiper built in Solid-JS
148 lines (145 loc) • 4.17 kB
JavaScript
import { spread, insert, createComponent, use, template } from 'solid-js/web';
import { splitProps, createSignal, createEffect, onMount, For } from 'solid-js';
// src/Swiper.tsx
var _tmpl$ = /* @__PURE__ */ template(`<div class="swiper-container"><div class="swiper-wrapper">`);
var _tmpl$2 = /* @__PURE__ */ template(`<style>
.swiper-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
flex-wrap: nowrap;
overflow: hidden;
}
.swiper-wrapper {
position: relative;
width: 100%;
height: 100%;
flex-shrink: 0;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
flex-wrap: nowrap;
transition: transform 0ms ease-in-out;
transform: translateX(-0px);
}
.swiper-slide {
flex-shrink: 0;
width: 100%;
}
`);
var _tmpl$3 = /* @__PURE__ */ template(`<div class="swiper-slide">`);
function Swiper(attrs) {
const [props, rest] = splitProps(attrs, ["items", "threshold", "index", "onReady", "onChange"]);
const items = () => props?.items || [];
const threshold = () => props?.threshold || 80;
const [activeSlide, setActiveSlide] = createSignal(props?.index || 0);
const state = {
active: false,
start: [0, 0],
end: [0, 0]
};
let wrapperEl;
const itemsEl = {};
const refreshActive = () => {
offset = (itemsEl[0]?.clientWidth || 0) * activeSlide();
setOffset(offset, true);
};
createEffect(() => setActiveSlide(props?.index || 0));
createEffect(() => {
items() && refreshActive();
});
createEffect(() => {
props.onChange?.(activeSlide());
});
let offset = 0;
const setOffset = (value, animated = true) => {
if (wrapperEl?.style) {
wrapperEl.style.transform = `translateX(-${value}px)`;
wrapperEl.style.transitionDuration = animated ? "250ms" : "0ms";
}
};
const prev = () => {
let slide = activeSlide() - 1;
if (slide <= 0) {
setActiveSlide(0);
return false;
}
setActiveSlide(slide);
return true;
};
const next = () => {
let slide = activeSlide() + 1;
let maxSlide = (items()?.length || 1) - 1;
if (slide >= maxSlide) {
setActiveSlide(maxSlide);
return false;
}
setActiveSlide(slide);
return true;
};
onMount(() => {
const api = {
next: () => next(),
prev: () => prev()
};
props?.onReady?.(api);
});
const events = {
onMouseDown: (event) => {
event.preventDefault();
state.active = true;
state.start = [event.clientX, event.clientY];
},
onMouseMove: (event) => {
event.preventDefault();
if (!state.active)
return;
let diff = event.clientX - state.start[0];
let normalOffset = offset;
setOffset(normalOffset + -diff, false);
},
onMouseUp: (event) => {
event.preventDefault();
if (!state.active)
return;
state.end = [event.clientX, event.clientY];
state.active = false;
let diff = event.clientX - state.start[0];
if (diff > threshold()) {
if (prev())
return true;
} else if (diff < -threshold()) {
if (next())
return true;
}
setOffset(offset);
},
onMouseLeave: (event) => {
events.onMouseUp(event);
}
};
return [(() => {
const _el$ = _tmpl$(), _el$2 = _el$.firstChild;
const _ref$ = wrapperEl;
typeof _ref$ === "function" ? use(_ref$, _el$2) : wrapperEl = _el$2;
spread(_el$2, events, false, true);
insert(_el$2, createComponent(For, {
get each() {
return items();
},
children: (item, index) => (() => {
const _el$4 = _tmpl$3();
use((el) => itemsEl[index()] = el, _el$4);
insert(_el$4, () => attrs?.children?.(item, index));
return _el$4;
})()
}));
return _el$;
})(), _tmpl$2()];
}
export { Swiper };