@@ -33,6 +33,7 @@ const props = defineProps({
3333const uid = ref (createUid ());
3434const isTooltip = ref (false );
3535const hoveredValue = ref (undefined );
36+ const focusedValue = ref (undefined );
3637const units = ref ([]);
3738const slots = useSlots ();
3839
@@ -214,104 +215,117 @@ defineExpose({
214215 class =" vue-ui-rating-unit-container"
215216 :style =" `position:relative;height:${FINAL_CONFIG.style.itemSize}px;width:${FINAL_CONFIG.style.itemSize}px`"
216217 >
217- <!-- IMAGE FIRST LAYER -->
218- <img
219- :data-cy =" `rating-image-${i}`"
220- v-if =" isImage"
221- :src =" FINAL_CONFIG.style.image.src"
222- :height =" FINAL_CONFIG.style.itemSize"
223- :width =" FINAL_CONFIG.style.itemSize"
224- class =" vue-ui-rating-unit"
225- :style =" `position:absolute;top:0;left:0;opacity:${!isNaN(hoveredValue) ? getInactiveFill(value, true) : FINAL_CONFIG.style.image.inactiveOpacity}`"
226- />
227-
228- <!-- STAR FIRST LAYER -->
229- <svg
230- :xmlns =" XMLNS"
231- v-else
232- viewBox =" 0 0 100 100"
233- :height =" FINAL_CONFIG.style.itemSize"
234- :width =" FINAL_CONFIG.style.itemSize"
235- class =" vue-ui-rating-unit"
236- >
237- <defs >
238- <radialGradient
239- cx =" 50%" cy =" 50%" r =" 50%" fx =" 50%" fy =" 50%"
240- :id =" `star_gradient_under_${uid}`"
241- >
242- <stop offset =" 0%" :stop-color =" `${shiftHue(FINAL_CONFIG.style.star.activeColor, 0.05)}`" />
243- <stop offset =" 100%" :stop-color =" FINAL_CONFIG.style.star.activeColor" />
244- </radialGradient >
245- </defs >
246- <polygon
247- :data-cy =" `rating-shape-${i}`"
248- :points =" createStar({
249- plot: { x: 50, y: 50 },
250- radius: 30,
251- apexes: FINAL_CONFIG.style.star.apexes
252- })"
253- :fill ="
254- !isNaN(hoveredValue)
255- ? getInactiveFill(value)
256- : FINAL_CONFIG.style.star.inactiveColor
257- "
258- :stroke ="
259- FINAL_CONFIG.style.star.borderColor
260- ? FINAL_CONFIG.style.star.borderColor
261- : hoveredValue
262- ? getInactiveFill(value)
263- : FINAL_CONFIG.style.star.inactiveColor
264- "
265- :stroke-width =" FINAL_CONFIG.style.star.borderWidth"
266- stroke-linecap =" round"
267- stroke-linejoin =" round"
218+ <!-- LAYER SLOTS -->
219+ <div v-if =" $slots['layer-under'] || $slots['layer-above']" style =" position :relative " >
220+ <div v-if =" $slots['layer-under']" style =" position : absolute ; top : 0 ; left : 0 ; width : 100% ; height : 100% " >
221+ <slot name =" layer-under" v-bind =" { value, size: FINAL_CONFIG.style.itemSize, hoveredValue, focusedValue }" />
222+ </div >
223+ <div v-if =" $slots['layer-above']" style =" position : absolute ; top : 0 ; left : 0 ; width : 100% ; height : 100% " >
224+ <slot name =" layer-above" v-bind =" { value, size: FINAL_CONFIG.style.itemSize, hoveredValue, focusedValue }" />
225+ </div >
226+ </div >
227+
228+
229+ <template v-else >
230+ <!-- IMAGE FIRST LAYER -->
231+ <img
232+ :data-cy =" `rating-image-${i}`"
233+ v-if =" isImage"
234+ :src =" FINAL_CONFIG.style.image.src"
235+ :height =" FINAL_CONFIG.style.itemSize"
236+ :width =" FINAL_CONFIG.style.itemSize"
237+ class =" vue-ui-rating-unit"
238+ :style =" `position:absolute;top:0;left:0;opacity:${!isNaN(hoveredValue) ? getInactiveFill(value, true) : FINAL_CONFIG.style.image.inactiveOpacity}`"
268239 />
269- </svg >
270-
271- <!-- IMAGE SECOND LAYER -->
272- <img
273- :data-cy =" `rating-image-overlay-${i}`"
274- v-if =" isImage"
275- :src =" FINAL_CONFIG.style.image.src"
276- :alt =" `${FINAL_CONFIG.style.image.alt} ${value}`"
277- :height =" FINAL_CONFIG.style.itemSize"
278- :width =" FINAL_CONFIG.style.itemSize"
279- :id =" `active_${uid}_${value}`"
280- class =" vue-ui-rating-unit"
281- :style =" `position:absolute;top:0;left:0;clip:rect(0px,${calcShapeFill(i, true) * FINAL_CONFIG.style.itemSize}px,${FINAL_CONFIG.style.itemSize}px,0px`"
282- />
283-
284- <!-- STAR SECOND LAYER -->
285- <svg
286- :xmlns =" XMLNS"
287- :data-cy =" `rating-shape-overlay-${i}`"
288- v-else
289- :viewBox =" `0 0 ${calcShapeFill(i)} 100`"
290- :height =" FINAL_CONFIG.style.itemSize"
291- class =" vue-ui-rating-unit"
292- :id =" `active_${uid}_${value}`"
293- style =" position :absolute ;top :0 ;left :0 "
294- >
295- <defs >
296- <radialGradient
297- cx =" 50%" cy =" 50%" r =" 50%" fx =" 50%" fy =" 50%"
298- :id =" `star_gradient_over_${uid}`"
299- >
300- <stop offset =" 0%" :stop-color =" `${shiftHue(FINAL_CONFIG.style.star.activeColor, 0.05)}`" />
301- <stop offset =" 100%" :stop-color =" FINAL_CONFIG.style.star.activeColor" />
302- </radialGradient >
303- </defs >
304-
305- <polygon
306- :points =" createStar({
307- plot: { x: 50, y: 50 },
308- radius: 30,
309- apexes: FINAL_CONFIG.style.star.apexes
310- })"
311- :fill =" FINAL_CONFIG.style.star.useGradient ? `url(#star_gradient_over_${uid})` : FINAL_CONFIG.style.star.activeColor"
312- :stroke =" FINAL_CONFIG.style.star.activeColor"
240+
241+ <!-- STAR FIRST LAYER -->
242+ <svg
243+ :xmlns =" XMLNS"
244+ v-else
245+ viewBox =" 0 0 100 100"
246+ :height =" FINAL_CONFIG.style.itemSize"
247+ :width =" FINAL_CONFIG.style.itemSize"
248+ class =" vue-ui-rating-unit"
249+ >
250+ <defs >
251+ <radialGradient
252+ cx =" 50%" cy =" 50%" r =" 50%" fx =" 50%" fy =" 50%"
253+ :id =" `star_gradient_under_${uid}`"
254+ >
255+ <stop offset =" 0%" :stop-color =" `${shiftHue(FINAL_CONFIG.style.star.activeColor, 0.05)}`" />
256+ <stop offset =" 100%" :stop-color =" FINAL_CONFIG.style.star.activeColor" />
257+ </radialGradient >
258+ </defs >
259+ <polygon
260+ :data-cy =" `rating-shape-${i}`"
261+ :points =" createStar({
262+ plot: { x: 50, y: 50 },
263+ radius: 30,
264+ apexes: FINAL_CONFIG.style.star.apexes
265+ })"
266+ :fill ="
267+ !isNaN(hoveredValue)
268+ ? getInactiveFill(value)
269+ : FINAL_CONFIG.style.star.inactiveColor
270+ "
271+ :stroke ="
272+ FINAL_CONFIG.style.star.borderColor
273+ ? FINAL_CONFIG.style.star.borderColor
274+ : hoveredValue
275+ ? getInactiveFill(value)
276+ : FINAL_CONFIG.style.star.inactiveColor
277+ "
278+ :stroke-width =" FINAL_CONFIG.style.star.borderWidth"
279+ stroke-linecap =" round"
280+ stroke-linejoin =" round"
281+ />
282+ </svg >
283+
284+ <!-- IMAGE SECOND LAYER -->
285+ <img
286+ :data-cy =" `rating-image-overlay-${i}`"
287+ v-if =" isImage"
288+ :src =" FINAL_CONFIG.style.image.src"
289+ :alt =" `${FINAL_CONFIG.style.image.alt} ${value}`"
290+ :height =" FINAL_CONFIG.style.itemSize"
291+ :width =" FINAL_CONFIG.style.itemSize"
292+ :id =" `active_${uid}_${value}`"
293+ class =" vue-ui-rating-unit"
294+ :style =" `position:absolute;top:0;left:0;clip:rect(0px,${calcShapeFill(i, true) * FINAL_CONFIG.style.itemSize}px,${FINAL_CONFIG.style.itemSize}px,0px`"
313295 />
314- </svg >
296+
297+ <!-- STAR SECOND LAYER -->
298+ <svg
299+ :xmlns =" XMLNS"
300+ :data-cy =" `rating-shape-overlay-${i}`"
301+ v-else
302+ :viewBox =" `0 0 ${calcShapeFill(i)} 100`"
303+ :height =" FINAL_CONFIG.style.itemSize"
304+ class =" vue-ui-rating-unit"
305+ :id =" `active_${uid}_${value}`"
306+ style =" position :absolute ;top :0 ;left :0 "
307+ >
308+ <defs >
309+ <radialGradient
310+ cx =" 50%" cy =" 50%" r =" 50%" fx =" 50%" fy =" 50%"
311+ :id =" `star_gradient_over_${uid}`"
312+ >
313+ <stop offset =" 0%" :stop-color =" `${shiftHue(FINAL_CONFIG.style.star.activeColor, 0.05)}`" />
314+ <stop offset =" 100%" :stop-color =" FINAL_CONFIG.style.star.activeColor" />
315+ </radialGradient >
316+ </defs >
317+
318+ <polygon
319+ :points =" createStar({
320+ plot: { x: 50, y: 50 },
321+ radius: 30,
322+ apexes: FINAL_CONFIG.style.star.apexes
323+ })"
324+ :fill =" FINAL_CONFIG.style.star.useGradient ? `url(#star_gradient_over_${uid})` : FINAL_CONFIG.style.star.activeColor"
325+ :stroke =" FINAL_CONFIG.style.star.activeColor"
326+ />
327+ </svg >
328+ </template >
315329
316330 <!-- MOUSE TRAPS -->
317331 <svg
@@ -333,6 +347,8 @@ defineExpose({
333347 @click =" rate(value)"
334348 @mouseenter =" hoveredValue = value"
335349 @mouseleave =" hoveredValue = undefined"
350+ @focus =" focusedValue = value"
351+ @blur =" focusedValue = undefined"
336352 tabindex =" 0"
337353 @keyup.enter =" rate(value)"
338354 />
@@ -347,6 +363,8 @@ defineExpose({
347363 fill =" transparent"
348364 @mouseenter =" hoveredValue = value"
349365 @mouseleave =" hoveredValue = undefined"
366+ @focus =" focusedValue = value"
367+ @blur =" focusedValue = undefined"
350368 />
351369 </svg >
352370 <template v-if =" FINAL_CONFIG .style .tooltip .show && hasBreakdown && isReadonly " >
0 commit comments