Wisch-Reihe für Handys: Scroll-Snap mit angeschnittener Folgekarte und Zähler

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-01 14:20:43 +00:00
1 parent 822481f2e4
commit 69d006334f
2 files changed
+83

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
import { Children, useEffect, useRef, useState, type ReactNode } from "react";
import "./wisch-reihe.css";
type WischReiheProps = {
/** Beschreibung für Screenreader, z. B. „Vier Leistungen, seitlich wischen“ */
ariaLabel: string;
children: ReactNode;
className?: string;
/** Zähler „2 / 4“ unter der Reihe anzeigen (Standard: ja) */
zaehler?: boolean;
};
/**
* Horizontale Wisch-Reihe für Handys (Spezifikation 9.4): natives Scroll-Snap ohne Bibliothek,
* die nächste Karte ist angeschnitten sichtbar, darunter ein Zähler. Keine automatische Bewegung.
* Ab 900 px entscheidet der Abschnitt selbst, ob er die Reihe überhaupt zeigt.
*/
const WischReihe = ({ ariaLabel, children, className, zaehler = true }: WischReiheProps) => {
const karten = Children.toArray(children);
const reiheRef = useRef<HTMLUListElement>(null);
const [aktiv, setAktiv] = useState(0);
useEffect(() => {
const reihe = reiheRef.current;
if (!reihe || typeof IntersectionObserver === "undefined") return;
const beobachter = new IntersectionObserver(
(eintraege) => {
for (const e of eintraege) {
if (e.isIntersecting) setAktiv(Number((e.target as HTMLElement).dataset.index));
}
},
{ root: reihe, threshold: 0.6 },
);
reihe.querySelectorAll<HTMLElement>(":scope > li").forEach((li) => beobachter.observe(li));
return () => beobachter.disconnect();
}, [karten.length]);
return (
<div className={`wk-wisch${className ? ` ${className}` : ""}`}>
<ul ref={reiheRef} className="wk-wisch__reihe" role="list" tabIndex={0} aria-label={ariaLabel}>
{karten.map((karte, i) => (
<li key={i} className="wk-wisch__karte" data-index={i}>
{karte}
</li>
))}
</ul>
{zaehler && karten.length > 1 && (
<p className="wk-wisch__zaehler wk-num" aria-hidden>
{aktiv + 1} / {karten.length}
</p>
)}
</div>
);
};
export default WischReihe;
+27
View File
@@ -0,0 +1,27 @@
/* Wisch-Reihe (Spezifikation 9.4) */
.wk-wisch__reihe {
display: flex;
gap: 12px;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-padding-inline: var(--gutter);
padding-inline: var(--gutter);
padding-bottom: 4px;
overscroll-behavior-x: contain;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
}
.wk-wisch__reihe::-webkit-scrollbar {
display: none;
}
.wk-wisch__karte {
flex: 0 0 80vw;
max-width: 380px;
scroll-snap-align: start;
}
.wk-wisch__zaehler {
margin-top: 0.9rem;
text-align: center;
font-size: var(--fs-small);
color: var(--fg-muted);
}