Skip to content

Commit f9b997d

Browse files
authored
feat: add daisy slider component (#199)
* feat(slider): expose style and class to customize the slider component * feat(slider): add Daisy slider * fix(slider): fix null check
1 parent a5a9e33 commit f9b997d

File tree

7 files changed

+176
-31
lines changed

7 files changed

+176
-31
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { component$, useSignal } from '@builder.io/qwik';
2+
import { Slider } from '@qwik-ui/theme-daisy';
3+
4+
export default component$(() => {
5+
const sliderValue = useSignal(55);
6+
7+
return (
8+
<div class="flex flex-col gap-8 mt-4">
9+
<h2>This is the documentation for the Slider</h2>
10+
11+
<div class="flex flex-col gap-8 mt-4">
12+
<div>
13+
<h2>Basic Example</h2>
14+
<div class="panel">
15+
<Slider value={40} max={100} min={20} variant="primary" />
16+
<Slider value={50} max={100} min={20} variant="secondary" />
17+
<Slider value={60} max={100} min={20} variant="accent" />
18+
<Slider value={70} max={100} min={20} variant="success" />
19+
<Slider value={80} max={100} min={20} variant="warning" />
20+
<Slider value={90} max={100} min={20} variant="error" />
21+
</div>
22+
</div>
23+
</div>
24+
<div class="flex flex-col gap-8 mt-4">
25+
<h2>Value: {sliderValue.value}</h2>
26+
<Slider
27+
value={sliderValue.value}
28+
onChange$={(value) => {
29+
sliderValue.value = value;
30+
}}
31+
max={100}
32+
min={0}
33+
variant="accent"
34+
/>
35+
</div>
36+
</div>
37+
);
38+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const daisyConfig = {
2+
variants: {
3+
primary: '--p',
4+
secondary: '--s',
5+
accent: '--a',
6+
success: '--su',
7+
warning: '--wa',
8+
error: '--er',
9+
},
10+
};
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { component$, PropFunction } from '@builder.io/qwik';
2+
import {
3+
Slider as HeadlessSlider,
4+
SliderProgress as HeadlessSliderProgress,
5+
SliderThumb as HeadlessSliderThumb,
6+
} from '@qwik-ui/headless';
7+
import { clsq } from '@qwik-ui/shared';
8+
import { daisyConfig } from './daisy.config';
9+
10+
export type SliderProps = {
11+
variant?: DaisySliderVariants;
12+
value: number;
13+
min: number;
14+
max: number;
15+
onChange$?: PropFunction<(value: number) => void>;
16+
class?: string;
17+
style?: string;
18+
};
19+
20+
export type DaisySliderVariants =
21+
| 'primary'
22+
| 'secondary'
23+
| 'accent'
24+
| 'success'
25+
| 'warning'
26+
| 'error';
27+
28+
export const Slider = component$(
29+
({
30+
variant = 'primary',
31+
class: classNames,
32+
value = 0,
33+
style,
34+
onChange$,
35+
...rest
36+
}: SliderProps) => {
37+
const { variants } = daisyConfig;
38+
39+
return (
40+
<HeadlessSlider
41+
{...rest}
42+
style={`
43+
height: 1.5em;
44+
background-color: transparent;
45+
border: none;
46+
${style ?? ''}
47+
`}
48+
class={clsq('mx-4', classNames)}
49+
value={value}
50+
onChange$={(value) => onChange$?.(value)}
51+
>
52+
<HeadlessSliderProgress
53+
style={`
54+
background-color: hsl(var(${variants[variant]}));
55+
height: 1.5em;
56+
border-radius: 1.5em 0 0 1.5em;
57+
`}
58+
/>
59+
<HeadlessSliderThumb
60+
style={`
61+
border: 3px solid hsl(var(${variants[variant]}));
62+
height: 1.5em;
63+
width: 1.5em;
64+
background-color: hsl(var(--b1));
65+
`}
66+
/>
67+
<div
68+
style={{
69+
position: 'absolute',
70+
top: '50%',
71+
transform: 'translateY(-50%)',
72+
left: '0',
73+
right: '0',
74+
height: '33%',
75+
zIndex: -1,
76+
borderRadius: '1.5em',
77+
backgroundColor: 'hsl(var(--b1))',
78+
}}
79+
/>
80+
</HeadlessSlider>
81+
);
82+
}
83+
);

packages/daisy/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ export * from './components/toast/toast';
1212
export * from './components/toggle/toggle';
1313
export * from './components/tooltip/tooltip';
1414
export * from './components/ratio/radio';
15+
export * from './components/slider/slider';

packages/headless/src/components/slider/slider.tsx

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,19 @@ interface SliderProps {
2828
min: number;
2929
max: number;
3030
onChange$?: PropFunction<(value: number) => void>;
31+
class?: string;
32+
style?: string;
3133
}
3234

3335
export const Slider = component$(
34-
({ value = 0, min = 0, max = 100, onChange$ }: SliderProps) => {
36+
({
37+
value = 0,
38+
min = 0,
39+
max = 100,
40+
onChange$,
41+
style,
42+
class: classNames,
43+
}: SliderProps) => {
3544
const rootPositionRef = useSignal<Element>();
3645
const sliderValue = useSignal(value);
3746
const minSignal = useSignal(min);
@@ -66,15 +75,17 @@ export const Slider = component$(
6675
return (
6776
<div
6877
ref={rootPositionRef}
69-
style={{
70-
display: 'inline-block',
71-
position: 'relative',
72-
border: 'solid 1px rgb(178,178,178)',
73-
borderRadius: '4px',
74-
background: 'rgb(239,239,239)',
75-
width: '100px',
76-
height: '6px',
77-
}}
78+
style={`
79+
display: inline-block;
80+
position: relative;
81+
border: solid 1px rgb(178,178,178);
82+
border-radius: 4px;
83+
background: rgb(239,239,239);
84+
width: 100px;
85+
height: 6px;
86+
${style ?? ''}
87+
`}
88+
class={classNames}
7889
>
7990
<Slot />
8091
</div>

packages/headless/src/components/slider/sliderProgress.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import { component$, Slot, useContext } from '@builder.io/qwik';
22
import { sliderContext } from './slider';
33

4-
export const SliderProgress = component$(() => {
4+
export const SliderProgress = component$(({ style }: { style?: string }) => {
55
const contextService = useContext(sliderContext);
66

77
return (
88
<div
9-
style={{
10-
display: 'block',
11-
position: 'absolute',
12-
top: 0,
13-
height: '100%',
14-
left: 0,
15-
width: `${contextService.percentage.value}%`,
16-
background: 'rgb(0,117,255)',
17-
}}
9+
style={`
10+
display: block;
11+
position: absolute;
12+
top: 0;
13+
height: 100%;
14+
left: 0;
15+
width: ${contextService.percentage.value}%;
16+
background: rgb(0,117,255);
17+
${style ?? ''}
18+
`}
1819
>
1920
<Slot />
2021
</div>

packages/headless/src/components/slider/sliderThumb.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const clamp = (value: number, min: number, max: number) => {
1313
return Math.min(max, Math.max(value, min));
1414
};
1515

16-
export const SliderThumb = component$(() => {
16+
export const SliderThumb = component$(({ style }: { style?: string }) => {
1717
const mouseDownHappenedSignal = useSignal(false);
1818
const contextService = useContext(sliderContext);
1919

@@ -57,16 +57,17 @@ export const SliderThumb = component$(() => {
5757

5858
return (
5959
<div
60-
style={{
61-
width: '20px',
62-
height: '20px',
63-
borderRadius: '20px',
64-
background: 'rgba(0, 0, 250)',
65-
position: 'absolute',
66-
transform: 'translateX(-50%) translateY(-50%)',
67-
top: '50%',
68-
left: `${contextService.percentage.value}%`,
69-
}}
60+
style={`
61+
width: 20px;
62+
height: 20px;
63+
border-radius: 20px;
64+
background: rgba(0, 0, 250);
65+
position: absolute;
66+
transform: translateX(-50%) translateY(-50%);
67+
top: 50%;
68+
left: ${contextService.percentage.value}%;
69+
${style ?? ''}
70+
`}
7071
onMouseDown$={handleMouseDown}
7172
>
7273
<Slot />

0 commit comments

Comments
 (0)