@bedard/hexboard 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +2 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.js +369 -379
- package/package.json +1 -1
- package/src/lib/components/hexboard/Hexboard.vue +22 -15
- package/src/lib/components/hexboard/constants.ts +0 -1
- package/src/lib/components/hexboard/types.ts +12 -2
- package/src/sandbox/App.vue +42 -1
- package/src/lib/components/hexboard/haptics.ts +0 -56
package/package.json
CHANGED
|
@@ -190,9 +190,8 @@ import {
|
|
|
190
190
|
} from './constants'
|
|
191
191
|
import { d } from './dom'
|
|
192
192
|
import { x, y } from './geometry'
|
|
193
|
-
import { hapticConfirm } from './haptics'
|
|
194
193
|
import GiocoPieces from './pieces/Gioco.vue'
|
|
195
|
-
import type { HexboardOptions } from './types'
|
|
194
|
+
import type { HexboardOptions, Rect } from './types'
|
|
196
195
|
|
|
197
196
|
//
|
|
198
197
|
// props
|
|
@@ -264,7 +263,7 @@ const pointerCoords = shallowRef({ x: 0, y: 0 })
|
|
|
264
263
|
const pointerdownPosition = shallowRef<number | null>(null)
|
|
265
264
|
|
|
266
265
|
/** rect of promotion anchor element */
|
|
267
|
-
const promotionRect = shallowRef
|
|
266
|
+
const promotionRect = shallowRef(rect())
|
|
268
267
|
|
|
269
268
|
/** staging display data */
|
|
270
269
|
const staging = shallowRef<{
|
|
@@ -285,7 +284,7 @@ const staging = shallowRef<{
|
|
|
285
284
|
const svgEl = useTemplateRef('svgEl')
|
|
286
285
|
|
|
287
286
|
/** rect of svg element on pointerdown */
|
|
288
|
-
const svgRect = shallowRef<
|
|
287
|
+
const svgRect = shallowRef<Rect>(rect())
|
|
289
288
|
|
|
290
289
|
/** flag to skip click handling after promotion cancel */
|
|
291
290
|
let skipNextClick = false
|
|
@@ -582,7 +581,7 @@ function listen() {
|
|
|
582
581
|
/** measure promotion element rect */
|
|
583
582
|
function measurePromotionRect() {
|
|
584
583
|
promotionRect.value
|
|
585
|
-
= staging.value.promotionEl?.getBoundingClientRect() ??
|
|
584
|
+
= staging.value.promotionEl?.getBoundingClientRect() ?? rect()
|
|
586
585
|
}
|
|
587
586
|
|
|
588
587
|
/** click position */
|
|
@@ -674,7 +673,7 @@ function onPointerupPosition(index: number, evt: PointerEvent) {
|
|
|
674
673
|
|
|
675
674
|
// Keep selection but reset drag state
|
|
676
675
|
pointerdownPosition.value = null
|
|
677
|
-
svgRect.value =
|
|
676
|
+
svgRect.value = rect()
|
|
678
677
|
return
|
|
679
678
|
}
|
|
680
679
|
|
|
@@ -701,7 +700,7 @@ function onPointerupPosition(index: number, evt: PointerEvent) {
|
|
|
701
700
|
// If clicking on any piece, keep the selection (it was set in pointerdown)
|
|
702
701
|
if (props.hexchess?.board[index]) {
|
|
703
702
|
pointerdownPosition.value = null
|
|
704
|
-
svgRect.value =
|
|
703
|
+
svgRect.value = rect()
|
|
705
704
|
return
|
|
706
705
|
}
|
|
707
706
|
|
|
@@ -734,8 +733,6 @@ function cancelPromotion() {
|
|
|
734
733
|
function onPointerdownPosition(index: number, evt: PointerEvent) {
|
|
735
734
|
evt.preventDefault()
|
|
736
735
|
|
|
737
|
-
hapticConfirm()
|
|
738
|
-
|
|
739
736
|
// Don't start new interactions during promotion
|
|
740
737
|
if (staging.value.hexchess) {
|
|
741
738
|
return
|
|
@@ -750,10 +747,6 @@ function onPointerdownPosition(index: number, evt: PointerEvent) {
|
|
|
750
747
|
if (props.autoselect) {
|
|
751
748
|
selected.value = index
|
|
752
749
|
targets.value = props.hexchess?.movesFrom(index).map(san => san.to) ?? []
|
|
753
|
-
|
|
754
|
-
if (normalizedOptions.value.haptics) {
|
|
755
|
-
hapticConfirm()
|
|
756
|
-
}
|
|
757
750
|
}
|
|
758
751
|
|
|
759
752
|
if (!isPlayingPosition(index)) {
|
|
@@ -813,7 +806,7 @@ function onPointerupWindow() {
|
|
|
813
806
|
// If dragging a piece, keep the selection but reset drag state
|
|
814
807
|
if (pointerdownPosition.value !== null) {
|
|
815
808
|
pointerdownPosition.value = null
|
|
816
|
-
svgRect.value =
|
|
809
|
+
svgRect.value = rect()
|
|
817
810
|
return
|
|
818
811
|
}
|
|
819
812
|
|
|
@@ -836,6 +829,20 @@ function promote(promotion: 'n' | 'b' | 'r' | 'q') {
|
|
|
836
829
|
}
|
|
837
830
|
}
|
|
838
831
|
|
|
832
|
+
function rect(data: Partial<Rect> = {}): Rect {
|
|
833
|
+
return {
|
|
834
|
+
bottom: 0,
|
|
835
|
+
height: 0,
|
|
836
|
+
left: 0,
|
|
837
|
+
right: 0,
|
|
838
|
+
top: 0,
|
|
839
|
+
width: 0,
|
|
840
|
+
x: 0,
|
|
841
|
+
y: 0,
|
|
842
|
+
...data,
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
839
846
|
/** reset state */
|
|
840
847
|
function resetState() {
|
|
841
848
|
document.body.style.setProperty('cursor', null)
|
|
@@ -848,7 +855,7 @@ function resetState() {
|
|
|
848
855
|
promotionTo: null,
|
|
849
856
|
selected: null,
|
|
850
857
|
}
|
|
851
|
-
svgRect.value =
|
|
858
|
+
svgRect.value = rect()
|
|
852
859
|
targets.value = []
|
|
853
860
|
}
|
|
854
861
|
|
|
@@ -10,7 +10,6 @@ export const defaultOptions: HexboardOptions = {
|
|
|
10
10
|
'oklch(0.8366 0.1165 66.29)',
|
|
11
11
|
'oklch(0.6806 0.1423 75.83)',
|
|
12
12
|
],
|
|
13
|
-
haptics: true,
|
|
14
13
|
highlightColor: 'oklch(90.5% 0.182 98.111 / 75%)', // yellow-300 / 75% opacity
|
|
15
14
|
labelActiveColor: 'oklch(76.9% 0.188 70.08)', // amber-500
|
|
16
15
|
labelColor: 'oklch(55.4% 0.046 257.417)', // slate-500
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
export interface HexboardOptions {
|
|
3
3
|
/** position colors */
|
|
4
4
|
colors: [string, string, string]
|
|
5
|
-
/** haptic feedback vibrations */
|
|
6
|
-
haptics: boolean
|
|
7
5
|
/** color of highlighted position */
|
|
8
6
|
highlightColor: string
|
|
9
7
|
/** color of active label relative to mouseover */
|
|
@@ -20,6 +18,18 @@ export interface HexboardOptions {
|
|
|
20
18
|
selectedColor: string
|
|
21
19
|
}
|
|
22
20
|
|
|
21
|
+
/** rect */
|
|
22
|
+
export type Rect = {
|
|
23
|
+
bottom: number
|
|
24
|
+
height: number
|
|
25
|
+
left: number
|
|
26
|
+
right: number
|
|
27
|
+
top: number
|
|
28
|
+
width: number
|
|
29
|
+
x: number
|
|
30
|
+
y: number
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
/** uniform tuple of length `T`, `number` by default */
|
|
24
34
|
export type Vec<
|
|
25
35
|
T extends number,
|
package/src/sandbox/App.vue
CHANGED
|
@@ -10,7 +10,48 @@
|
|
|
10
10
|
:hexchess
|
|
11
11
|
:playing="true"
|
|
12
12
|
@move="onMove"
|
|
13
|
-
|
|
13
|
+
>
|
|
14
|
+
<template #promotion="{ b, n, q, r, promote }">
|
|
15
|
+
<div class="absolute bg-gray-50 cursor-pointer flex left-1/2 bottom-full rounded-md shadow-md overflow-hidden -translate-x-1/2">
|
|
16
|
+
<button
|
|
17
|
+
class="aspect-square border-r border-gray-200 cursor-pointer flex items-center justify-center size-12 hover:bg-gray-200"
|
|
18
|
+
@click="promote('b')"
|
|
19
|
+
>
|
|
20
|
+
<Component
|
|
21
|
+
class="size-3/4"
|
|
22
|
+
:is="b"
|
|
23
|
+
/>
|
|
24
|
+
</button>
|
|
25
|
+
<button
|
|
26
|
+
class="aspect-square border-r border-gray-200 cursor-pointer flex items-center justify-center size-12 hover:bg-gray-200"
|
|
27
|
+
@click="promote('n')"
|
|
28
|
+
>
|
|
29
|
+
<Component
|
|
30
|
+
class="size-3/4"
|
|
31
|
+
:is="n"
|
|
32
|
+
/>
|
|
33
|
+
</button>
|
|
34
|
+
<button
|
|
35
|
+
class="aspect-square border-r border-gray-200 cursor-pointer flex items-center justify-center size-12 hover:bg-gray-200"
|
|
36
|
+
@click="promote('r')"
|
|
37
|
+
>
|
|
38
|
+
<Component
|
|
39
|
+
class="size-3/4"
|
|
40
|
+
:is="r"
|
|
41
|
+
/>
|
|
42
|
+
</button>
|
|
43
|
+
<button
|
|
44
|
+
class="aspect-square cursor-pointer flex items-center justify-center size-12 hover:bg-gray-200"
|
|
45
|
+
@click="promote('q')"
|
|
46
|
+
>
|
|
47
|
+
<Component
|
|
48
|
+
class="size-3/4"
|
|
49
|
+
:is="q"
|
|
50
|
+
/>
|
|
51
|
+
</button>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
</Hexboard>
|
|
14
55
|
</div>
|
|
15
56
|
</template>
|
|
16
57
|
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/** check if haptics are supported */
|
|
2
|
-
export const supportsHaptics
|
|
3
|
-
= typeof window === 'undefined'
|
|
4
|
-
? false
|
|
5
|
-
: window.matchMedia('(pointer: coarse)').matches
|
|
6
|
-
|
|
7
|
-
/** trigger haptic feedback */
|
|
8
|
-
function tick() {
|
|
9
|
-
try {
|
|
10
|
-
// use the native api if supported
|
|
11
|
-
if (navigator.vibrate) {
|
|
12
|
-
navigator.vibrate(50)
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (!supportsHaptics) return
|
|
17
|
-
|
|
18
|
-
// otherwise simulate a tep using a checkbox
|
|
19
|
-
const labelEl = document.createElement('label')
|
|
20
|
-
labelEl.ariaHidden = 'true'
|
|
21
|
-
labelEl.style.display = 'none'
|
|
22
|
-
|
|
23
|
-
const inputEl = document.createElement('input')
|
|
24
|
-
inputEl.type = 'checkbox'
|
|
25
|
-
inputEl.setAttribute('switch', '')
|
|
26
|
-
labelEl.appendChild(inputEl)
|
|
27
|
-
|
|
28
|
-
document.head.appendChild(labelEl)
|
|
29
|
-
labelEl.click()
|
|
30
|
-
document.head.removeChild(labelEl)
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
// do nothing
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function hapticConfirm() {
|
|
38
|
-
if (navigator.vibrate) {
|
|
39
|
-
navigator.vibrate([50, 70, 50])
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
tick()
|
|
44
|
-
setTimeout(tick, 120)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function hapticError() {
|
|
48
|
-
if (navigator.vibrate) {
|
|
49
|
-
navigator.vibrate([50, 70, 50, 70, 50])
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
tick()
|
|
54
|
-
setTimeout(tick, 120)
|
|
55
|
-
setTimeout(tick, 240)
|
|
56
|
-
}
|