1+ <script setup>
2+ import { computed } from " vue" ;
3+ import BaseIcon from " ./BaseIcon.vue" ;
4+
5+ const props = defineProps ({
6+ min: {
7+ type: Number ,
8+ default: 0
9+ },
10+ max: {
11+ type: Number ,
12+ default: 0
13+ },
14+ inputColor: {
15+ type: String ,
16+ default: ' #1A1A1A'
17+ },
18+ background: {
19+ type: String ,
20+ default: ' #FFFFFF'
21+ },
22+ borderColor: {
23+ type: String ,
24+ default: ' #FFFFFF'
25+ },
26+ selectColor: {
27+ type: String ,
28+ default: ' #4A4A4A'
29+ },
30+ textColor: {
31+ type: String ,
32+ default: ' #1A1A1A'
33+ },
34+ useResetSlot: {
35+ type: Boolean ,
36+ default: false
37+ },
38+ value: {
39+ type: Number ,
40+ default: 0
41+ },
42+ source: {
43+ type: Number ,
44+ default: 0 ,
45+ }
46+ })
47+
48+ const slicerColor = computed (() => props .inputColor );
49+ const backgroundColor = computed (() => props .background );
50+ const selectColorOpaque = computed (() => ` ${ props .selectColor } 33` );
51+ const borderColor = computed (() => props .borderColor );
52+
53+ const emit = defineEmits ([' update:value' , ' reset' ]);
54+
55+ function reset () {
56+ emit (' reset' );
57+ }
58+
59+ const highlightStyle = computed (() => {
60+ const range = props .max - props .min ;
61+ const startPercent = 0 ;
62+ const endPercent = ((props .value - props .min ) / range) * 100 ;
63+ return {
64+ left: ` ${ startPercent} %` ,
65+ width: ` ${ endPercent - startPercent} %` ,
66+ background: props .selectColor
67+ };
68+ });
69+
70+ </script >
71+
72+ <template >
73+ <div data-html2canvas-ignore >
74+ <div v-if =" value !== source" class =" reset-wrapper" >
75+ <button v-if =" !useResetSlot" data-cy-reset tabindex =" 0" role =" button" class =" vue-data-ui-refresh-button"
76+ @click =" reset" >
77+ <BaseIcon name =" refresh" :stroke =" textColor" />
78+ </button >
79+ <slot v-else name =" reset-action" :reset =" reset" />
80+ </div >
81+ <div v-else class =" reset-wrapper" />
82+ <div class =" mono-slicer" >
83+ <div class =" slider-track" ></div >
84+ <div class =" range-highlight" :style =" highlightStyle" ></div >
85+ <input type =" range" :min =" min" :max =" max" :value =" Number(value)" @input =" emit('update:value', Number($event.target.value))" />
86+ </div >
87+ </div >
88+ </template >
89+
90+ <style scoped lang="scss">
91+ .mono-slicer {
92+ position : relative !important ;
93+ width : calc (100% - 48px );
94+ height : 40px ;
95+ margin : 0 auto ;
96+ }
97+
98+ .reset-wrapper {
99+ display : flex ;
100+ flex-direction : row ;
101+ align-items : center ;
102+ justify-content : center ;
103+ padding : 0 24px ;
104+ height : 40px ;
105+ }
106+
107+ input [type = " range" ] {
108+ position : absolute ;
109+ left : 0 ;
110+ width : 100% ;
111+ appearance : none ;
112+ background : transparent ;
113+ pointer-events : none ;
114+ z-index : 3 ;
115+ }
116+
117+ input [type = " range" ]::-webkit-slider-thumb {
118+ -webkit-appearance : none ;
119+ pointer-events : auto ;
120+ width : 20px ;
121+ height : 20px ;
122+ background-color : v-bind (slicerColor );
123+ border-radius : 50% ;
124+ cursor : pointer ;
125+ position : relative ;
126+ z-index : 2 ;
127+ outline : 2px solid v-bind (borderColor );
128+ transition : all 0.2s ease-in-out ;
129+ & :active ,
130+ & :hover {
131+ box-shadow : 0 0 0 10px v-bind (selectColorOpaque );
132+ background-color : v-bind (selectColor );
133+ }
134+ }
135+
136+ input [type = " range" ]::-moz-range-thumb {
137+ pointer-events : auto ;
138+ width : 20px ;
139+ height : 20px ;
140+ background-color : v-bind (slicerColor );
141+ border-radius : 50% ;
142+ cursor : pointer ;
143+ position : relative ;
144+ z-index : 2 ;
145+ outline : 2px solid v-bind (borderColor );
146+ transition : all 0.2s ease-in-out ;
147+ & :active ,
148+ & :hover {
149+ box-shadow : 0 0 0 10px v-bind (selectColorOpaque );
150+ background-color : v-bind (selectColor );
151+ }
152+ }
153+
154+ input [type = " range" ]::-ms-thumb {
155+ pointer-events : auto ;
156+ width : 20px ;
157+ height : 20px ;
158+ background-color : v-bind (slicerColor );
159+ border-radius : 50% ;
160+ cursor : pointer ;
161+ position : relative ;
162+ z-index : 2 ;
163+ outline : 2px solid v-bind (borderColor );
164+ transition : all 0.2s ease-in-out ;
165+ & :active ,
166+ & :hover {
167+ box-shadow : 0 0 0 10px v-bind (selectColorOpaque );
168+ background-color : v-bind (selectColor );
169+ }
170+ }
171+
172+ .slider-track {
173+ position : absolute ;
174+ width : 99% ;
175+ height : 8px ;
176+ border-radius : 4px ;
177+ background : v-bind (backgroundColor );
178+ top : 8px ;
179+ z-index : 1 ;
180+ left : 50% ;
181+ transform : translateX (-50% );
182+ -webkit-transform : translateX (-50% );
183+ }
184+
185+ .range-highlight {
186+ position : absolute ;
187+ height : 8px ;
188+ top : 8px ;
189+ z-index : 1 ;
190+ border-radius : 4px ;
191+ }
192+
193+ .vue-data-ui-refresh-button {
194+ outline : none ;
195+ border : none ;
196+ background : transparent ;
197+ height : 36px ;
198+ width : 36px ;
199+ display : flex ;
200+ align-items : center ;
201+ justify-content : center ;
202+ border-radius : 50% ;
203+ cursor : pointer ;
204+ transition : transform 0.2s ease-in-out ;
205+ transform-origin : center ;
206+ & :focus {
207+ outline : 1px solid v-bind (slicerColor );
208+ }
209+ & :hover {
210+ transform : rotate (-90deg )
211+ }
212+ }
213+
214+ .vue-data-ui-slicer-labels {
215+ display : flex ;
216+ flex-direction : row ;
217+ align-items : center ;
218+ padding : 0 24px ;
219+ height : 40px ;
220+ }
221+
222+ .vue-data-ui-slicer-label-left ,
223+ .vue-data-ui-slicer-label-right {
224+ width : 100% ;
225+ }
226+
227+ .vue-data-ui-slicer-label-left {
228+ text-align : left ;
229+ }
230+
231+ .vue-data-ui-slicer-label-right {
232+ text-align : right ;
233+ }
234+ </style >
0 commit comments