Skip to content

Commit f1ea4f3

Browse files
feat: migrate the carousel to transforms (#963)
* feat: get custom scroll for mouse and update * refactor: remove drag speed * refactor: add back drag speed * feat: one scroll model * fix: clean up a bit * fix: dumb timeouts * without animateScroll$ * does transform walking * feat: correct drag direction * initial snapping * correct snapping * works with next and prev * add will change transform * custom animations except for initial load * user defined transitions work * fix: resize * mobile sorta works * smoother on mobile * fix: simplify scroller impl * narrowed down problem * mobile working * handle x, y, or z * working in an agnostic way * cleanup markup and props * get initial slide position * refactor: add comment on qvisible * feat: no flicker getting initial slide * teeny flicker but with animations * feat: no more flicker * feat: handle initial slide pos for any orientation * feat: respect transform boundaries * fix: carousel start index * fix: progress * fix: make sure there are no duplicate handler calls * fix: respect boundaries * refactor: make carousel scroller easier to understand * fix: remove the viewport from the equation * fix: smoother swiping experience * feat: sensitivity * feat: initial move impl * fix: only calculate pos when it's not the start * feat: renders correct bullets based on slides per view * feat: proper bullet navigation * feat: bullets are smart enough to know if something is in range * feat: prev and next buttons both work with move * fix: state tests * feat: initial vertical * fix: offset for vertical version * feat: vertical with transform * fix: touch start moves according to touchY in vertical * refactor: better naming * refactor: code more easy to understand * refactored names * refactor: use props map instead * fix: initial slide position vertically * fix: don't render marker points with non-scroller carousels * feat: start docs * fix: text align * docs: add example animation * feat: upgrade carousel to beta * fix: the merge issues
1 parent f59e183 commit f1ea4f3

File tree

24 files changed

+1146
-635
lines changed

24 files changed

+1146
-635
lines changed

apps/website/src/_state/component-statuses.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const statusByComponent: ComponentKitsStatuses = {
3838
},
3939
headless: {
4040
Accordion: ComponentStatus.Beta,
41-
Carousel: ComponentStatus.Draft,
41+
Carousel: ComponentStatus.Beta,
4242
Collapsible: ComponentStatus.Beta,
4343
Combobox: ComponentStatus.Beta,
4444
Checkbox: ComponentStatus.Draft,

apps/website/src/components/feature-list/feature-list.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const FeatureList = component$((props: FeatureListProps) => {
6868
{!props.issues && (
6969
<Note>
7070
Missing a feature? Check out the{' '}
71-
<a class="font-bold" href="https://qwikui.com/contributing/">
71+
<a class="font-bold" href="https://qwikui.com/docs/contributing/">
7272
contributing guide
7373
</a>{' '}
7474
and we'd be happy to review any relevant issues or PR's. Feel free to work on

apps/website/src/routes/docs/contributing/index.mdx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -379,20 +379,16 @@ Notice how `<ExampleRoot />` returns a `children` prop. This is because inline c
379379
Context and hooks is still easy to use, create a new component called `<ExampleBase />` and return that instead of the div (with the children passed between) in the example above. From there, you can use context, hooks, and all the other Qwik goodies as a top level component.
380380
381381
```tsx
382-
return (
383-
<ExampleBase>
384-
{props.children}
385-
</ExampleBase>
386-
)
382+
return <ExampleBase>{props.children}</ExampleBase>;
387383

388384
// use hooks, context, and other stuff here!
389385
export const ExampleBase = component$(() => {
390386
return (
391387
<div>
392388
<Slot />
393389
</div>
394-
)
395-
})
390+
);
391+
});
396392
```
397393
398394
## That's it!
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { component$, useStyles$ } from '@builder.io/qwik';
2+
import { Carousel } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
useStyles$(styles);
6+
7+
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
8+
9+
return (
10+
<Carousel.Root class="carousel-root" gap={30}>
11+
<div class="carousel-buttons">
12+
<Carousel.Previous>Prev</Carousel.Previous>
13+
<Carousel.Next>Next</Carousel.Next>
14+
</div>
15+
<Carousel.Scroller class="carousel-scroller carousel-animation">
16+
{colors.map((color) => (
17+
<Carousel.Slide key={color} class="carousel-slide">
18+
{color}
19+
</Carousel.Slide>
20+
))}
21+
</Carousel.Scroller>
22+
</Carousel.Root>
23+
);
24+
});
25+
// internal
26+
import styles from './carousel.css?inline';

apps/website/src/routes/docs/headless/carousel/examples/carousel.css

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
width: 100%;
33
}
44

5-
.carousel-scroller {
6-
margin-bottom: 0.5rem;
7-
}
8-
95
.carousel-slide {
106
border: 2px dotted hsl(var(--primary));
117
min-height: 10rem;
8+
max-height: 10rem;
129
-webkit-user-select: none; /* support for Safari */
1310
user-select: none;
1411
}
@@ -18,13 +15,15 @@
1815
gap: 0.5rem;
1916
padding: 1rem;
2017
border: 2px dotted hsl(var(--foreground));
18+
margin-top: 0.5rem;
2119
}
2220

2321
.carousel-buttons {
2422
display: flex;
2523
justify-content: space-between;
2624
border: 2px dotted hsl(var(--accent));
2725
margin-bottom: 0.5rem;
26+
margin-bottom: 0.5rem;
2827
}
2928

3029
.carousel-buttons button {
@@ -76,6 +75,8 @@
7675
.carousel-stepper {
7776
display: flex;
7877
justify-content: space-between;
78+
margin-bottom: 0.5rem;
79+
flex-wrap: wrap;
7980
}
8081

8182
.carousel-step {
@@ -100,3 +101,7 @@
100101
.carousel-step[data-current]::before {
101102
background-color: hsl(var(--primary));
102103
}
104+
105+
.carousel-animation {
106+
transition: 0.35s transform cubic-bezier(0.57, 0.16, 0.95, 0.67);
107+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { component$, useStyles$ } from '@builder.io/qwik';
2+
import { Carousel } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
useStyles$(styles);
6+
7+
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
8+
9+
useStyles$(`
10+
.carousel-circle {
11+
width: 20px;
12+
height: 20px;
13+
margin: 0 5px;
14+
border-radius: 50%;
15+
background-color: lightgray;
16+
}
17+
18+
.carousel-circle[data-active] {
19+
background-color: lightblue;
20+
}
21+
`);
22+
23+
return (
24+
<>
25+
<Carousel.Root class="carousel-root" gap={30} move={2} slidesPerView={2}>
26+
<div class="carousel-buttons">
27+
<Carousel.Previous>Prev</Carousel.Previous>
28+
<Carousel.Next>Next</Carousel.Next>
29+
</div>
30+
<Carousel.Scroller class="carousel-scroller">
31+
{colors.map((color) => (
32+
<Carousel.Slide key={color} class="carousel-slide">
33+
{color}
34+
</Carousel.Slide>
35+
))}
36+
</Carousel.Scroller>
37+
38+
<Carousel.Pagination
39+
style={{ display: 'flex', justifyContent: 'center', marginTop: '0.5rem' }}
40+
>
41+
{colors.map((_, index) => {
42+
return (
43+
<Carousel.Bullet key={index} class="carousel-circle"></Carousel.Bullet>
44+
);
45+
})}
46+
</Carousel.Pagination>
47+
</Carousel.Root>
48+
</>
49+
);
50+
});
51+
// internal
52+
import styles from './carousel.css?inline';

apps/website/src/routes/docs/headless/carousel/examples/reactive.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default component$(() => {
55
useStyles$(styles);
66

77
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
8-
const selectedIndex = useSignal<number>(0);
8+
const selectedIndex = useSignal<number>(2);
99

1010
return (
1111
<>

apps/website/src/routes/docs/headless/carousel/examples/loop.tsx renamed to apps/website/src/routes/docs/headless/carousel/examples/rewind.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default component$(() => {
77
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
88

99
return (
10-
<Carousel.Root class="carousel-root" gap={30} loop>
10+
<Carousel.Root class="carousel-root" gap={30} rewind>
1111
<div class="carousel-buttons">
1212
<Carousel.Previous>Prev</Carousel.Previous>
1313
<Carousel.Next>Next</Carousel.Next>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { component$, useStyles$ } from '@builder.io/qwik';
2+
import { Carousel } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
useStyles$(styles);
6+
7+
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
8+
9+
return (
10+
<Carousel.Root
11+
class="carousel-root"
12+
gap={30}
13+
sensitivity={{
14+
mouse: 2.5,
15+
touch: 2.25,
16+
}}
17+
>
18+
<div class="carousel-buttons">
19+
<Carousel.Previous>Prev</Carousel.Previous>
20+
<Carousel.Next>Next</Carousel.Next>
21+
</div>
22+
<Carousel.Scroller class="carousel-scroller">
23+
{colors.map((color) => (
24+
<Carousel.Slide key={color} class="carousel-slide">
25+
{color}
26+
</Carousel.Slide>
27+
))}
28+
</Carousel.Scroller>
29+
</Carousel.Root>
30+
);
31+
});
32+
// internal
33+
import styles from './carousel.css?inline';
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { component$, useStyles$ } from '@builder.io/qwik';
2+
import { Carousel } from '@qwik-ui/headless';
3+
4+
export default component$(() => {
5+
useStyles$(styles);
6+
7+
const colors = ['red', 'green', 'blue', 'yellow', 'purple', 'orange', 'pink'];
8+
9+
return (
10+
<Carousel.Root class="carousel-root" gap={30}>
11+
<div class="carousel-buttons">
12+
<Carousel.Previous>Prev</Carousel.Previous>
13+
<Carousel.Next>Next</Carousel.Next>
14+
</div>
15+
<Carousel.Scroller class="carousel-scroller">
16+
{colors.map((color) => (
17+
<Carousel.Slide
18+
style={{ flexBasis: '300px' }}
19+
key={color}
20+
class="carousel-slide"
21+
>
22+
{color}
23+
</Carousel.Slide>
24+
))}
25+
</Carousel.Scroller>
26+
</Carousel.Root>
27+
);
28+
});
29+
// internal
30+
import styles from './carousel.css?inline';

0 commit comments

Comments
 (0)