mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: curtains
This commit is contained in:
1 parent
f84f846e76
commit
58e0876aa0
2 files changed
+65
-8
No files matched your search
@@ -3,6 +3,8 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@
|
|||||||
border-radius: var(--max-size);
|
border-radius: var(--max-size);
|
||||||
|
|
||||||
.bar-container {
|
.bar-container {
|
||||||
height: 10px;
|
height: var(--space-3);
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@@ -52,4 +54,30 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.curtain {
|
||||||
|
width: min(25%, var(--space-7));
|
||||||
|
height: calc(100% - var(--space-3) - 2 * var(--space-1));
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
transition: opacity var(--duration-brief);
|
||||||
|
|
||||||
|
&[data-side="left"] {
|
||||||
|
left: 0;
|
||||||
|
background: linear-gradient(90deg, var(--gray-1), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-side="right"] {
|
||||||
|
right: 0;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--gray-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-visible="true"] {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
|||||||
const bar = useRef<HTMLDivElement>(null!);
|
const bar = useRef<HTMLDivElement>(null!);
|
||||||
const container = useRef<HTMLDivElement>(null!);
|
const container = useRef<HTMLDivElement>(null!);
|
||||||
const content = useRef<HTMLDivElement>(null!);
|
const content = useRef<HTMLDivElement>(null!);
|
||||||
|
const curtainLeft = useRef<HTMLDivElement>(null!);
|
||||||
|
const curtainRight = useRef<HTMLDivElement>(null!);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function updateBarSize() {
|
function updateBarSize() {
|
||||||
@@ -19,7 +21,7 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
|||||||
bar.current.style.width = `${(visible / total) * 100}%`;
|
bar.current.style.width = `${(visible / total) * 100}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncBarToScroll() {
|
function syncBar() {
|
||||||
const maxTravel = container.current.clientWidth - bar.current.clientWidth;
|
const maxTravel = container.current.clientWidth - bar.current.clientWidth;
|
||||||
const maxScroll =
|
const maxScroll =
|
||||||
content.current.scrollWidth - content.current.clientWidth;
|
content.current.scrollWidth - content.current.clientWidth;
|
||||||
@@ -33,6 +35,16 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
|||||||
bar.current.style.left = `${ratio * maxTravel}px`;
|
bar.current.style.left = `${ratio * maxTravel}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncCurtains() {
|
||||||
|
const el = content.current;
|
||||||
|
|
||||||
|
const showLeft = el.scrollLeft > 0;
|
||||||
|
const showRight = el.scrollLeft + el.clientWidth < el.scrollWidth;
|
||||||
|
|
||||||
|
curtainLeft.current.dataset.visible = showLeft ? "true" : "false";
|
||||||
|
curtainRight.current.dataset.visible = showRight ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
let lastX = 0;
|
let lastX = 0;
|
||||||
|
|
||||||
function handlePointerDown(event: PointerEvent) {
|
function handlePointerDown(event: PointerEvent) {
|
||||||
@@ -56,7 +68,7 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
|||||||
|
|
||||||
content.current.scrollLeft += delta;
|
content.current.scrollLeft += delta;
|
||||||
|
|
||||||
syncBarToScroll();
|
syncBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePointerUp(event: PointerEvent) {
|
function handlePointerUp(event: PointerEvent) {
|
||||||
@@ -65,17 +77,31 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
|||||||
window.removeEventListener("pointerup", handlePointerUp);
|
window.removeEventListener("pointerup", handlePointerUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleScroll() {
|
||||||
|
syncBar();
|
||||||
|
syncCurtains();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleResize() {
|
||||||
|
updateBarSize();
|
||||||
|
syncBar();
|
||||||
|
syncCurtains();
|
||||||
|
}
|
||||||
|
|
||||||
updateBarSize();
|
updateBarSize();
|
||||||
syncBarToScroll();
|
syncBar();
|
||||||
|
syncCurtains();
|
||||||
|
|
||||||
bar.current.addEventListener("pointerdown", handlePointerDown);
|
bar.current.addEventListener("pointerdown", handlePointerDown);
|
||||||
content.current.addEventListener("scroll", syncBarToScroll);
|
content.current.addEventListener("scroll", syncBar);
|
||||||
window.addEventListener("resize", updateBarSize);
|
window.addEventListener("resize", handleResize);
|
||||||
|
content.current.addEventListener("scroll", handleScroll);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
bar.current.removeEventListener("pointerdown", handlePointerDown);
|
bar.current.removeEventListener("pointerdown", handlePointerDown);
|
||||||
content.current.removeEventListener("scroll", syncBarToScroll);
|
content.current.removeEventListener("scroll", syncBar);
|
||||||
window.removeEventListener("resize", updateBarSize);
|
window.removeEventListener("resize", handleResize);
|
||||||
|
content.current.removeEventListener("scroll", handleScroll);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -90,6 +116,9 @@ export function Scroller({ children, className, ...props }: ScrollerProps) {
|
|||||||
<div className={styles.bar} ref={bar} />
|
<div className={styles.bar} ref={bar} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div ref={curtainLeft} data-side="left" className={styles.curtain} />
|
||||||
|
<div ref={curtainRight} data-side="right" className={styles.curtain} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user