Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
0a9bcdb
v2: carousel class
thejackshelton-kunaico Nov 23, 2025
782a450
feat: working carousel with classes
thejackshelton-kunaico Nov 23, 2025
c38e96e
remove deprecated fns
thejackshelton-kunaico Nov 24, 2025
1bcfabb
refactor: remove unused comments
thejackshelton-kunaico Nov 24, 2025
00963a3
feat: simpler serializer call
thejackshelton-kunaico Nov 24, 2025
67e418a
feat: all carousel tests passing
thejackshelton-kunaico Nov 24, 2025
7e30bfc
feat: use qresume instead of hack
thejackshelton-kunaico Nov 24, 2025
bfebd3d
faster
thejackshelton-kunaico Nov 24, 2025
68d3cdd
fix: format
thejackshelton-kunaico Nov 24, 2025
72a20d1
swipe detection script
thejackshelton-kunaico Nov 24, 2025
1a8ec94
feat: implement swipe detection script
thejackshelton-kunaico Nov 24, 2025
d1e959e
feat: implement swipe detection script
thejackshelton-kunaico Nov 24, 2025
150835b
visible task :/
thejackshelton-kunaico Nov 24, 2025
0785cbe
feat: improved prevent
thejackshelton-kunaico Nov 24, 2025
9e074c0
improve perf
thejackshelton-kunaico Nov 24, 2025
af91bdf
back to old
thejackshelton-kunaico Nov 24, 2025
19a7225
feat: pre-warm on dev mode
thejackshelton-kunaico Nov 24, 2025
fb7b873
fix: format
thejackshelton-kunaico Nov 24, 2025
8c5d53f
fix: checkbox flaky test
thejackshelton-kunaico Nov 24, 2025
e0e5009
feat: latest deps
thejackshelton-kunaico Dec 1, 2025
a4a4650
feat: all tests passing
thejackshelton-kunaico Dec 1, 2025
4a7aacf
feat: improved gaps
thejackshelton-kunaico Dec 2, 2025
9ec9b5d
feat: simpler gap handling
thejackshelton-kunaico Dec 2, 2025
6ac8778
feat: better gap dx
thejackshelton-kunaico Dec 2, 2025
c232141
feat: better gap handling
thejackshelton-kunaico Dec 2, 2025
283f8af
remove gap api
thejackshelton-kunaico Dec 2, 2025
22beafa
feat: better scroll markers
thejackshelton-kunaico Dec 2, 2025
a8036c4
feat: no more scroll markers
thejackshelton-kunaico Dec 2, 2025
8bfeae0
feat: math js class
thejackshelton-kunaico Dec 3, 2025
1cc035a
feat: expoential decay slowdown
thejackshelton-kunaico Dec 3, 2025
895b003
better
thejackshelton-kunaico Dec 3, 2025
0790c73
feat: best snapping
thejackshelton-kunaico Dec 3, 2025
0304455
feat: better perf
thejackshelton-kunaico Dec 3, 2025
a7ca463
more optimizations
thejackshelton-kunaico Dec 3, 2025
c88a4a6
further optimizations
thejackshelton-kunaico Dec 3, 2025
bbaaf74
feat: better way to handle preventDefault
thejackshelton-kunaico Dec 4, 2025
cc5664b
feat: infinite scroll
thejackshelton-kunaico Dec 4, 2025
2ab92e4
feat: use waapi
thejackshelton-kunaico Dec 4, 2025
1a5aa66
feat: working infinite scroll
thejackshelton-kunaico Dec 4, 2025
2638de3
simpler
thejackshelton-kunaico Dec 4, 2025
9f1609a
feat: momentum is back
thejackshelton-kunaico Dec 4, 2025
ee8290b
feat: improved tests
thejackshelton-kunaico Dec 4, 2025
7b1e7f7
feat: support windows
thejackshelton Dec 5, 2025
d991f8b
feat: support windoiws
thejackshelton Dec 5, 2025
2c61b41
feat: get separation
thejackshelton Dec 5, 2025
ccec7eb
fix: loops
thejackshelton Dec 5, 2025
d67d518
bit more readable
thejackshelton Dec 6, 2025
94a65e2
remove dead code
thejackshelton Dec 6, 2025
a56df3c
refactor: better naming
thejackshelton Dec 6, 2025
6aed791
fix: only reset interaction state events when mouse
thejackshelton Dec 6, 2025
0567247
refactor: remove unused guard
thejackshelton Dec 6, 2025
792edbe
refactor: remove duplicate check
thejackshelton Dec 6, 2025
69bb8bb
refactor: less duplicate assignments
thejackshelton Dec 6, 2025
fbaa8ae
remove dead code
thejackshelton Dec 6, 2025
eef5e92
remove redundant disable call
thejackshelton Dec 6, 2025
c44b952
feat: improve infinite scroll perf
thejackshelton Dec 6, 2025
4d239e8
feat: improve animateToItem perf
thejackshelton Dec 6, 2025
a0b15bb
fix: item jumping
thejackshelton Dec 6, 2025
70b0981
feat: less duplication
thejackshelton Dec 6, 2025
27e99f2
feat: waapi migration
thejackshelton Dec 7, 2025
91e1540
feat: better dragging in non loop
thejackshelton Dec 7, 2025
7e55516
fix: accurate dragging in non-loop
thejackshelton Dec 7, 2025
906a754
feat: working again
thejackshelton Dec 7, 2025
8e27896
feat: working across
thejackshelton Dec 7, 2025
5c15fe2
feat: support mobile infinite scroll
thejackshelton Dec 7, 2025
cf5eca6
feat: simpler
thejackshelton Dec 7, 2025
d1ee55a
feat: consistent momentum
thejackshelton Dec 7, 2025
5448131
raw content plugin
thejackshelton Dec 9, 2025
0fabd49
remove output txt
thejackshelton Dec 9, 2025
3938a32
new minification plugin
thejackshelton Dec 9, 2025
2f49efe
feat: successful extraction
thejackshelton Dec 9, 2025
cf29b99
feat: working latest
thejackshelton Dec 9, 2025
a324ca0
feat: simpler
thejackshelton Dec 9, 2025
5d29cc3
feat: improved minify plugin
thejackshelton Dec 9, 2025
2d14258
feat: remove need for qds transform
thejackshelton Dec 10, 2025
ee3362d
fix: barrel files
thejackshelton Dec 10, 2025
fc442ea
update w/ vite
thejackshelton Dec 10, 2025
53ce5e9
transformer
thejackshelton Dec 10, 2025
4c1e0e2
fix: handles navigation
thejackshelton Dec 10, 2025
9c91e42
remove log
thejackshelton Dec 10, 2025
4191f39
feat: view handle script
thejackshelton Dec 10, 2025
592ef9e
feat: items per view script
thejackshelton Dec 10, 2025
ef0117a
feat: simpler
thejackshelton Dec 11, 2025
543b886
feat: get server info already
thejackshelton Dec 11, 2025
ff7b667
fix: improved dom handling
thejackshelton Dec 11, 2025
c2c0aa2
feat: faster
thejackshelton Dec 11, 2025
5670ccf
simpler
thejackshelton Dec 11, 2025
3fdd182
feat: very efficient
thejackshelton Dec 11, 2025
dde58f4
feat: very efficient
thejackshelton Dec 11, 2025
a5e8689
cache
thejackshelton Dec 11, 2025
2300ff8
feat: handles it now
thejackshelton Dec 11, 2025
9473ed1
better cache ratio
thejackshelton Dec 11, 2025
e368bac
fix: ci
thejackshelton Dec 11, 2025
9c8dcac
fix: csr items showing
thejackshelton Dec 12, 2025
15ab6fb
feat: works with csr
thejackshelton Dec 13, 2025
c394391
feat: CSR works
thejackshelton Dec 13, 2025
55e270a
feat: correct behavior with csr
thejackshelton Dec 13, 2025
4519cb0
feat: script works in ssr and csr
thejackshelton Dec 13, 2025
a6f42a3
proper cleanup
thejackshelton Dec 13, 2025
76cc827
visibility handles looping
thejackshelton Dec 13, 2025
167062a
gets current items on csr
thejackshelton Dec 13, 2025
3312f34
fix: bad test
thejackshelton Dec 13, 2025
2c03d21
all tests passing
thejackshelton Dec 13, 2025
b15f34e
feat: null check for parsed transition
thejackshelton Dec 13, 2025
55b604a
all tests pass
thejackshelton Dec 13, 2025
a328d88
fix: format
thejackshelton Dec 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cursor/worktrees.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"setup-worktree": ["npm install"]
}
861 changes: 861 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
"@qds.dev/tools": "workspace:*",
"@qds.dev/ui": "workspace:*",
"@qds.dev/utils": "workspace:*",
"@qwik.dev/core": "https://pkg.pr.new/QwikDev/qwik/@qwik.dev/core@8144",
"@qwik.dev/router": "https://pkg.pr.new/QwikDev/qwik/@qwik.dev/router@8144",
"@qwik.dev/core": "2.0.0-beta.15",
"@qwik.dev/router": "2.0.0-beta.15",
"@qwikest/icons": "^0.0.13",
"@tailwindcss/vite": "^4.1.3",
"@types/estree-jsx": "1.0.5",
Expand Down
88 changes: 63 additions & 25 deletions docs/src/routes/components/carousel/examples/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,75 @@ export default component$(() => {
const colors = ["red", "green", "blue", "yellow", "purple", "orange", "pink"];

const selectedSlide = useSignal("yellow");
// const isRendered = useSignal(false);
const isRendered = useSignal(false);

return (
<Carousel.Root
class="carousel-root"
autoplayInterval={1000}
bind:value={selectedSlide}
>
<Carousel.PrevTrigger>Prev</Carousel.PrevTrigger>
<Carousel.NextTrigger>Next</Carousel.NextTrigger>
<div class="border border-red-500">
<Carousel.ScrollArea class="h-40">
<>
<button type="button" onClick$={() => (isRendered.value = true)}>
Render
</button>

{isRendered.value && (
<Carousel.Root class="carousel-root" autoplayInterval={1000} loop move="view">
<Carousel.PrevTrigger>Prev</Carousel.PrevTrigger>
<Carousel.NextTrigger>Next</Carousel.NextTrigger>
<div class="border border-red-500">
<Carousel.ScrollArea class="h-40 gap-4">
{colors.map((color) => (
<Carousel.Item
value={color}
key={color}
class="bg-red-50 h-20 border-4 border-red-500 w-[31.75%]"
>
{color}
</Carousel.Item>
))}
</Carousel.ScrollArea>
</div>

<Carousel.NavList>
{colors.map((color) => (
<Carousel.NavTrigger key={color}>{color}</Carousel.NavTrigger>
))}
</Carousel.NavList>

<p>Selected slide: {selectedSlide.value}</p>

<button onClick$={() => (selectedSlide.value = "green")}>Set to green</button>

<Carousel.PlayTrigger>Autoplay</Carousel.PlayTrigger>
</Carousel.Root>
)}

<Carousel.Root class="carousel-root" autoplayInterval={1000} loop move="view">
<Carousel.PrevTrigger>Prev</Carousel.PrevTrigger>
<Carousel.NextTrigger>Next</Carousel.NextTrigger>
<div class="border border-red-500">
<Carousel.ScrollArea class="h-40 gap-4">
{colors.map((color) => (
<Carousel.Item
value={color}
key={color}
class="bg-red-50 h-20 border-4 border-red-500 w-[31.75%]"
>
{color}
</Carousel.Item>
))}
</Carousel.ScrollArea>
</div>

<Carousel.NavList>
{colors.map((color) => (
<Carousel.Item value={color} key={color} class="carousel-item h-20">
{color}
</Carousel.Item>
<Carousel.NavTrigger key={color}>{color}</Carousel.NavTrigger>
))}
</Carousel.ScrollArea>
</div>

<Carousel.NavList>
{colors.map((color) => (
<Carousel.NavTrigger key={color}>{color}</Carousel.NavTrigger>
))}
</Carousel.NavList>
</Carousel.NavList>

<p>Selected slide: {selectedSlide.value}</p>
<p>Selected slide: {selectedSlide.value}</p>

<button onClick$={() => (selectedSlide.value = "green")}>Set to green</button>
<button onClick$={() => (selectedSlide.value = "green")}>Set to green</button>

<Carousel.PlayTrigger>Autoplay</Carousel.PlayTrigger>
</Carousel.Root>
<Carousel.PlayTrigger>Autoplay</Carousel.PlayTrigger>
</Carousel.Root>
</>
);
});
3 changes: 3 additions & 0 deletions docs/src/routes/components/carousel/index.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import Basic from "./examples/basic";
import { Link } from "@qwik.dev/router"

