@remix-run/ui 0.0.0 → 0.1.1

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.
Files changed (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -2
  3. package/dist/animation/animate-layout-mixin.d.ts +12 -0
  4. package/dist/animation/animate-layout-mixin.js +214 -0
  5. package/dist/animation/animate-layout-mixin.js.map +1 -0
  6. package/dist/animation/animate-mixins.d.ts +29 -0
  7. package/dist/animation/animate-mixins.js +235 -0
  8. package/dist/animation/animate-mixins.js.map +1 -0
  9. package/dist/animation/index.d.ts +6 -0
  10. package/dist/animation/index.js +5 -0
  11. package/dist/animation/index.js.map +1 -0
  12. package/dist/animation/spring.d.ts +75 -0
  13. package/dist/animation/spring.js +183 -0
  14. package/dist/animation/spring.js.map +1 -0
  15. package/dist/animation/tween.d.ts +70 -0
  16. package/dist/animation/tween.js +93 -0
  17. package/dist/animation/tween.js.map +1 -0
  18. package/dist/components/accordion/accordion.d.ts +92 -0
  19. package/dist/components/accordion/accordion.js +337 -0
  20. package/dist/components/accordion/accordion.js.map +1 -0
  21. package/dist/components/anchor/anchor.d.ts +13 -0
  22. package/dist/components/anchor/anchor.js +558 -0
  23. package/dist/components/anchor/anchor.js.map +1 -0
  24. package/dist/components/breadcrumbs/breadcrumbs.d.ts +11 -0
  25. package/dist/components/breadcrumbs/breadcrumbs.js +78 -0
  26. package/dist/components/breadcrumbs/breadcrumbs.js.map +1 -0
  27. package/dist/components/button/button.d.ts +23 -0
  28. package/dist/components/button/button.js +147 -0
  29. package/dist/components/button/button.js.map +1 -0
  30. package/dist/components/combobox/combobox.d.ts +101 -0
  31. package/dist/components/combobox/combobox.js +708 -0
  32. package/dist/components/combobox/combobox.js.map +1 -0
  33. package/dist/components/glyph/glyph.d.ts +14 -0
  34. package/dist/components/glyph/glyph.js +65 -0
  35. package/dist/components/glyph/glyph.js.map +1 -0
  36. package/dist/components/listbox/listbox.d.ts +67 -0
  37. package/dist/components/listbox/listbox.js +340 -0
  38. package/dist/components/listbox/listbox.js.map +1 -0
  39. package/dist/components/menu/hover-aim.d.ts +5 -0
  40. package/dist/components/menu/hover-aim.js +308 -0
  41. package/dist/components/menu/hover-aim.js.map +1 -0
  42. package/dist/components/menu/menu.d.ts +164 -0
  43. package/dist/components/menu/menu.js +1106 -0
  44. package/dist/components/menu/menu.js.map +1 -0
  45. package/dist/components/popover/popover.d.ts +35 -0
  46. package/dist/components/popover/popover.js +138 -0
  47. package/dist/components/popover/popover.js.map +1 -0
  48. package/dist/components/select/select.d.ts +67 -0
  49. package/dist/components/select/select.js +397 -0
  50. package/dist/components/select/select.js.map +1 -0
  51. package/dist/components/separator/separator.d.ts +2 -0
  52. package/dist/components/separator/separator.js +15 -0
  53. package/dist/components/separator/separator.js.map +1 -0
  54. package/dist/components/tabs/tabs.d.ts +78 -0
  55. package/dist/components/tabs/tabs.js +341 -0
  56. package/dist/components/tabs/tabs.js.map +1 -0
  57. package/dist/index.d.ts +28 -0
  58. package/dist/index.js +21 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/interactions/keydown/keydown.d.ts +1 -0
  61. package/dist/interactions/keydown/keydown.js +8 -0
  62. package/dist/interactions/keydown/keydown.js.map +1 -0
  63. package/dist/interactions/outside-click/outside-click-mixin.d.ts +2 -0
  64. package/dist/interactions/outside-click/outside-click-mixin.js +29 -0
  65. package/dist/interactions/outside-click/outside-click-mixin.js.map +1 -0
  66. package/dist/interactions/typeahead/typeahead-mixin.d.ts +8 -0
  67. package/dist/interactions/typeahead/typeahead-mixin.js +59 -0
  68. package/dist/interactions/typeahead/typeahead-mixin.js.map +1 -0
  69. package/dist/jsx-runtime.d.ts +2 -0
  70. package/dist/jsx-runtime.js +3 -0
  71. package/dist/jsx-runtime.js.map +1 -0
  72. package/dist/runtime/client-entries.d.ts +91 -0
  73. package/dist/runtime/client-entries.js +40 -0
  74. package/dist/runtime/client-entries.js.map +1 -0
  75. package/dist/runtime/component.d.ts +223 -0
  76. package/dist/runtime/component.js +152 -0
  77. package/dist/runtime/component.js.map +1 -0
  78. package/dist/runtime/create-element.d.ts +10 -0
  79. package/dist/runtime/create-element.js +29 -0
  80. package/dist/runtime/create-element.js.map +1 -0
  81. package/dist/runtime/diff-dom.d.ts +2 -0
  82. package/dist/runtime/diff-dom.js +364 -0
  83. package/dist/runtime/diff-dom.js.map +1 -0
  84. package/dist/runtime/diff-props.d.ts +9 -0
  85. package/dist/runtime/diff-props.js +195 -0
  86. package/dist/runtime/diff-props.js.map +1 -0
  87. package/dist/runtime/document-state.d.ts +11 -0
  88. package/dist/runtime/document-state.js +106 -0
  89. package/dist/runtime/document-state.js.map +1 -0
  90. package/dist/runtime/dom.d.ts +3189 -0
  91. package/dist/runtime/dom.js +2 -0
  92. package/dist/runtime/dom.js.map +1 -0
  93. package/dist/runtime/error-event.d.ts +20 -0
  94. package/dist/runtime/error-event.js +19 -0
  95. package/dist/runtime/error-event.js.map +1 -0
  96. package/dist/runtime/event-listeners.d.ts +50 -0
  97. package/dist/runtime/event-listeners.js +31 -0
  98. package/dist/runtime/event-listeners.js.map +1 -0
  99. package/dist/runtime/frame.d.ts +119 -0
  100. package/dist/runtime/frame.js +920 -0
  101. package/dist/runtime/frame.js.map +1 -0
  102. package/dist/runtime/invariant.d.ts +23 -0
  103. package/dist/runtime/invariant.js +33 -0
  104. package/dist/runtime/invariant.js.map +1 -0
  105. package/dist/runtime/jsx.d.ts +320 -0
  106. package/dist/runtime/jsx.js +32 -0
  107. package/dist/runtime/jsx.js.map +1 -0
  108. package/dist/runtime/mixins/attrs-mixin.d.ts +9 -0
  109. package/dist/runtime/mixins/attrs-mixin.js +23 -0
  110. package/dist/runtime/mixins/attrs-mixin.js.map +1 -0
  111. package/dist/runtime/mixins/link-mixin.d.ts +17 -0
  112. package/dist/runtime/mixins/link-mixin.js +101 -0
  113. package/dist/runtime/mixins/link-mixin.js.map +1 -0
  114. package/dist/runtime/mixins/mixin.d.ts +145 -0
  115. package/dist/runtime/mixins/mixin.js +570 -0
  116. package/dist/runtime/mixins/mixin.js.map +1 -0
  117. package/dist/runtime/mixins/on-mixin.d.ts +16 -0
  118. package/dist/runtime/mixins/on-mixin.js +49 -0
  119. package/dist/runtime/mixins/on-mixin.js.map +1 -0
  120. package/dist/runtime/mixins/ref-mixin.d.ts +9 -0
  121. package/dist/runtime/mixins/ref-mixin.js +21 -0
  122. package/dist/runtime/mixins/ref-mixin.js.map +1 -0
  123. package/dist/runtime/navigation.d.ts +28 -0
  124. package/dist/runtime/navigation.js +107 -0
  125. package/dist/runtime/navigation.js.map +1 -0
  126. package/dist/runtime/reconcile.d.ts +11 -0
  127. package/dist/runtime/reconcile.js +1262 -0
  128. package/dist/runtime/reconcile.js.map +1 -0
  129. package/dist/runtime/render.d.ts +54 -0
  130. package/dist/runtime/render.js +50 -0
  131. package/dist/runtime/render.js.map +1 -0
  132. package/dist/runtime/run.d.ts +45 -0
  133. package/dist/runtime/run.js +68 -0
  134. package/dist/runtime/run.js.map +1 -0
  135. package/dist/runtime/scheduler.d.ts +30 -0
  136. package/dist/runtime/scheduler.js +195 -0
  137. package/dist/runtime/scheduler.js.map +1 -0
  138. package/dist/runtime/svg-attributes.d.ts +5 -0
  139. package/dist/runtime/svg-attributes.js +124 -0
  140. package/dist/runtime/svg-attributes.js.map +1 -0
  141. package/dist/runtime/to-vnode.d.ts +3 -0
  142. package/dist/runtime/to-vnode.js +46 -0
  143. package/dist/runtime/to-vnode.js.map +1 -0
  144. package/dist/runtime/typed-event-target.d.ts +50 -0
  145. package/dist/runtime/typed-event-target.js +6 -0
  146. package/dist/runtime/typed-event-target.js.map +1 -0
  147. package/dist/runtime/vdom.d.ts +55 -0
  148. package/dist/runtime/vdom.js +198 -0
  149. package/dist/runtime/vdom.js.map +1 -0
  150. package/dist/runtime/vnode.d.ts +79 -0
  151. package/dist/runtime/vnode.js +38 -0
  152. package/dist/runtime/vnode.js.map +1 -0
  153. package/dist/server/stream.d.ts +57 -0
  154. package/dist/server/stream.js +1011 -0
  155. package/dist/server/stream.js.map +1 -0
  156. package/dist/style/css-mixin.d.ts +8 -0
  157. package/dist/style/css-mixin.js +54 -0
  158. package/dist/style/css-mixin.js.map +1 -0
  159. package/dist/style/index.d.ts +5 -0
  160. package/dist/style/index.js +4 -0
  161. package/dist/style/index.js.map +1 -0
  162. package/dist/style/style.d.ts +24 -0
  163. package/dist/style/style.js +269 -0
  164. package/dist/style/style.js.map +1 -0
  165. package/dist/style/stylesheet.d.ts +11 -0
  166. package/dist/style/stylesheet.js +174 -0
  167. package/dist/style/stylesheet.js.map +1 -0
  168. package/dist/test.d.ts +2 -0
  169. package/dist/test.js +2 -0
  170. package/dist/test.js.map +1 -0
  171. package/dist/theme/contract.d.ts +259 -0
  172. package/dist/theme/contract.js +131 -0
  173. package/dist/theme/contract.js.map +1 -0
  174. package/dist/theme/glyph-contract.d.ts +13 -0
  175. package/dist/theme/glyph-contract.js +34 -0
  176. package/dist/theme/glyph-contract.js.map +1 -0
  177. package/dist/theme/presets/rmx-01/glyphs.d.ts +2 -0
  178. package/dist/theme/presets/rmx-01/glyphs.js +252 -0
  179. package/dist/theme/presets/rmx-01/glyphs.js.map +1 -0
  180. package/dist/theme/presets/rmx-01/index.d.ts +2 -0
  181. package/dist/theme/presets/rmx-01/index.js +119 -0
  182. package/dist/theme/presets/rmx-01/index.js.map +1 -0
  183. package/dist/theme/runtime.d.ts +2 -0
  184. package/dist/theme/runtime.js +81 -0
  185. package/dist/theme/runtime.js.map +1 -0
  186. package/dist/theme/theme.d.ts +6 -0
  187. package/dist/theme/theme.js +5 -0
  188. package/dist/theme/theme.js.map +1 -0
  189. package/dist/utils/flash-attribute.d.ts +1 -0
  190. package/dist/utils/flash-attribute.js +11 -0
  191. package/dist/utils/flash-attribute.js.map +1 -0
  192. package/dist/utils/scroll-lock.d.ts +3 -0
  193. package/dist/utils/scroll-lock.js +69 -0
  194. package/dist/utils/scroll-lock.js.map +1 -0
  195. package/dist/utils/wait-for-css-transition.d.ts +1 -0
  196. package/dist/utils/wait-for-css-transition.js +58 -0
  197. package/dist/utils/wait-for-css-transition.js.map +1 -0
  198. package/dist/utils/wait.d.ts +1 -0
  199. package/dist/utils/wait.js +6 -0
  200. package/dist/utils/wait.js.map +1 -0
  201. package/package.json +124 -5
  202. package/src/animation/animate-layout-mixin.ts +266 -0
  203. package/src/animation/animate-mixins.ts +292 -0
  204. package/src/animation/index.ts +6 -0
  205. package/src/animation/spring.ts +299 -0
  206. package/src/animation/tween.ts +134 -0
  207. package/src/components/accordion/accordion.tsx +565 -0
  208. package/src/components/anchor/anchor.ts +904 -0
  209. package/src/components/breadcrumbs/breadcrumbs.tsx +124 -0
  210. package/src/components/button/README.md +44 -0
  211. package/src/components/button/button.tsx +188 -0
  212. package/src/components/combobox/README.md +145 -0
  213. package/src/components/combobox/combobox.tsx +1014 -0
  214. package/src/components/glyph/glyph.tsx +110 -0
  215. package/src/components/listbox/listbox.ts +447 -0
  216. package/src/components/menu/hover-aim.ts +428 -0
  217. package/src/components/menu/menu.tsx +1547 -0
  218. package/src/components/popover/README.md +122 -0
  219. package/src/components/popover/popover.ts +201 -0
  220. package/src/components/select/select.tsx +585 -0
  221. package/src/components/separator/separator.ts +19 -0
  222. package/src/components/tabs/README.md +105 -0
  223. package/src/components/tabs/tabs.tsx +499 -0
  224. package/src/index.ts +72 -0
  225. package/src/interactions/keydown/keydown.ts +14 -0
  226. package/src/interactions/outside-click/outside-click-mixin.ts +55 -0
  227. package/src/interactions/typeahead/typeahead-mixin.ts +89 -0
  228. package/src/jsx-runtime.ts +2 -0
  229. package/src/runtime/client-entries.ts +137 -0
  230. package/src/runtime/component.ts +402 -0
  231. package/src/runtime/create-element.ts +38 -0
  232. package/src/runtime/diff-dom.ts +404 -0
  233. package/src/runtime/diff-props.ts +209 -0
  234. package/src/runtime/document-state.ts +130 -0
  235. package/src/runtime/dom.ts +3971 -0
  236. package/src/runtime/error-event.ts +26 -0
  237. package/src/runtime/event-listeners.ts +171 -0
  238. package/src/runtime/frame.ts +1218 -0
  239. package/src/runtime/invariant.ts +31 -0
  240. package/src/runtime/jsx.ts +397 -0
  241. package/src/runtime/mixins/attrs-mixin.ts +35 -0
  242. package/src/runtime/mixins/link-mixin.ts +131 -0
  243. package/src/runtime/mixins/mixin.ts +908 -0
  244. package/src/runtime/mixins/on-mixin.ts +89 -0
  245. package/src/runtime/mixins/ref-mixin.ts +32 -0
  246. package/src/runtime/navigation.ts +148 -0
  247. package/src/runtime/reconcile.ts +1757 -0
  248. package/src/runtime/render.ts +101 -0
  249. package/src/runtime/run.ts +100 -0
  250. package/src/runtime/scheduler.ts +269 -0
  251. package/src/runtime/svg-attributes.ts +133 -0
  252. package/src/runtime/to-vnode.ts +51 -0
  253. package/src/runtime/typed-event-target.ts +67 -0
  254. package/src/runtime/vdom.ts +295 -0
  255. package/src/runtime/vnode.ts +137 -0
  256. package/src/server/stream.ts +1347 -0
  257. package/src/style/css-mixin.ts +82 -0
  258. package/src/style/index.ts +10 -0
  259. package/src/style/style.ts +312 -0
  260. package/src/style/stylesheet.ts +209 -0
  261. package/src/test/utils.ts +45 -0
  262. package/src/test.ts +2 -0
  263. package/src/theme/contract.ts +183 -0
  264. package/src/theme/glyph-contract.ts +57 -0
  265. package/src/theme/presets/rmx-01/glyphs.tsx +308 -0
  266. package/src/theme/presets/rmx-01/index.ts +121 -0
  267. package/src/theme/runtime.ts +116 -0
  268. package/src/theme/theme.ts +15 -0
  269. package/src/utils/flash-attribute.ts +11 -0
  270. package/src/utils/scroll-lock.ts +97 -0
  271. package/src/utils/wait-for-css-transition.ts +66 -0
  272. package/src/utils/wait.ts +5 -0
@@ -0,0 +1,428 @@
1
+ export interface HoverAim {
2
+ start(
3
+ source: HTMLElement,
4
+ target: HTMLElement,
5
+ event?: PointerEvent,
6
+ onExpire?: () => void,
7
+ ): boolean
8
+ accepts(event: PointerEvent): boolean
9
+ }
10
+
11
+ type Point = {
12
+ x: number
13
+ y: number
14
+ }
15
+
16
+ type Rect = {
17
+ left: number
18
+ top: number
19
+ right: number
20
+ bottom: number
21
+ }
22
+
23
+ type Session = {
24
+ target: HTMLElement
25
+ actualRect: Rect
26
+ polygon: Point[]
27
+ startedAt: number
28
+ lastDistance: number
29
+ lastPoint: Point
30
+ durationTimeoutId: number
31
+ stalledUpdates: number
32
+ stallTimeoutId: number
33
+ onExpire?: () => void
34
+ }
35
+
36
+ const HOVER_AIM_PADDING = 8
37
+ const HOVER_AIM_MAX_DURATION = 300
38
+ const HOVER_AIM_STALL_DURATION = 120
39
+ const HOVER_AIM_MIN_PROGRESS = 0.5
40
+ const HOVER_AIM_MAX_STALLED_UPDATES = 2
41
+
42
+ export function createHoverAim(): HoverAim {
43
+ let lastPointer: Point | null = null
44
+ let session: Session | null = null
45
+ let pointerTrackingActive = false
46
+ let processedEvents = new WeakMap<PointerEvent, boolean>()
47
+
48
+ function handleDocumentPointerMove(event: Event) {
49
+ accepts(event as PointerEvent)
50
+ }
51
+
52
+ function startPointerTracking() {
53
+ if (pointerTrackingActive) {
54
+ return
55
+ }
56
+
57
+ document.addEventListener('pointermove', handleDocumentPointerMove, { capture: true })
58
+ pointerTrackingActive = true
59
+ }
60
+
61
+ function stopPointerTracking() {
62
+ if (!pointerTrackingActive) {
63
+ return
64
+ }
65
+
66
+ document.removeEventListener('pointermove', handleDocumentPointerMove, { capture: true })
67
+ pointerTrackingActive = false
68
+ }
69
+
70
+ function clearSession(reason: string, currentSession: Session | null = session) {
71
+ if (!currentSession) {
72
+ return
73
+ }
74
+
75
+ clearTimeout(currentSession.durationTimeoutId)
76
+ clearTimeout(currentSession.stallTimeoutId)
77
+
78
+ if (session === currentSession) {
79
+ session = null
80
+ }
81
+
82
+ stopPointerTracking()
83
+
84
+ if (reason === 'duration-timeout' || reason === 'stall-timeout') {
85
+ currentSession.onExpire?.()
86
+ }
87
+ }
88
+
89
+ function scheduleDurationTimeout(currentSession: Session) {
90
+ currentSession.durationTimeoutId = window.setTimeout(() => {
91
+ clearSession('duration-timeout', currentSession)
92
+ }, HOVER_AIM_MAX_DURATION)
93
+ }
94
+
95
+ function scheduleStallTimeout(currentSession: Session) {
96
+ clearTimeout(currentSession.stallTimeoutId)
97
+ currentSession.stallTimeoutId = window.setTimeout(() => {
98
+ clearSession('stall-timeout', currentSession)
99
+ }, HOVER_AIM_STALL_DURATION)
100
+ }
101
+
102
+ function rememberPointer(event: PointerEvent) {
103
+ if (!isMousePointer(event)) {
104
+ return
105
+ }
106
+
107
+ lastPointer = getPoint(event)
108
+ }
109
+
110
+ function start(
111
+ source: HTMLElement,
112
+ target: HTMLElement,
113
+ event?: PointerEvent,
114
+ onExpire?: () => void,
115
+ ) {
116
+ clearSession('restart')
117
+
118
+ if (event && !isMousePointer(event)) {
119
+ return false
120
+ }
121
+
122
+ if (!source.isConnected || !target.isConnected) {
123
+ return false
124
+ }
125
+
126
+ let startPoint = event ? getPoint(event) : lastPointer
127
+ if (!startPoint) {
128
+ return false
129
+ }
130
+
131
+ if (event?.relatedTarget instanceof Node && target.contains(event.relatedTarget)) {
132
+ lastPointer = startPoint
133
+ return true
134
+ }
135
+
136
+ let sourceRect = toRect(source.getBoundingClientRect())
137
+ let actualRect = toRect(target.getBoundingClientRect())
138
+ if (
139
+ isEmptyRect(sourceRect) ||
140
+ isEmptyRect(actualRect) ||
141
+ containsPoint(actualRect, startPoint) ||
142
+ !isHeadingTowardTarget(sourceRect, actualRect, startPoint)
143
+ ) {
144
+ return false
145
+ }
146
+
147
+ lastPointer = startPoint
148
+
149
+ let paddedRect = inflateRect(actualRect, HOVER_AIM_PADDING)
150
+ let currentSession: Session = {
151
+ target,
152
+ actualRect,
153
+ polygon: createCorridor(startPoint, paddedRect),
154
+ startedAt: Date.now(),
155
+ lastDistance: distanceToRect(startPoint, actualRect),
156
+ lastPoint: startPoint,
157
+ durationTimeoutId: 0,
158
+ stalledUpdates: 0,
159
+ stallTimeoutId: 0,
160
+ onExpire,
161
+ }
162
+
163
+ session = currentSession
164
+ startPointerTracking()
165
+ scheduleDurationTimeout(currentSession)
166
+ scheduleStallTimeout(currentSession)
167
+ return true
168
+ }
169
+
170
+ function accepts(event: PointerEvent) {
171
+ if (processedEvents.has(event)) {
172
+ return processedEvents.get(event) as boolean
173
+ }
174
+
175
+ rememberPointer(event)
176
+
177
+ let currentSession = session
178
+ if (!currentSession) {
179
+ processedEvents.set(event, true)
180
+ return true
181
+ }
182
+
183
+ if (!isMousePointer(event) || event.type !== 'pointermove') {
184
+ clearSession('non-pointermove', currentSession)
185
+ processedEvents.set(event, true)
186
+ return true
187
+ }
188
+
189
+ if (!currentSession.target.isConnected) {
190
+ clearSession('target-disconnected', currentSession)
191
+ processedEvents.set(event, true)
192
+ return true
193
+ }
194
+
195
+ let point = getPoint(event)
196
+ if (enteredTarget(currentSession, point, event.target)) {
197
+ clearSession('entered-target', currentSession)
198
+ processedEvents.set(event, true)
199
+ return true
200
+ }
201
+
202
+ if (!pointInPolygon(point, currentSession.polygon)) {
203
+ clearSession('outside-corridor', currentSession)
204
+ processedEvents.set(event, true)
205
+ return true
206
+ }
207
+
208
+ if (distanceBetweenPoints(currentSession.lastPoint, point) > 0) {
209
+ scheduleStallTimeout(currentSession)
210
+ }
211
+
212
+ let nextDistance = distanceToRect(point, currentSession.actualRect)
213
+ if (currentSession.lastDistance - nextDistance >= HOVER_AIM_MIN_PROGRESS) {
214
+ currentSession.stalledUpdates = 0
215
+ } else {
216
+ currentSession.stalledUpdates++
217
+ }
218
+
219
+ currentSession.lastPoint = point
220
+ currentSession.lastDistance = nextDistance
221
+
222
+ if (currentSession.stalledUpdates >= HOVER_AIM_MAX_STALLED_UPDATES) {
223
+ clearSession('stalled-updates', currentSession)
224
+ processedEvents.set(event, true)
225
+ return true
226
+ }
227
+
228
+ if (Date.now() - currentSession.startedAt >= HOVER_AIM_MAX_DURATION) {
229
+ clearSession('max-duration', currentSession)
230
+ processedEvents.set(event, true)
231
+ return true
232
+ }
233
+
234
+ processedEvents.set(event, false)
235
+ return false
236
+ }
237
+ return { start, accepts }
238
+ }
239
+
240
+ function isMousePointer(event: PointerEvent) {
241
+ return (
242
+ event.pointerType === undefined || event.pointerType === '' || event.pointerType === 'mouse'
243
+ )
244
+ }
245
+
246
+ function getPoint(event: PointerEvent): Point {
247
+ return {
248
+ x: event.clientX,
249
+ y: event.clientY,
250
+ }
251
+ }
252
+
253
+ function toRect(rect: DOMRectReadOnly): Rect {
254
+ return {
255
+ left: rect.left,
256
+ top: rect.top,
257
+ right: rect.right,
258
+ bottom: rect.bottom,
259
+ }
260
+ }
261
+
262
+ function isEmptyRect(rect: Rect) {
263
+ return rect.left === rect.right || rect.top === rect.bottom
264
+ }
265
+
266
+ function inflateRect(rect: Rect, padding: number): Rect {
267
+ return {
268
+ left: rect.left - padding,
269
+ top: rect.top - padding,
270
+ right: rect.right + padding,
271
+ bottom: rect.bottom + padding,
272
+ }
273
+ }
274
+
275
+ function containsPoint(rect: Rect, point: Point) {
276
+ return (
277
+ point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom
278
+ )
279
+ }
280
+
281
+ function isHeadingTowardTarget(sourceRect: Rect, targetRect: Rect, point: Point) {
282
+ let sourceCenterX = sourceRect.left + (sourceRect.right - sourceRect.left) / 2
283
+ let sourceCenterY = sourceRect.top + (sourceRect.bottom - sourceRect.top) / 2
284
+ let targetCenterX = targetRect.left + (targetRect.right - targetRect.left) / 2
285
+ let targetCenterY = targetRect.top + (targetRect.bottom - targetRect.top) / 2
286
+ let deltaX = targetCenterX - sourceCenterX
287
+ let deltaY = targetCenterY - sourceCenterY
288
+
289
+ if (Math.abs(deltaX) >= Math.abs(deltaY)) {
290
+ return deltaX >= 0 ? point.x >= sourceCenterX : point.x <= sourceCenterX
291
+ }
292
+
293
+ return deltaY >= 0 ? point.y >= sourceCenterY : point.y <= sourceCenterY
294
+ }
295
+
296
+ function enteredTarget(session: Session, point: Point, eventTarget: EventTarget | null) {
297
+ if (containsPoint(session.actualRect, point)) {
298
+ return true
299
+ }
300
+
301
+ return eventTarget instanceof Node && session.target.contains(eventTarget)
302
+ }
303
+
304
+ function distanceBetweenPoints(from: Point, to: Point) {
305
+ return Math.hypot(to.x - from.x, to.y - from.y)
306
+ }
307
+
308
+ function distanceToRect(point: Point, rect: Rect) {
309
+ let dx = 0
310
+ let dy = 0
311
+
312
+ if (point.x < rect.left) {
313
+ dx = rect.left - point.x
314
+ } else if (point.x > rect.right) {
315
+ dx = point.x - rect.right
316
+ }
317
+
318
+ if (point.y < rect.top) {
319
+ dy = rect.top - point.y
320
+ } else if (point.y > rect.bottom) {
321
+ dy = point.y - rect.bottom
322
+ }
323
+
324
+ return Math.hypot(dx, dy)
325
+ }
326
+
327
+ function createCorridor(startPoint: Point, rect: Rect) {
328
+ let points = dedupePoints([
329
+ startPoint,
330
+ { x: rect.left, y: rect.top },
331
+ { x: rect.right, y: rect.top },
332
+ { x: rect.right, y: rect.bottom },
333
+ { x: rect.left, y: rect.bottom },
334
+ ])
335
+
336
+ if (points.length <= 2) {
337
+ return points
338
+ }
339
+
340
+ points.sort((left, right) => {
341
+ if (left.x === right.x) {
342
+ return left.y - right.y
343
+ }
344
+
345
+ return left.x - right.x
346
+ })
347
+
348
+ let lower: Point[] = []
349
+ for (let point of points) {
350
+ while (
351
+ lower.length >= 2 &&
352
+ crossProduct(lower[lower.length - 2], lower[lower.length - 1], point) <= 0
353
+ ) {
354
+ lower.pop()
355
+ }
356
+ lower.push(point)
357
+ }
358
+
359
+ let upper: Point[] = []
360
+ for (let index = points.length - 1; index >= 0; index--) {
361
+ let point = points[index]
362
+ while (
363
+ upper.length >= 2 &&
364
+ crossProduct(upper[upper.length - 2], upper[upper.length - 1], point) <= 0
365
+ ) {
366
+ upper.pop()
367
+ }
368
+ upper.push(point)
369
+ }
370
+
371
+ return lower.slice(0, -1).concat(upper.slice(0, -1))
372
+ }
373
+
374
+ function crossProduct(origin: Point, a: Point, b: Point) {
375
+ return (a.x - origin.x) * (b.y - origin.y) - (a.y - origin.y) * (b.x - origin.x)
376
+ }
377
+
378
+ function dedupePoints(points: Point[]) {
379
+ let seen = new Set<string>()
380
+ return points.filter((point) => {
381
+ let key = `${point.x}:${point.y}`
382
+ if (seen.has(key)) {
383
+ return false
384
+ }
385
+
386
+ seen.add(key)
387
+ return true
388
+ })
389
+ }
390
+
391
+ function pointInPolygon(point: Point, polygon: Point[]) {
392
+ if (polygon.length < 3) {
393
+ return false
394
+ }
395
+
396
+ let inside = false
397
+
398
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
399
+ if (pointOnSegment(point, polygon[j], polygon[i])) {
400
+ return true
401
+ }
402
+
403
+ if (
404
+ polygon[i].y > point.y !== polygon[j].y > point.y &&
405
+ point.x <
406
+ ((polygon[j].x - polygon[i].x) * (point.y - polygon[i].y)) / (polygon[j].y - polygon[i].y) +
407
+ polygon[i].x
408
+ ) {
409
+ inside = !inside
410
+ }
411
+ }
412
+
413
+ return inside
414
+ }
415
+
416
+ function pointOnSegment(point: Point, start: Point, end: Point) {
417
+ let cross = crossProduct(start, end, point)
418
+ if (Math.abs(cross) > 0.001) {
419
+ return false
420
+ }
421
+
422
+ return (
423
+ point.x >= Math.min(start.x, end.x) &&
424
+ point.x <= Math.max(start.x, end.x) &&
425
+ point.y >= Math.min(start.y, end.y) &&
426
+ point.y <= Math.max(start.y, end.y)
427
+ )
428
+ }