File size: 3,383 Bytes
8b9f7d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<script setup lang="ts">
import { computed, getCurrentInstance, onMounted, onUnmounted, PropType, ref } from 'vue';
import { getAssetUrl } from '../utils';
import { useConfig } from '../ConfigProvider';

type CursorState =
  | 'default'
  | 'default-active'
  | 'pointer'
  | 'pointer-active'
  | 'pointer-denied'
  | 'hold'
  | 'arrow-top'
  | 'arrow-right'
  | 'arrow-bottom'
  | 'arrow-left'

const props = defineProps({
  state: {
    type: String as PropType<CursorState>,
    default: () => 'default',
  },
  // color: { // TODO: Finish this feature (its hard to mix color and sprites with alpha via css)
  //   type: String,
  //   default: () => '#0000',
  // }
});

const {theme} = useConfig();
const cursorEl = ref<HTMLElement | null>(null);
const cursorPlaceEl = ref<HTMLElement | null>(null);

const spriteUrl = computed(() => getAssetUrl('cursor.png', theme.value));

function moveCursor(e: MouseEvent) {
  if(!cursorEl.value) return;
  cursorEl.value.style.transform = `translate(${e.pageX}px, ${e.pageY}px)`;
}


onMounted(() => {
  cursorPlaceEl.value = getCurrentInstance()?.proxy?.$el.parentElement;
  if(!cursorPlaceEl?.value) {
    throw new Error('[warcraft-3-ui]: Cursor - element from "to" prop not found or something went wrong')
  }

  cursorPlaceEl.value.addEventListener('mousemove', moveCursor);
  cursorPlaceEl.value.classList.add('cursored');
})

onUnmounted(()=>{
  if(cursorPlaceEl.value){
    cursorPlaceEl.value.removeEventListener('mousemove', moveCursor);
    cursorPlaceEl.value.classList.remove('cursored');
  }
})
</script>

<template>
  <div ref="cursorEl" class="cursor__container">
    <div :class="`cursor cursor--${props.state}`" />
  </div>
</template>

<style lang="scss">
$tile-size: 32px;

.cursored{
  cursor: none;
  & * {
    cursor: none;
  }
}
.cursor {
  position: relative;
  width: $tile-size;
  height: $tile-size;
  background: v-bind(spriteUrl) no-repeat;
  // mix-blend-mode: color;
  // border: 1px solid orange;

  &__container {
    top: 0;
    left: 0;
    position: fixed;
    z-index: 99;
    pointer-events: none;
    // background-color: v-bind('props.color');
  }

  &--default-active {
    animation: cursor-active 500ms steps(8) infinite;
  }
  &--pointer {
    background-position: (-$tile-size * 1) (-$tile-size * 3);
  }
  &--pointer-active {
    animation: cursor-pointer 500ms steps(8) infinite;
  }
  &--pointer-denied {
    background-position: (-$tile-size * 2) (-$tile-size * 3);
  }
  &--hold {
    background-position: (-$tile-size * 4) (-$tile-size * 3);
  }
  &--arrow-top {
    animation: cursor-arrow 100ms steps(3) infinite;
    transform: rotate(-90deg)
  }
  &--arrow-right {
    animation: cursor-arrow 100ms steps(3) infinite;
  }
  &--arrow-bottom {
    animation: cursor-arrow 100ms steps(3) infinite;
    transform: rotate(90deg)
  }
  &--arrow-left {
    animation: cursor-arrow 100ms steps(3) infinite;
    transform: rotate(-180deg)
  }
}

@keyframes cursor-active {
   from { background-position: 0 0; }
   to { background-position: (-$tile-size * 8) 0; }
}
@keyframes cursor-pointer {
   from { background-position: 0 (-$tile-size * 2); }
   to { background-position: (-$tile-size * 8) (-$tile-size * 2); }
}
@keyframes cursor-arrow {
   from { background-position: (-$tile-size * 5) (-$tile-size * 3); }
   to { background-position: (-$tile-size * 8) (-$tile-size * 3); }
}
</style>