# Carousel

<Link class="size-4" href="/components/checkbox">Go to checkbox</Link>

<Basic />
3 changes: 3 additions & 0 deletions docs/src/routes/components/checkbox/index.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import api from "./code-notate/api.json";
import Template, { config } from "./template";
import { Link } from "@qwik.dev/router";

# Checkbox

<Link class="size-4" href="/components/carousel">Go to carousel</Link>

<Subtitle>A clickable input that lets users make binary choices or select multiple options.</Subtitle>

<Playground template={Template} config={config} />
Expand Down
8 changes: 4 additions & 4 deletions docs/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { resolve } from "node:path";
import { qdsTransformPlugin } from "@qds.dev/tools/rolldown";
import { asChild, icons } from "@qds.dev/tools/vite";
import { asChild, icons, minifyContentPlugin } from "@qds.dev/tools/vite";
import { qwikVite } from "@qwik.dev/core/optimizer";
import { qwikRouter } from "@qwik.dev/router/vite";
import tailwindcss from "@tailwindcss/vite";
Expand Down Expand Up @@ -36,8 +35,9 @@ export default defineConfig((): UserConfig => {
plugins: [
asChild(),
icons(),
// This plugin handles transforms for our lib author DX. We add it here so it runs in the docs dev mode as well.
qdsTransformPlugin(),
minifyContentPlugin({
outputDir: resolve(__dirname, "../libs/components")
}),
tailwindcss(),
qwikRouter({
mdx: {
Expand Down
13 changes: 11 additions & 2 deletions libs/components/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
/// <reference types="@qwik.dev/core" />

// CSS inline imports
declare module "*.css?inline" {
declare module "*?raw" {
const content: string;
export default content;
}

declare module "*?minify" {
const content: string;
export default content;
}

declare module "*.css?inline" {
const list: string;
export default list;
}
4 changes: 4 additions & 0 deletions libs/components/injected-scripts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const INJECTED_SCRIPTS = {
"view-navigation":
'(()=>{let e=document.currentScript,t=e?.closest(`[ui-qds-carousel-root]`);if(!t||!(t instanceof HTMLElement)||t.dataset.measured)return;t.dataset.measured=`1`;let n=t.id||e?.getAttribute(`ui-scope-id`)||`default`,r=window.carouselState||={};r[n]||={};let i=n=>e?.getAttribute(n)??t.getAttribute(n),a=(n=>e?.hasAttribute(n)??t.hasAttribute(n))(`ui-loop`),o=(e,t)=>{if(e.right<=t.left||e.left>=t.right||e.bottom<=t.top||e.top>=t.bottom)return!1;let n=Math.min(t.right,e.right)-Math.max(t.left,e.left),r=Math.min(t.bottom,e.bottom)-Math.max(t.top,e.top);return n>0&&r>0&&n*r/(e.width*e.height)>=.5},s=globalThis._qdsCache||=new Map,c=e=>{let n=t.querySelector(`[ui-qds-carousel-item]`),r=parseFloat(getComputedStyle(n||t).width)||0,i=parseFloat(getComputedStyle(t).gap)||0,a=`${Math.round(e.width)}|${devicePixelRatio}|${Math.round(r+i)}`;if(s.has(a))return s.get(a);let c=new Set,{width:l,height:u,left:d,top:f}=e;for(let e of[.2,.5,.8])for(let n of[.1,.3,.5,.7,.9]){let r=d+l*n,i=f+u*e;if(r<0||i<0||r>innerWidth||i>innerHeight)continue;let a=document.elementsFromPoint(r,i).find(e=>e.closest(`[ui-qds-carousel-item]`)?.closest(`[ui-qds-carousel-root]`)===t);a&&c.add(a.closest(`[ui-qds-carousel-item]`))}for(let t of c){let n=t.previousElementSibling;for(;n?.hasAttribute(`ui-qds-carousel-item`)&&o(n.getBoundingClientRect(),e);)c.add(n),n=n.previousElementSibling;for(n=t.nextElementSibling;n?.hasAttribute(`ui-qds-carousel-item`)&&o(n.getBoundingClientRect(),e);)c.add(n),n=n.nextElementSibling}for(let e of c)e.setAttribute(`ui-current`,``),e.removeAttribute(`inert`);return s.set(a,c.size),c.size},l=e=>{let o=Number(i(`ui-total-items`)||`0`);r[n].itemsVisible=e;let s=`[ui-qds-carousel-item]:nth-child(-n+${e})`;if(t.querySelectorAll(s).forEach(e=>{e.setAttribute(`ui-current`,``),e.removeAttribute(`inert`)}),e>=o&&o>0){t.setAttribute(`ui-all-fit`,``);return}t.removeAttribute(`ui-all-fit`);let c=a?o-1:o-e,l=[];for(let t=0;t<=c;t+=e)l.push(t);l[l.length-1]!==c&&l.push(c);let u=l.map(e=>`[ui-qds-carousel-nav-trigger][data-qds-index="${e}"]`).join(`,`);t.querySelectorAll(u).forEach(e=>e.setAttribute(`ui-visible`,``))},u=()=>{let e=t.getBoundingClientRect();return e.width===0||e.height===0?!1:(l(c(e)),!0)};requestAnimationFrame(()=>{if(u())return;let e=()=>requestAnimationFrame(()=>requestAnimationFrame(u));addEventListener(`load`,e,{once:!0}),document.fonts?.ready.then(e).catch(()=>{}),`requestIdleCallback`in window&&window.requestIdleCallback(e,{timeout:250})})})();'
} as const;
9 changes: 5 additions & 4 deletions libs/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,22 @@
"build.lib": "rolldown -c rolldown.config.ts",
"build.types": "tsc --emitDeclarationOnly --outDir ./lib-types && pnpm run transform.types",
"transform.types": "node ../tools/utils/transform-dts.ts ./src ./lib-types/src",
"generate.styles": "node styles/tailwind/generate.ts"
"generate.styles": "node styles/tailwind/generate.ts",
"dev": "rolldown -c rolldown.config.ts -w"
},
"devDependencies": {
"@fluejs/noscroll": "^1.0.0",
"@qds.dev/utils": "workspace:*",
"@qwik.dev/core": "https://pkg.pr.new/QwikDev/qwik/@qwik.dev/core@8144",
"@qwik.dev/core": "2.0.0-beta.15",
"@qds.dev/tools": "workspace:*",
"@types/node": "24.9.0",
"rolldown": "1.0.0-beta.45",
"typescript": "5.4.5",
"uqr": "^0.1.2",
"vitest-browser-qwik": "0.0.12"
"vitest-browser-qwik": "0.1"
},
"peerDependencies": {
"@qwik.dev/core": ">=https://pkg.pr.new/QwikDev/qwik/@qwik.dev/core@8144"
"@qwik.dev/core": ">=2.0.0-beta.15"
},
"dependencies": {
"@oddbird/css-anchor-positioning": "^0.6"
Expand Down
10 changes: 4 additions & 6 deletions libs/components/rolldown.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
inlineCssPlugin,
qdsTransformPlugin,
qwikRolldown
} from "@qds.dev/tools/rolldown";
import { inlineCssPlugin, qwikRolldown } from "@qds.dev/tools/rolldown";
import { type PackageJson, readPackageJson } from "@qds.dev/tools/utils";
import { qwikRollup } from "@qwik.dev/core/optimizer";
import { defineConfig } from "rolldown";
Expand All @@ -27,12 +23,14 @@ export default defineConfig({
}),
// qwikRollup overrides the default output dir to dist, we need to fix this. qwikRolldown overrides it back to lib.
qwikRolldown(),
qdsTransformPlugin(),
inlineCssPlugin()
],
external: [/^node:.*/, ...excludeAll(dependencies), ...excludeAll(peerDependencies)],
platform: "neutral",
resolve: {
mainFields: ["module", "main"]
},
watch: {
exclude: ["injected-scripts.ts"]
}
});
61 changes: 27 additions & 34 deletions libs/components/src/carousel/carousel-item.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
$,
component$,
isBrowser,
type PropsOf,
Slot,
useComputed$,
Expand Down Expand Up @@ -37,8 +38,31 @@ export const CarouselItem = component$((props: CarouselItemProps) => {
const isVisible = useComputed$(() => {
const currentIdx = context.currentIndex.value;
const start = currentIdx;
const end = start + context.itemsPerView.value;
return index !== undefined && index >= start && index < end;
const itemsPerView = context.itemsPerView.value;
const end = start + itemsPerView;
const total = context.totalItems.value;
const isLoop = context.isLoop.value;

let shouldBeVisible = index !== undefined && index >= start && index < end;

if (!shouldBeVisible && isLoop && total > 0 && index !== undefined) {
if (end > total) {
const wrappedEnd = end % total;
shouldBeVisible = index < wrappedEnd;
}
}

if (isBrowser && context.scrollAreaRef.value) {
if (shouldBeVisible) {
itemRef.value?.setAttribute("ui-current", "");
itemRef.value?.removeAttribute("inert");
} else {
itemRef.value?.removeAttribute("ui-current");
itemRef.value?.setAttribute("inert", "");
}
}

return shouldBeVisible;
});

const isActive = useComputed$(() => {
Expand Down Expand Up @@ -78,7 +102,6 @@ export const CarouselItem = component$((props: CarouselItemProps) => {

return (
<>
<ScrollMarker align="start" index={index} value={itemValue} />
<Render
{...rest}
fallback="div"
Expand All @@ -91,42 +114,12 @@ export const CarouselItem = component$((props: CarouselItemProps) => {
ui-qds-carousel-item
ui-qds-scope
ui-current={isVisible.value ? "" : undefined}
ui-initial-item={context.startValue === itemValue ? "" : undefined}
aria-label={`${index + 1} of ${context.totalItems.value}`}
onFocusIn$={[handleFocusIn$, rest.onFocusIn$]}
>
<Slot />
<ScrollMarker align="center" index={index} value={itemValue} />
</Render>
<ScrollMarker align="end" index={index} value={itemValue} />
</>
);
});

type ScrollMarkerProps = PropsOf<"div"> & {
align: "start" | "center" | "end";
index: number;
value: string;
};

const ScrollMarker = component$((props: ScrollMarkerProps) => {
const context = useContext(carouselContextId);

const { align, index, value, ...rest } = props;

const isVisible = useComputed$(
() =>
context.startValue === value &&
context.currentIndex.value === index &&
context.align.value === align
);

return (
<div
ref={context.scrollStartRef}
ui-qds-scroll-start
hidden={!isVisible.value}
{...{ [`ui-${align}`]: "" }}
{...rest}
/>
);
});
2 changes: 2 additions & 0 deletions libs/components/src/carousel/carousel-nav-trigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ export const CarouselNavTrigger = component$((props: NavTriggerProps) => {
aria-controls={itemId}
ui-current={isActiveNavTrigger.value ? "" : undefined}
ui-qds-scope
ui-qds-carousel-nav-trigger
data-qds-index={index}
aria-selected={isActiveNavTrigger.value}
onClick$={[handleClick$, props.onClick$]}
onFocus$={[handleFocus$, props.onFocus$]}
Expand Down
41 changes: 5 additions & 36 deletions libs/components/src/carousel/carousel-next-trigger.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,15 @@
import {
$,
component$,
PropsOf,
Slot,
useContext,
useSignal,
useTask$
} from "@qwik.dev/core";
import { $, component$, PropsOf, Slot, useContext } from "@qwik.dev/core";
import { Render } from "../render/render";
import { carouselContextId } from "./carousel-root";
import { getNextValue } from "./carousel-utils";

export const CarouselNextTrigger = component$((props: PropsOf<"button">) => {
const context = useContext(carouselContextId);
const isLastItemInView = useSignal(false);
const initialLoad = useSignal(true);

useTask$(({ track }) => {
track(() => context.currentValue.value);

if (initialLoad.value) return;

const validValues = context.validValues.value;
const currentValue = context.currentValue.value;
isLastItemInView.value = validValues.indexOf(currentValue) === validValues.length - 1;
});

useTask$(() => {
initialLoad.value = false;
});

const handleClick$ = $(() => {
const validValues = context.validValues.value;
const currentValue = context.currentValue.value;
const currentPosition = validValues.indexOf(currentValue);

if (currentPosition === validValues.length - 1 && context.isRewind.value) {
context.currentValue.value = validValues[0];
} else {
const nextPosition = Math.min(currentPosition + 1, validValues.length - 1);
context.currentValue.value = validValues[nextPosition];
const nextValue = getNextValue(context);
if (nextValue !== undefined) {
context.currentValue.value = nextValue;
}
});

Expand All @@ -47,8 +18,6 @@ export const CarouselNextTrigger = component$((props: PropsOf<"button">) => {
{...props}
fallback="button"
internalRef={context.nextButtonRef}
aria-disabled={isLastItemInView.value && !context.isRewind.value}
ui-disabled={isLastItemInView.value && !context.isRewind.value}
ui-qds-scope
onClick$={[handleClick$, props.onClick$]}
ui-qds-carousel-next-trigger
Expand Down
Loading
Loading