arrowtab 0.0.1 → 0.0.3
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/LICENSE +21 -0
- package/README.md +110 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +6 -0
- package/dist/index.test.js.map +1 -0
- package/dist/lib/debugMode.d.ts +8 -0
- package/dist/lib/debugMode.js +68 -0
- package/dist/lib/debugMode.js.map +1 -0
- package/dist/lib/distances.d.ts +13 -0
- package/dist/lib/distances.js +15 -0
- package/dist/lib/distances.js.map +1 -0
- package/dist/lib/getAngle.d.ts +4 -0
- package/dist/lib/getAngle.js +15 -0
- package/dist/lib/getAngle.js.map +1 -0
- package/dist/lib/getFocusable.js +29 -0
- package/dist/lib/getFocusable.js.map +1 -0
- package/dist/lib/getXyDistance.d.ts +7 -0
- package/dist/lib/getXyDistance.js +12 -0
- package/dist/lib/getXyDistance.js.map +1 -0
- package/dist/lib/hasDisabledKeys.d.ts +4 -0
- package/dist/lib/hasDisabledKeys.js +26 -0
- package/dist/lib/hasDisabledKeys.js.map +1 -0
- package/dist/lib/hasTextSelection.d.ts +4 -0
- package/dist/lib/hasTextSelection.js +53 -0
- package/dist/lib/hasTextSelection.js.map +1 -0
- package/dist/lib/initArrowTab.d.ts +5 -0
- package/dist/lib/initArrowTab.js +102 -0
- package/dist/lib/initArrowTab.js.map +1 -0
- package/dist/lib/positions.js +16 -0
- package/dist/lib/positions.js.map +1 -0
- package/dist/lib/preventNativeArrowKeyPresses.d.ts +4 -0
- package/dist/lib/preventNativeArrowKeyPresses.js +24 -0
- package/dist/lib/preventNativeArrowKeyPresses.js.map +1 -0
- package/dist/lib/strategies.d.ts +9 -23
- package/dist/lib/strategies.js +111 -39
- package/dist/lib/strategies.js.map +1 -1
- package/dist/lib/{sumBy.mjs → sumBy.js} +1 -1
- package/dist/lib/sumBy.js.map +1 -0
- package/package.json +35 -9
- package/.prettierrc +0 -5
- package/.vscode/settings.json +0 -4
- package/dist/index.d.mts +0 -1
- package/dist/index.mjs +0 -177
- package/dist/index.mjs.map +0 -1
- package/dist/lib/getFocusable.mjs +0 -15
- package/dist/lib/getFocusable.mjs.map +0 -1
- package/dist/lib/positions.mjs +0 -12
- package/dist/lib/positions.mjs.map +0 -1
- package/dist/lib/sumBy.mjs.map +0 -1
- package/index.html +0 -142
- package/src/index.mts +0 -228
- package/src/lib/getFocusable.mts +0 -13
- package/src/lib/positions.mts +0 -12
- package/src/lib/strategies.ts +0 -62
- package/src/lib/sumBy.mts +0 -4
- package/tsconfig.json +0 -20
- /package/dist/lib/{getFocusable.d.mts → getFocusable.d.ts} +0 -0
- /package/dist/lib/{positions.d.mts → positions.d.ts} +0 -0
- /package/dist/lib/{sumBy.d.mts → sumBy.d.ts} +0 -0
package/index.html
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>arrowTab</title>
|
|
7
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div class="flex flex-col gap-48">
|
|
11
|
-
<div class="grid grid-cols-3 gap-4 p-4 items-baseline">
|
|
12
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
13
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
14
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
15
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
16
|
-
<input type="text" class="border-2 border-gray-300 p-2" value="Hello" />
|
|
17
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
18
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
19
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
20
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<div class="grid grid-cols-3 gap-4 p-4 items-baseline">
|
|
24
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
25
|
-
<input type="text" disabled class="border-2 border-gray-300 p-2" />
|
|
26
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
27
|
-
<input type="text" disabled class="border-2 border-gray-300 p-2" />
|
|
28
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
29
|
-
<input type="text" disabled class="border-2 border-gray-300 p-2" />
|
|
30
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
31
|
-
<input type="text" disabled class="border-2 border-gray-300 p-2" />
|
|
32
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
<div class="grid grid-cols-3 gap-4 p-4 items-baseline">
|
|
36
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
37
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
38
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
39
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
40
|
-
<input
|
|
41
|
-
type="text"
|
|
42
|
-
class="border-2 border-gray-300 p-2"
|
|
43
|
-
value="✅ Input with Text"
|
|
44
|
-
/>
|
|
45
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
46
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
47
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
48
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
49
|
-
|
|
50
|
-
<hr class="col-span-3" />
|
|
51
|
-
|
|
52
|
-
<input
|
|
53
|
-
type="text"
|
|
54
|
-
class="border-2 border-gray-300 p-2"
|
|
55
|
-
value="✅ input"
|
|
56
|
-
/>
|
|
57
|
-
<div>
|
|
58
|
-
<span>❌ input hidden</span>
|
|
59
|
-
<input type="text" hidden class="border-2 border-gray-300 p-2" />
|
|
60
|
-
</div>
|
|
61
|
-
<input
|
|
62
|
-
type="text"
|
|
63
|
-
disabled
|
|
64
|
-
class="border-2 border-gray-300 p-2"
|
|
65
|
-
value="❌ input disabled"
|
|
66
|
-
/>
|
|
67
|
-
<button>✅ Button</button>
|
|
68
|
-
<button disabled>❌ button disabled</button>
|
|
69
|
-
<button aria-hidden="true">❌ button aria-hidden</button>
|
|
70
|
-
<a href="#" class="focus:outline">✅ a tag with href</a>
|
|
71
|
-
<a class="focus:outline">❌ only a tag</a>
|
|
72
|
-
<div></div>
|
|
73
|
-
<div tabindex="10">✅ tabindex="10"</div>
|
|
74
|
-
<div tabindex="0">✅ tabindex="0"</div>
|
|
75
|
-
<div tabindex="-1">❌ tabindex="-1"</div>
|
|
76
|
-
|
|
77
|
-
<hr class="col-span-3" />
|
|
78
|
-
|
|
79
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
80
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
81
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
82
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
83
|
-
<textarea class="border-2 border-gray-300 p-2">
|
|
84
|
-
✅ Multiline
|
|
85
|
-
Textarea
|
|
86
|
-
</textarea>
|
|
87
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
88
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
89
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
90
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
91
|
-
|
|
92
|
-
<hr class="col-span-3" />
|
|
93
|
-
|
|
94
|
-
<input
|
|
95
|
-
type="button"
|
|
96
|
-
class="border-2 border-gray-300 p-2"
|
|
97
|
-
value="input button"
|
|
98
|
-
/>
|
|
99
|
-
<input
|
|
100
|
-
type="submit"
|
|
101
|
-
class="border-2 border-gray-300 p-2"
|
|
102
|
-
value="input submit"
|
|
103
|
-
/>
|
|
104
|
-
<input
|
|
105
|
-
type="reset"
|
|
106
|
-
class="border-2 border-gray-300 p-2"
|
|
107
|
-
value="input reset"
|
|
108
|
-
/>
|
|
109
|
-
|
|
110
|
-
<input type="password" class="border-2 border-gray-300 p-2" />
|
|
111
|
-
<input type="checkbox" class="border-2 border-gray-300 p-2" />
|
|
112
|
-
<input type="radio" class="border-2 border-gray-300 p-2" />
|
|
113
|
-
<input type="file" class="border-2 border-gray-300 p-2" />
|
|
114
|
-
<input type="image" class="border-2 border-gray-300 p-2" />
|
|
115
|
-
<input type="email" class="border-2 border-gray-300 p-2" />
|
|
116
|
-
<input type="url" class="border-2 border-gray-300 p-2" />
|
|
117
|
-
<input type="tel" class="border-2 border-gray-300 p-2" />
|
|
118
|
-
<input type="search" class="border-2 border-gray-300 p-2" />
|
|
119
|
-
<input type="date" class="border-2 border-gray-300 p-2" />
|
|
120
|
-
<input type="time" class="border-2 border-gray-300 p-2" />
|
|
121
|
-
<input type="datetime" class="border-2 border-gray-300 p-2" />
|
|
122
|
-
<input type="datetime-local" class="border-2 border-gray-300 p-2" />
|
|
123
|
-
<input type="month" class="border-2 border-gray-300 p-2" />
|
|
124
|
-
<input type="week" class="border-2 border-gray-300 p-2" />
|
|
125
|
-
<input type="number" class="border-2 border-gray-300 p-2" />
|
|
126
|
-
<input type="range" class="border-2 border-gray-300 p-2" />
|
|
127
|
-
<input type="color" class="border-2 border-gray-300 p-2" />
|
|
128
|
-
|
|
129
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
130
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
131
|
-
<input type="text" class="border-2 border-gray-300 p-2" />
|
|
132
|
-
|
|
133
|
-
<!-- TODO: select, details -->
|
|
134
|
-
<!-- TODO: summary, iframe (?) -->
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
<script type="module">
|
|
138
|
-
import { initArrowTab } from './dist/index.mjs'
|
|
139
|
-
initArrowTab()
|
|
140
|
-
</script>
|
|
141
|
-
</body>
|
|
142
|
-
</html>
|
package/src/index.mts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
// TODO: Options
|
|
2
|
-
// modifierKey: 'ctrlKey',
|
|
3
|
-
// onlyWithModifierKey: false, // TODO: Better name
|
|
4
|
-
// strategy: arrowTab.XWalkEuclidean,
|
|
5
|
-
// selector: undefined,
|
|
6
|
-
// elementFilter: () => boolean,
|
|
7
|
-
// getElementPosition: (element) => { x: number, y: number },
|
|
8
|
-
// eventTriggerName: 'keydown' | 'keyup',
|
|
9
|
-
// earlyReturn: (event) => boolean, // TODO: Better name
|
|
10
|
-
|
|
11
|
-
import { getFocusable } from './lib/getFocusable.mjs'
|
|
12
|
-
import { getMiddle } from './lib/positions.mjs'
|
|
13
|
-
import { strategy } from './lib/strategies.js'
|
|
14
|
-
import { sumBy } from './lib/sumBy.mjs'
|
|
15
|
-
|
|
16
|
-
export const initArrowTab = () => {
|
|
17
|
-
document.addEventListener(
|
|
18
|
-
'keydown',
|
|
19
|
-
(event) => {
|
|
20
|
-
const activeStrategy = strategy.XWalkEuclidean
|
|
21
|
-
|
|
22
|
-
const activeElement =
|
|
23
|
-
document.activeElement === document.body
|
|
24
|
-
? getFocusable()?.[0]
|
|
25
|
-
: document.activeElement
|
|
26
|
-
|
|
27
|
-
if (!activeElement) {
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
event.key !== 'ArrowLeft' &&
|
|
33
|
-
event.key !== 'ArrowRight' &&
|
|
34
|
-
event.key !== 'ArrowUp' &&
|
|
35
|
-
event.key !== 'ArrowDown'
|
|
36
|
-
) {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
activeElement instanceof HTMLInputElement ||
|
|
42
|
-
activeElement instanceof HTMLTextAreaElement
|
|
43
|
-
) {
|
|
44
|
-
const selectionStart = activeElement.selectionStart
|
|
45
|
-
const selectionEnd = activeElement.selectionEnd
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
event.key === 'ArrowLeft' &&
|
|
49
|
-
selectionStart !== undefined &&
|
|
50
|
-
selectionStart !== null &&
|
|
51
|
-
selectionStart !== 0
|
|
52
|
-
) {
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
event.key === 'ArrowRight' &&
|
|
58
|
-
selectionStart !== undefined &&
|
|
59
|
-
selectionStart !== null &&
|
|
60
|
-
selectionStart !== activeElement.value?.length
|
|
61
|
-
) {
|
|
62
|
-
return
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
(event.key === 'ArrowLeft' || event.key === 'ArrowRight') &&
|
|
67
|
-
selectionStart !== undefined &&
|
|
68
|
-
selectionEnd !== undefined &&
|
|
69
|
-
selectionStart !== null &&
|
|
70
|
-
selectionEnd !== null &&
|
|
71
|
-
selectionStart !== selectionEnd
|
|
72
|
-
) {
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
event.key === 'ArrowUp' &&
|
|
78
|
-
selectionStart !== undefined &&
|
|
79
|
-
selectionStart !== null &&
|
|
80
|
-
activeElement instanceof HTMLTextAreaElement
|
|
81
|
-
) {
|
|
82
|
-
const rows = activeElement.value?.split('\n')
|
|
83
|
-
const start = selectionStart
|
|
84
|
-
const firstRow = rows.at(0)
|
|
85
|
-
if (firstRow && start > firstRow.length) {
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
event.key === 'ArrowDown' &&
|
|
92
|
-
selectionStart !== undefined &&
|
|
93
|
-
selectionStart !== null &&
|
|
94
|
-
activeElement instanceof HTMLTextAreaElement
|
|
95
|
-
) {
|
|
96
|
-
const rows = activeElement.value?.split('\n')
|
|
97
|
-
const withoutLastRow = rows.slice(0, -1)
|
|
98
|
-
const lengthUntilLastRow = sumBy(withoutLastRow, (row) => row.length)
|
|
99
|
-
|
|
100
|
-
const start = selectionStart
|
|
101
|
-
if (start <= lengthUntilLastRow + 1) {
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const inputTypesThatNeedModifierKey: Record<string, string[]> = {
|
|
108
|
-
date: ['ArrowDown', 'ArrowUp'],
|
|
109
|
-
time: ['ArrowDown', 'ArrowUp'],
|
|
110
|
-
datetime: ['ArrowDown', 'ArrowUp'],
|
|
111
|
-
'datetime-local': ['ArrowDown', 'ArrowUp'],
|
|
112
|
-
month: ['ArrowDown', 'ArrowUp'],
|
|
113
|
-
week: ['ArrowDown', 'ArrowUp'],
|
|
114
|
-
number: ['ArrowDown', 'ArrowUp'],
|
|
115
|
-
range: ['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight'],
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (activeElement instanceof HTMLInputElement) {
|
|
119
|
-
const inputType = activeElement.type
|
|
120
|
-
if (
|
|
121
|
-
inputTypesThatNeedModifierKey[inputType] &&
|
|
122
|
-
inputTypesThatNeedModifierKey[inputType].includes(event.key)
|
|
123
|
-
) {
|
|
124
|
-
// TODO: Use modifierKey
|
|
125
|
-
if (!event.shiftKey) {
|
|
126
|
-
return
|
|
127
|
-
} else {
|
|
128
|
-
event.preventDefault()
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const activePosition = getMiddle(activeElement)
|
|
134
|
-
|
|
135
|
-
const allFocusable = getFocusable()
|
|
136
|
-
const withoutActiveElement = allFocusable.filter(
|
|
137
|
-
(element) => element !== activeElement,
|
|
138
|
-
)
|
|
139
|
-
const withPosition = withoutActiveElement.map((element) => {
|
|
140
|
-
const position = getMiddle(element)
|
|
141
|
-
|
|
142
|
-
// Calculate angle between active element and focusable element
|
|
143
|
-
const xDistance = position.x - activePosition.x
|
|
144
|
-
const yDistance = position.y - activePosition.y
|
|
145
|
-
let angle =
|
|
146
|
-
Math.acos(yDistance / Math.sqrt(xDistance ** 2 + yDistance ** 2)) *
|
|
147
|
-
(180 / Math.PI)
|
|
148
|
-
const direction = xDistance > 0 ? 'right' : 'left'
|
|
149
|
-
if (direction === 'right') {
|
|
150
|
-
angle = 360 - angle
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
xDistance,
|
|
155
|
-
yDistance,
|
|
156
|
-
element,
|
|
157
|
-
angle,
|
|
158
|
-
position,
|
|
159
|
-
}
|
|
160
|
-
})
|
|
161
|
-
const withDistance = withPosition.map((focusable) => {
|
|
162
|
-
const distance = activeStrategy.distanceMetric({ ...focusable, event })
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
...focusable,
|
|
166
|
-
distance,
|
|
167
|
-
}
|
|
168
|
-
})
|
|
169
|
-
const withWithinReach = withDistance.map((focusable) => {
|
|
170
|
-
const withinReach = activeStrategy.withinReachMetric({
|
|
171
|
-
...focusable,
|
|
172
|
-
event,
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
...focusable,
|
|
177
|
-
withinReach,
|
|
178
|
-
}
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
const reversed = [...withWithinReach].reverse() // Prefer down / right if same distance
|
|
182
|
-
|
|
183
|
-
const sorted = reversed.sort((a, b) => {
|
|
184
|
-
return a.distance - b.distance
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
const withinReach = sorted.filter(({ withinReach }) => withinReach)
|
|
188
|
-
|
|
189
|
-
let nearest = withinReach.at(0)
|
|
190
|
-
|
|
191
|
-
if (!nearest) {
|
|
192
|
-
return
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// const nearlySameDistance = _.filter(candidates, (candidate) => {
|
|
196
|
-
// return candidate.distance - nearest.distance < 10
|
|
197
|
-
// })
|
|
198
|
-
|
|
199
|
-
// console.log('nearlySameDistance', nearlySameDistance)
|
|
200
|
-
|
|
201
|
-
// if (nearlySameDistance.length > 1) {
|
|
202
|
-
// const ordered = _.orderBy(nearlySameDistance, (candidate) => {
|
|
203
|
-
// if (event.key === 'ArrowDown') {
|
|
204
|
-
// console.log('ArrowDown', candidate.xDistance)
|
|
205
|
-
// return -candidate.xDistance
|
|
206
|
-
// }
|
|
207
|
-
// if (event.key === 'ArrowUp') {
|
|
208
|
-
// return candidate.xDistance
|
|
209
|
-
// }
|
|
210
|
-
// if (event.key === 'ArrowLeft') {
|
|
211
|
-
// return candidate.yDistance
|
|
212
|
-
// }
|
|
213
|
-
// if (event.key === 'ArrowRight') {
|
|
214
|
-
// console.log('ArrowRight', candidate.yDistance)
|
|
215
|
-
// return -candidate.yDistance
|
|
216
|
-
// }
|
|
217
|
-
// })
|
|
218
|
-
// console.log('ordered', ordered)
|
|
219
|
-
// nearest = _.first(ordered)
|
|
220
|
-
// }
|
|
221
|
-
|
|
222
|
-
if (nearest.element instanceof HTMLElement) {
|
|
223
|
-
nearest.element.focus()
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
{ capture: true },
|
|
227
|
-
)
|
|
228
|
-
}
|
package/src/lib/getFocusable.mts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const getFocusable = () => {
|
|
2
|
-
// Selectors from https://zellwk.com/blog/keyboard-focusable-elements/
|
|
3
|
-
const allFocusable = document.querySelectorAll(
|
|
4
|
-
'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex^="-"])',
|
|
5
|
-
)
|
|
6
|
-
const focusable = Array.from(allFocusable).filter((element) => {
|
|
7
|
-
if ('disabled' in element && element.disabled) return false
|
|
8
|
-
if ('hidden' in element && element.hidden) return false
|
|
9
|
-
if (element.getAttribute('aria-hidden') === 'true') return false
|
|
10
|
-
return true
|
|
11
|
-
})
|
|
12
|
-
return focusable
|
|
13
|
-
}
|
package/src/lib/positions.mts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export const getMiddle = (element: Element) => {
|
|
2
|
-
const { x, y, width, height } = element.getBoundingClientRect()
|
|
3
|
-
return {
|
|
4
|
-
x: x + width / 2,
|
|
5
|
-
y: y + height / 2,
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const getTopLeft = (element: Element) => {
|
|
10
|
-
const { x, y } = element.getBoundingClientRect()
|
|
11
|
-
return { x, y }
|
|
12
|
-
}
|
package/src/lib/strategies.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
type StrategyInput = {
|
|
2
|
-
event: KeyboardEvent
|
|
3
|
-
xDistance: number
|
|
4
|
-
yDistance: number
|
|
5
|
-
element: Element
|
|
6
|
-
angle: number
|
|
7
|
-
position: { x: number; y: number }
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const withinReachMetrics = {
|
|
11
|
-
XWalk: ({ angle, event }: StrategyInput) => {
|
|
12
|
-
if (event.key === 'ArrowDown' && (angle >= 315 || angle <= 45)) {
|
|
13
|
-
return true
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (event.key === 'ArrowLeft' && angle > 45 && angle < 135) {
|
|
17
|
-
return true
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (event.key === 'ArrowUp' && angle >= 135 && angle <= 225) {
|
|
21
|
-
return true
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (event.key === 'ArrowRight' && angle > 225 && angle < 315) {
|
|
25
|
-
return true
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return false
|
|
29
|
-
},
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const distanceMetrics = {
|
|
33
|
-
euclidean: ({ xDistance, yDistance }: StrategyInput) => {
|
|
34
|
-
return Math.sqrt(xDistance ** 2 + yDistance ** 2)
|
|
35
|
-
},
|
|
36
|
-
manhattan: ({ xDistance, yDistance }: StrategyInput) => {
|
|
37
|
-
return Math.abs(xDistance) + Math.abs(yDistance)
|
|
38
|
-
},
|
|
39
|
-
manhattanWeighted: ({ xDistance, yDistance, event }: StrategyInput) => {
|
|
40
|
-
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
41
|
-
return Math.abs(xDistance) + Math.abs(yDistance) * 0.1
|
|
42
|
-
}
|
|
43
|
-
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
|
44
|
-
return Math.abs(xDistance) * 0.1 + Math.abs(yDistance)
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const strategy = {
|
|
50
|
-
XWalkEuclidean: {
|
|
51
|
-
withinReachMetric: withinReachMetrics.XWalk,
|
|
52
|
-
distanceMetric: distanceMetrics.euclidean,
|
|
53
|
-
},
|
|
54
|
-
XWalkManhattan: {
|
|
55
|
-
withinReachMetric: withinReachMetrics.XWalk,
|
|
56
|
-
distanceMetric: distanceMetrics.manhattan,
|
|
57
|
-
},
|
|
58
|
-
XWalkManhattanWeighted: {
|
|
59
|
-
withinReachMetric: withinReachMetrics.XWalk,
|
|
60
|
-
distanceMetric: distanceMetrics.manhattanWeighted,
|
|
61
|
-
},
|
|
62
|
-
}
|
package/src/lib/sumBy.mts
DELETED
package/tsconfig.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"esModuleInterop": true,
|
|
4
|
-
"skipLibCheck": true,
|
|
5
|
-
"target": "es2022",
|
|
6
|
-
"allowJs": true,
|
|
7
|
-
"resolveJsonModule": true,
|
|
8
|
-
"moduleDetection": "force",
|
|
9
|
-
"isolatedModules": true,
|
|
10
|
-
"verbatimModuleSyntax": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"noUncheckedIndexedAccess": true,
|
|
13
|
-
"noImplicitOverride": true,
|
|
14
|
-
"module": "NodeNext",
|
|
15
|
-
"outDir": "dist",
|
|
16
|
-
"sourceMap": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"lib": ["es2022", "dom", "dom.iterable"]
|
|
19
|
-
}
|
|
20
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|