-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e563fd4
commit e20ddab
Showing
4 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React, { ReactNode } from "react"; | ||
import Slider from "./component.tsx"; | ||
|
||
export default { | ||
title: "Components/Slider-Old", | ||
component: Slider, | ||
parameters: { | ||
layout: "fullscreen", | ||
}, | ||
tags: ["autodocs"], | ||
}; | ||
|
||
const Slide = ({ children }: { children: ReactNode }) => ( | ||
<div className="h-full p-24 bg-white rounded"> | ||
<p className="ui-text-p2 text-center">{children}</p> | ||
</div> | ||
); | ||
|
||
const slides = [ | ||
<Slide key="1"> | ||
Powers live chat, updates, analytics, and composition for millions of users. | ||
</Slide>, | ||
<Slide key="2"> | ||
Powers virtual venues for millions of event attendees around the world. | ||
</Slide>, | ||
<Slide key="3"> | ||
Provides 5 million daily users with live financial commentary and stock | ||
tickers. | ||
</Slide>, | ||
<Slide key="4">Monitors live car performance data across the USA.</Slide>, | ||
]; | ||
|
||
export const SliderOnAllBreakpoints = { | ||
args: { | ||
slides, | ||
}, | ||
}; | ||
|
||
export const SliderOnSmallBreakpointOnly = { | ||
args: { | ||
slides, | ||
classes: `sm:grid-cols-${slides.length / 2} md:grid-cols-${slides.length}`, | ||
mqEnableThreshold: () => !window.matchMedia("(min-width: 48rem)").matches, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.ui-slider-marker { | ||
font-size: 0.5rem; | ||
top: -1px; | ||
|
||
@apply leading-none px-4 relative; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import "./component.css"; | ||
|
||
import throttle from "lodash.throttle"; | ||
|
||
import { queryId, queryIdAll } from "../dom-query"; | ||
|
||
const mdBreakpoint = () => window.matchMedia("(min-width: 48rem)").matches; | ||
const DRAG_BUFFER = 20; | ||
|
||
const init = (slidesContainer) => { | ||
const transformContainer = queryId("slider-strip", slidesContainer); | ||
const slides = Array.from(queryIdAll("slider-slide", slidesContainer)); | ||
const slideLeftChevron = queryId("slider-previous", slidesContainer); | ||
const slideRightChevron = queryId("slider-next", slidesContainer); | ||
const slideMarkers = Array.from(queryIdAll("slider-marker", slidesContainer)); | ||
const sliderControls = queryId("slider-controls", slidesContainer); | ||
|
||
sliderControls.classList.replace("hidden", "flex"); | ||
const slidesLength = slides.length; | ||
|
||
const slidesWidth = slidesContainer.getBoundingClientRect().width; | ||
const { width: slideWidth, left: slideLeftDistance } = | ||
slides[0].getBoundingClientRect(); | ||
const { left: slideLeftDistanceSecond } = slides[1].getBoundingClientRect(); | ||
const slideGap = slideLeftDistanceSecond - slideLeftDistance - slideWidth; | ||
const adjustment = (slidesWidth - slideWidth) / 2; | ||
|
||
let currentIndex = 0; | ||
let touchStartX = 0; | ||
|
||
const calculateTransform = (index) => | ||
index * -slideWidth + adjustment + index * -slideGap; | ||
|
||
const updateSlide = (index) => | ||
(transformContainer.style.transform = `translateX(${calculateTransform( | ||
index | ||
)}px)`); | ||
|
||
const updateMarkers = (index) => { | ||
slideMarkers.forEach((marker) => | ||
marker.classList.remove("text-active-orange") | ||
); | ||
slideMarkers[index].classList.remove("text-cool-black"); | ||
slideMarkers[index].classList.add("text-active-orange"); | ||
}; | ||
|
||
const slideLeft = () => { | ||
currentIndex = currentIndex - 1 <= 0 ? 0 : currentIndex - 1; | ||
updateSlide(currentIndex); | ||
updateMarkers(currentIndex); | ||
}; | ||
|
||
const slideRight = () => { | ||
currentIndex = | ||
currentIndex + 1 >= slidesLength ? currentIndex : currentIndex + 1; | ||
updateSlide(currentIndex); | ||
updateMarkers(currentIndex); | ||
}; | ||
|
||
updateSlide(0); | ||
updateMarkers(0); | ||
|
||
slideLeftChevron.addEventListener("click", slideLeft); | ||
|
||
transformContainer.addEventListener("touchstart", (e) => { | ||
touchStartX = e.touches[0]?.clientX; | ||
}); | ||
|
||
transformContainer.addEventListener("touchend", (e) => { | ||
const distance = e.changedTouches[0]?.clientX - touchStartX; | ||
|
||
// Prevent sliding on clicks | ||
if (Math.abs(distance) < DRAG_BUFFER) return; | ||
|
||
const direction = distance > 0 ? slideLeft : slideRight; | ||
direction(); | ||
}); | ||
|
||
slideRightChevron.addEventListener("click", slideRight); | ||
|
||
return () => { | ||
transformContainer.style.transform = null; | ||
sliderControls.classList.replace("flex", "hidden"); | ||
}; | ||
}; | ||
|
||
const Slider = ({ container, mqEnableThreshold }) => { | ||
if (!container) return; | ||
|
||
const breakpointCheck = mqEnableThreshold || (() => !mdBreakpoint()); | ||
|
||
let unmount = () => {}; | ||
if (breakpointCheck()) unmount = init(container); | ||
|
||
window.addEventListener( | ||
"resize", | ||
throttle(() => { | ||
if (breakpointCheck()) { | ||
unmount = init(container); | ||
} else { | ||
unmount(); | ||
} | ||
}, 100) | ||
); | ||
}; | ||
|
||
export default Slider; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import React, { CSSProperties, ReactNode, useEffect, useRef } from "react"; | ||
|
||
import Icon from "../Icon/component.tsx"; | ||
import SliderScripts from "./component.js"; | ||
import "./component.css"; | ||
|
||
type SliderProps = { | ||
slides?: ReactNode[]; | ||
classes?: string; | ||
slideClasses?: string; | ||
slideMinWidth?: string; | ||
slideMaxWidth?: string; | ||
mqEnableThreshold?: () => boolean; | ||
|
||
container?: HTMLDivElement | null; | ||
}; | ||
|
||
const Slider = ({ | ||
slides = [], | ||
classes = "", | ||
slideClasses = "", | ||
slideMinWidth = "16.875rem", | ||
slideMaxWidth = "1fr", | ||
mqEnableThreshold = () => true, | ||
...props | ||
}: SliderProps) => { | ||
const containerRef = useRef<HTMLDivElement>(null); | ||
|
||
useEffect(() => { | ||
SliderScripts({ | ||
container: containerRef.current, | ||
mqEnableThreshold, | ||
}); | ||
}, []); | ||
|
||
if (slides.length === 0) return; | ||
|
||
return ( | ||
<div | ||
className="w-full overflow-x-hidden" | ||
data-id="slider" | ||
style={ | ||
{ | ||
"--dynamic-grid-columns-count": slides.length, | ||
"--dynamic-grid-column-min-width": slideMinWidth, | ||
"--dynamic-grid-column-max-width": slideMaxWidth, | ||
} as CSSProperties | ||
} | ||
ref={containerRef} | ||
> | ||
<ol | ||
className={`grid ui-grid-gap grid-cols-dynamic transform transition-transform ${classes}`} | ||
data-id="slider-strip" | ||
{...props} | ||
> | ||
{slides.map((slide, i) => ( | ||
<li key={i} className={slideClasses} data-id="slider-slide"> | ||
{slide} | ||
</li> | ||
))} | ||
</ol> | ||
|
||
<div | ||
className="justify-center items-center my-24 hidden" | ||
data-id="slider-controls" | ||
> | ||
<button | ||
type="button" | ||
className="p-0 w-24 h-24 flex items-center focus:outline-gui-focus" | ||
data-id="slider-previous" | ||
> | ||
<Icon | ||
name="icon-gui-disclosure-arrow" | ||
size="1.5rem" | ||
color="text-cool-black" | ||
additionalCSS="transform rotate-180" | ||
data-id="meganav-control-mobile-dropdown-menu" | ||
/> | ||
</button> | ||
|
||
<ul className="flex justify-center items-center mx-32 relative h-24"> | ||
{slides.map((_, i) => ( | ||
<li key={i}> | ||
<span | ||
className="ui-slider-marker text-cool-black" | ||
data-id="slider-marker" | ||
> | ||
⬤ | ||
</span>{" "} | ||
{/* ⬤ */} | ||
</li> | ||
))} | ||
</ul> | ||
|
||
<button | ||
type="button" | ||
className="p-0 w-24 h-24 flex items-center focus:outline-gui-focus" | ||
data-id="slider-next" | ||
> | ||
<Icon | ||
name="icon-gui-disclosure-arrow" | ||
size="1.5rem" | ||
color="text-cool-black" | ||
data-id="meganav-control-mobile-dropdown-menu" | ||
/> | ||
</button> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Slider; |