@inglorious/web 6.0.1 → 6.1.0
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 +9 -9
- package/README.md +138 -9
- package/package.json +5 -1
- package/src/compass/handlers.js +206 -0
- package/src/compass/index.js +3 -0
- package/src/geolocation/handlers.js +27 -27
- package/types/compass.d.ts +44 -0
- package/types/geolocation.d.ts +4 -2
package/LICENSE
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright © 2025 Inglorious Coderz Srl.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
-
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 Inglorious Coderz Srl.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A lightweight, reactive-enough web framework built on **pure JavaScript**, the e
|
|
|
7
7
|
|
|
8
8
|
Unlike modern frameworks that invent their own languages or rely on signals, proxies, or compilers, **@inglorious/web embraces plain JavaScript** and a transparent architecture.
|
|
9
9
|
|
|
10
|
-
It's a **complete framework**: it ships with a client-side router, declarative forms, geolocation state, async helpers (via `@inglorious/store/async`), and a dedicated testing utilities entry point (`@inglorious/web/test`) that re-exports `trigger` from `@inglorious/store` and `render` from `lit-html`. UI primitives (controls, data display, navigation, feedback, layout, surfaces) live in the companion package **[Inglorious UI](https://inglorious.dev/ui)**.
|
|
10
|
+
It's a **complete framework**: it ships with a client-side router, declarative forms, geolocation and compass state, async helpers (via `@inglorious/store/async`), and a dedicated testing utilities entry point (`@inglorious/web/test`) that re-exports `trigger` from `@inglorious/store` and `render` from `lit-html`. UI primitives (controls, data display, navigation, feedback, layout, surfaces) live in the companion package **[Inglorious UI](https://inglorious.dev/ui)**.
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -28,10 +28,10 @@ It's a **complete framework**: it ships with a client-side router, declarative f
|
|
|
28
28
|
Zero magic, zero reactivity graphs, zero compiler.
|
|
29
29
|
Just JavaScript functions and store events.
|
|
30
30
|
|
|
31
|
-
- **Router, Forms, Geolocation, Async, Testing utilities**
|
|
31
|
+
- **Router, Forms, Geolocation, Compass, Async, Testing utilities**
|
|
32
32
|
High-level primitives built on the same predictable model. UI primitives (tables, virtual lists, comboboxes, and more) live in **[Inglorious UI](https://inglorious.dev/ui)**.
|
|
33
33
|
|
|
34
|
-
- **Zero Component State**
|
|
34
|
+
- **Zero Component State**
|
|
35
35
|
All state lives in the store — never inside components.
|
|
36
36
|
|
|
37
37
|
- **No Signals, No Subscriptions, No Framework-Level Memory Leaks**
|
|
@@ -1259,18 +1259,145 @@ The entity state contains:
|
|
|
1259
1259
|
|
|
1260
1260
|
Events:
|
|
1261
1261
|
|
|
1262
|
-
-
|
|
1263
|
-
-
|
|
1264
|
-
-
|
|
1262
|
+
- `geolocationRequest` — request the current position
|
|
1263
|
+
- `geolocationWatch` — start watching position changes
|
|
1264
|
+
- `geolocationUnwatch` — stop the active watch
|
|
1265
1265
|
|
|
1266
1266
|
```javascript
|
|
1267
|
-
api.notify("
|
|
1267
|
+
api.notify("geolocationRequest", {
|
|
1268
1268
|
enableHighAccuracy: true,
|
|
1269
1269
|
timeout: 5000,
|
|
1270
1270
|
})
|
|
1271
1271
|
|
|
1272
|
-
api.notify("
|
|
1273
|
-
api.notify("
|
|
1272
|
+
api.notify("geolocationWatch")
|
|
1273
|
+
api.notify("geolocationUnwatch")
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1276
|
+
### Example: Show current location
|
|
1277
|
+
|
|
1278
|
+
```javascript
|
|
1279
|
+
import { mount, html } from "@inglorious/web"
|
|
1280
|
+
import { store } from "./store.js"
|
|
1281
|
+
|
|
1282
|
+
const renderApp = (api) => {
|
|
1283
|
+
const geolocation = api.getEntity("geolocation")
|
|
1284
|
+
const position = geolocation.position
|
|
1285
|
+
|
|
1286
|
+
return html`
|
|
1287
|
+
<section>
|
|
1288
|
+
<h2>Geolocation</h2>
|
|
1289
|
+
<p>Supported: ${geolocation.isSupported ? "yes" : "no"}</p>
|
|
1290
|
+
<p>Loading: ${geolocation.isLoading ? "yes" : "no"}</p>
|
|
1291
|
+
<p>
|
|
1292
|
+
Position:
|
|
1293
|
+
${position
|
|
1294
|
+
? html`${position.coords.latitude.toFixed(4)},
|
|
1295
|
+
${position.coords.longitude.toFixed(4)}`
|
|
1296
|
+
: "unknown"}
|
|
1297
|
+
</p>
|
|
1298
|
+
<p>Error: ${geolocation.error ? geolocation.error.message : "none"}</p>
|
|
1299
|
+
<button
|
|
1300
|
+
@click=${() =>
|
|
1301
|
+
api.notify("geolocationRequest", {
|
|
1302
|
+
enableHighAccuracy: true,
|
|
1303
|
+
timeout: 5000,
|
|
1304
|
+
})}
|
|
1305
|
+
>
|
|
1306
|
+
Request Current Position
|
|
1307
|
+
</button>
|
|
1308
|
+
<button @click=${() => api.notify("geolocationWatch")}>
|
|
1309
|
+
Start Watch
|
|
1310
|
+
</button>
|
|
1311
|
+
<button @click=${() => api.notify("geolocationUnwatch")}>
|
|
1312
|
+
Stop Watch
|
|
1313
|
+
</button>
|
|
1314
|
+
</section>
|
|
1315
|
+
`
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
mount(store, renderApp, document.getElementById("root"))
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1321
|
+
---
|
|
1322
|
+
|
|
1323
|
+
## Compass
|
|
1324
|
+
|
|
1325
|
+
`@inglorious/web` also includes a `Compass` type for managing device orientation and heading state inside the store.
|
|
1326
|
+
|
|
1327
|
+
```javascript
|
|
1328
|
+
import { createStore } from "@inglorious/store"
|
|
1329
|
+
import { Compass } from "@inglorious/web/compass"
|
|
1330
|
+
|
|
1331
|
+
const store = createStore({
|
|
1332
|
+
types: { Compass },
|
|
1333
|
+
autoCreateEntities: true,
|
|
1334
|
+
})
|
|
1335
|
+
|
|
1336
|
+
// The store now contains a `compass` entity.
|
|
1337
|
+
store.getState().compass
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
The entity state contains:
|
|
1341
|
+
|
|
1342
|
+
- `isSupported` — whether device orientation sensors are available
|
|
1343
|
+
- `isLoading` — whether permissions or heading data are pending
|
|
1344
|
+
- `isCompassPermissionGranted` — whether compass permission has been granted
|
|
1345
|
+
- `isCompassActive` — whether a valid heading is currently active
|
|
1346
|
+
- `heading` — the latest heading in degrees, or `null`
|
|
1347
|
+
- `error` — the latest normalized `{ code, message }` error
|
|
1348
|
+
- `manualOffset` — a heading offset in degrees to apply to raw sensor values
|
|
1349
|
+
|
|
1350
|
+
Events:
|
|
1351
|
+
|
|
1352
|
+
- `compassPermissionsRequest` — request compass permission when needed
|
|
1353
|
+
- `compassWatch` — start listening for device orientation events
|
|
1354
|
+
- `compassUnwatch` — stop listening for device orientation events
|
|
1355
|
+
- `compassPermissionsGrant` — set permission granted
|
|
1356
|
+
- `compassActiveChange` — update active/inactive state
|
|
1357
|
+
- `compassHeadingChange` — update the latest heading
|
|
1358
|
+
- `compassError` — store a normalized compass error
|
|
1359
|
+
|
|
1360
|
+
```javascript
|
|
1361
|
+
api.notify("compassPermissionsRequest")
|
|
1362
|
+
api.notify("compassWatch")
|
|
1363
|
+
api.notify("compassUnwatch")
|
|
1364
|
+
```
|
|
1365
|
+
|
|
1366
|
+
### Example: Show heading and request permission
|
|
1367
|
+
|
|
1368
|
+
```javascript
|
|
1369
|
+
import { mount, html } from "@inglorious/web"
|
|
1370
|
+
import { store } from "./store.js"
|
|
1371
|
+
|
|
1372
|
+
const renderApp = (api) => {
|
|
1373
|
+
const compass = api.getEntity("compass")
|
|
1374
|
+
|
|
1375
|
+
return html`
|
|
1376
|
+
<section>
|
|
1377
|
+
<h2>Compass</h2>
|
|
1378
|
+
<p>Supported: ${compass.isSupported ? "yes" : "no"}</p>
|
|
1379
|
+
<p>
|
|
1380
|
+
Permission:
|
|
1381
|
+
${compass.isCompassPermissionGranted ? "granted" : "unknown"}
|
|
1382
|
+
</p>
|
|
1383
|
+
<p>Active: ${compass.isCompassActive ? "yes" : "no"}</p>
|
|
1384
|
+
<p>
|
|
1385
|
+
Heading:
|
|
1386
|
+
${compass.heading !== null
|
|
1387
|
+
? `${compass.heading.toFixed(1)}°`
|
|
1388
|
+
: "unknown"}
|
|
1389
|
+
</p>
|
|
1390
|
+
<p>Error: ${compass.error ? compass.error.message : "none"}</p>
|
|
1391
|
+
<button @click=${() => api.notify("compassPermissionsRequest")}>
|
|
1392
|
+
Request Permission
|
|
1393
|
+
</button>
|
|
1394
|
+
<button @click=${() => api.notify("compassWatch")}>Start Compass</button>
|
|
1395
|
+
<button @click=${() => api.notify("compassUnwatch")}>Stop Compass</button>
|
|
1396
|
+
</section>
|
|
1397
|
+
`
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
mount(store, renderApp, document.getElementById("root"))
|
|
1274
1401
|
```
|
|
1275
1402
|
|
|
1276
1403
|
---
|
|
@@ -1621,6 +1748,8 @@ import { render, trigger } from "@inglorious/web/test"
|
|
|
1621
1748
|
|
|
1622
1749
|
import { Form } from "@inglorious/web/form"
|
|
1623
1750
|
import { Router, setRoutes } from "@inglorious/web/router"
|
|
1751
|
+
import { Geolocation } from "@inglorious/web/geolocation"
|
|
1752
|
+
import { Compass } from "@inglorious/web/compass"
|
|
1624
1753
|
```
|
|
1625
1754
|
|
|
1626
1755
|
This keeps `lit-html` as an internal implementation detail while still giving applications stable, tree-shakeable import paths.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/web",
|
|
3
|
-
"version": "6.0
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"description": "A new web framework that leverages the power of the Inglorious Store combined with the performance and simplicity of lit-html.",
|
|
5
5
|
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
"types": "./types/index.d.ts",
|
|
27
27
|
"import": "./src/index.js"
|
|
28
28
|
},
|
|
29
|
+
"./compass": {
|
|
30
|
+
"types": "./types/compass.d.ts",
|
|
31
|
+
"import": "./src/compass/index.js"
|
|
32
|
+
},
|
|
29
33
|
"./directives/*": {
|
|
30
34
|
"types": "./types/directives/*.d.ts",
|
|
31
35
|
"import": "./src/directives/*.js"
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("../../types/compass.js").CompassEntity} CompassEntity
|
|
3
|
+
* @typedef {import("../../types/compass.js").CompassError} CompassError
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const COMPASS_TIMEOUT = 3000
|
|
7
|
+
const NO_TIMEOUT = null
|
|
8
|
+
|
|
9
|
+
const FULL_CIRCLE = 360
|
|
10
|
+
const DEFAULT_ORIENTATION = 0
|
|
11
|
+
const DEFAULT_ERROR_CODE = 0
|
|
12
|
+
|
|
13
|
+
export function create(entity) {
|
|
14
|
+
entity.error ??= null
|
|
15
|
+
entity.heading ??= null
|
|
16
|
+
entity.isCompassActive ??= false
|
|
17
|
+
entity.isCompassPermissionGranted ??= false
|
|
18
|
+
entity.isLoading ??= false
|
|
19
|
+
entity.isSupported = isCompassSupported()
|
|
20
|
+
entity.manualOffset ??= 0
|
|
21
|
+
entity._absoluteListener ??= null
|
|
22
|
+
entity._orientationListener ??= null
|
|
23
|
+
// True once a deviceorientationabsolute event fires; used to drop the
|
|
24
|
+
// fallback deviceorientation listener so only one path updates heading.
|
|
25
|
+
entity._isUsingAbsolute ??= false
|
|
26
|
+
entity.compassTimeout ??= NO_TIMEOUT
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function destroy(entity) {
|
|
30
|
+
compassUnwatch(entity)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function compassUnwatch(entity) {
|
|
34
|
+
const win = getWindow()
|
|
35
|
+
|
|
36
|
+
if (entity._orientationListener && win) {
|
|
37
|
+
win.removeEventListener("deviceorientation", entity._orientationListener)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (entity._absoluteListener && win) {
|
|
41
|
+
win.removeEventListener(
|
|
42
|
+
"deviceorientationabsolute",
|
|
43
|
+
entity._absoluteListener,
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (entity.compassTimeout !== NO_TIMEOUT) {
|
|
48
|
+
clearTimeout(entity.compassTimeout)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
entity.isLoading = false
|
|
52
|
+
entity.isCompassActive = false
|
|
53
|
+
entity.compassTimeout = NO_TIMEOUT
|
|
54
|
+
entity._orientationListener = null
|
|
55
|
+
entity._absoluteListener = null
|
|
56
|
+
entity._isUsingAbsolute = false
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function compassError(entity, error) {
|
|
60
|
+
entity.error = normalizeError(error)
|
|
61
|
+
entity.isLoading = false
|
|
62
|
+
entity.isCompassPermissionGranted = false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function compassPermissionsRequest(entity, _, api) {
|
|
66
|
+
entity.isSupported = isCompassSupported()
|
|
67
|
+
entity.error = null
|
|
68
|
+
|
|
69
|
+
if (!entity.isSupported) {
|
|
70
|
+
entity.isLoading = false
|
|
71
|
+
api.notify("compassError", createUnsupportedError())
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
entity.isLoading = true
|
|
76
|
+
|
|
77
|
+
if (
|
|
78
|
+
typeof DeviceOrientationEvent !== "undefined" &&
|
|
79
|
+
typeof DeviceOrientationEvent.requestPermission === "function"
|
|
80
|
+
) {
|
|
81
|
+
try {
|
|
82
|
+
const permission = await DeviceOrientationEvent.requestPermission()
|
|
83
|
+
if (permission === "granted") {
|
|
84
|
+
api.notify("compassPermissionsGrant")
|
|
85
|
+
} else {
|
|
86
|
+
entity.isLoading = false
|
|
87
|
+
api.notify("compassError", createPermissionDeniedError())
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
entity.isLoading = false
|
|
91
|
+
api.notify("compassError", normalizeError(error))
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
api.notify("compassPermissionsGrant")
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function compassPermissionsGrant(entity) {
|
|
99
|
+
entity.isLoading = false
|
|
100
|
+
entity.isCompassPermissionGranted = true
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function compassWatch(entity, _, api) {
|
|
104
|
+
entity._isUsingAbsolute = false
|
|
105
|
+
|
|
106
|
+
const orientationListener = createOrientationChangeListener(entity, api)
|
|
107
|
+
const absoluteListener = (event) => {
|
|
108
|
+
if (!entity._isUsingAbsolute) {
|
|
109
|
+
entity._isUsingAbsolute = true
|
|
110
|
+
getWindow()?.removeEventListener("deviceorientation", orientationListener)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
orientationListener(event)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
entity._orientationListener = orientationListener
|
|
117
|
+
entity._absoluteListener = absoluteListener
|
|
118
|
+
|
|
119
|
+
const win = getWindow()
|
|
120
|
+
win?.addEventListener("deviceorientationabsolute", absoluteListener)
|
|
121
|
+
win?.addEventListener("deviceorientation", orientationListener)
|
|
122
|
+
|
|
123
|
+
entity.compassTimeout = globalThis.setTimeout(
|
|
124
|
+
() => checkTimeout(entity, api),
|
|
125
|
+
COMPASS_TIMEOUT,
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function checkTimeout(entity, api) {
|
|
130
|
+
entity.compassTimeout = NO_TIMEOUT
|
|
131
|
+
|
|
132
|
+
if (!entity.heading) {
|
|
133
|
+
api.notify("compassActiveChange", false)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function compassActiveChange(entity, value) {
|
|
138
|
+
entity.isCompassActive = value
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function compassHeadingChange(entity, value) {
|
|
142
|
+
entity.isLoading = false
|
|
143
|
+
entity.heading = value
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function createOrientationChangeListener(entity, api) {
|
|
147
|
+
return (event) => {
|
|
148
|
+
const heading = event?.alpha
|
|
149
|
+
if (typeof heading !== "number") {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (entity.compassTimeout !== NO_TIMEOUT) {
|
|
154
|
+
clearTimeout(entity.compassTimeout)
|
|
155
|
+
entity.compassTimeout = NO_TIMEOUT
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const screenAngle = getScreenAngle()
|
|
159
|
+
const adjustedHeading =
|
|
160
|
+
(((heading - screenAngle + entity.manualOffset) % FULL_CIRCLE) +
|
|
161
|
+
FULL_CIRCLE) %
|
|
162
|
+
FULL_CIRCLE
|
|
163
|
+
|
|
164
|
+
api.notify("compassActiveChange", true)
|
|
165
|
+
api.notify("compassHeadingChange", Math.round(adjustedHeading))
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function getWindow() {
|
|
170
|
+
return typeof window !== "undefined" ? window : null
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function getScreenAngle() {
|
|
174
|
+
const win = getWindow()
|
|
175
|
+
return (
|
|
176
|
+
win?.screen?.orientation?.angle ?? win?.orientation ?? DEFAULT_ORIENTATION
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function isCompassSupported() {
|
|
181
|
+
return (
|
|
182
|
+
typeof DeviceOrientationEvent !== "undefined" &&
|
|
183
|
+
Boolean(getWindow()?.addEventListener)
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function createUnsupportedError() {
|
|
188
|
+
return {
|
|
189
|
+
code: 0,
|
|
190
|
+
message: "Compass is not supported by this environment.",
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function createPermissionDeniedError() {
|
|
195
|
+
return {
|
|
196
|
+
code: 1,
|
|
197
|
+
message: "Compass permission denied.",
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function normalizeError(error) {
|
|
202
|
+
return {
|
|
203
|
+
code: error?.code ?? DEFAULT_ERROR_CODE,
|
|
204
|
+
message: error?.message ?? String(error),
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -6,22 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
const NO_WATCH_ID = null
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Stops an active geolocation watch.
|
|
11
|
-
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
12
|
-
*/
|
|
13
|
-
export function unwatch(entity) {
|
|
14
|
-
const geolocation = getGeolocation()
|
|
15
|
-
|
|
16
|
-
if (entity.watchId !== NO_WATCH_ID && geolocation) {
|
|
17
|
-
geolocation.clearWatch(entity.watchId)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
entity.isLoading = false
|
|
21
|
-
entity.isWatching = false
|
|
22
|
-
entity.watchId = NO_WATCH_ID
|
|
23
|
-
}
|
|
24
|
-
|
|
25
9
|
/**
|
|
26
10
|
* Initializes the geolocation entity with default state.
|
|
27
11
|
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
@@ -40,7 +24,7 @@ export function create(entity) {
|
|
|
40
24
|
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
41
25
|
*/
|
|
42
26
|
export function destroy(entity) {
|
|
43
|
-
|
|
27
|
+
geolocationUnwatch(entity)
|
|
44
28
|
}
|
|
45
29
|
|
|
46
30
|
/**
|
|
@@ -48,7 +32,7 @@ export function destroy(entity) {
|
|
|
48
32
|
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
49
33
|
* @param {GeolocationPositionError} error - The geolocation error.
|
|
50
34
|
*/
|
|
51
|
-
export function
|
|
35
|
+
export function geolocationError(entity, error) {
|
|
52
36
|
entity.error = normalizeError(error)
|
|
53
37
|
entity.isLoading = false
|
|
54
38
|
}
|
|
@@ -59,7 +43,7 @@ export function error(entity, error) {
|
|
|
59
43
|
* @param {GeolocationOptions} options - Position options.
|
|
60
44
|
* @param {{ notify: Function }} api - The store API.
|
|
61
45
|
*/
|
|
62
|
-
export function
|
|
46
|
+
export function geolocationRequest(entity, options = {}, api) {
|
|
63
47
|
const geolocation = getGeolocation()
|
|
64
48
|
|
|
65
49
|
entity.isSupported = Boolean(geolocation)
|
|
@@ -67,7 +51,7 @@ export function request(entity, options = {}, api) {
|
|
|
67
51
|
|
|
68
52
|
if (!geolocation) {
|
|
69
53
|
entity.isLoading = false
|
|
70
|
-
api.notify(
|
|
54
|
+
api.notify("geolocationError", createUnsupportedError())
|
|
71
55
|
return
|
|
72
56
|
}
|
|
73
57
|
|
|
@@ -75,10 +59,10 @@ export function request(entity, options = {}, api) {
|
|
|
75
59
|
|
|
76
60
|
geolocation.getCurrentPosition(
|
|
77
61
|
(position) => {
|
|
78
|
-
api.notify(
|
|
62
|
+
api.notify("geolocationSuccess", normalizePosition(position))
|
|
79
63
|
},
|
|
80
64
|
(error) => {
|
|
81
|
-
api.notify(
|
|
65
|
+
api.notify("geolocationError", error)
|
|
82
66
|
},
|
|
83
67
|
options,
|
|
84
68
|
)
|
|
@@ -89,19 +73,35 @@ export function request(entity, options = {}, api) {
|
|
|
89
73
|
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
90
74
|
* @param {GeolocationPosition} position - The geolocation position.
|
|
91
75
|
*/
|
|
92
|
-
export function
|
|
76
|
+
export function geolocationSuccess(entity, position) {
|
|
93
77
|
entity.error = null
|
|
94
78
|
entity.isLoading = false
|
|
95
79
|
entity.position = position
|
|
96
80
|
}
|
|
97
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Stops an active geolocation watch.
|
|
84
|
+
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
85
|
+
*/
|
|
86
|
+
export function geolocationUnwatch(entity) {
|
|
87
|
+
const geolocation = getGeolocation()
|
|
88
|
+
|
|
89
|
+
if (entity.watchId !== NO_WATCH_ID && geolocation) {
|
|
90
|
+
geolocation.clearWatch(entity.watchId)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
entity.isLoading = false
|
|
94
|
+
entity.isWatching = false
|
|
95
|
+
entity.watchId = NO_WATCH_ID
|
|
96
|
+
}
|
|
97
|
+
|
|
98
98
|
/**
|
|
99
99
|
* Starts watching geolocation changes.
|
|
100
100
|
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
101
101
|
* @param {GeolocationOptions} options - Watch options.
|
|
102
102
|
* @param {{ notify: Function }} api - The store API.
|
|
103
103
|
*/
|
|
104
|
-
export function
|
|
104
|
+
export function geolocationWatch(entity, options = {}, api) {
|
|
105
105
|
const geolocation = getGeolocation()
|
|
106
106
|
|
|
107
107
|
entity.isSupported = Boolean(geolocation)
|
|
@@ -109,7 +109,7 @@ export function watch(entity, options = {}, api) {
|
|
|
109
109
|
|
|
110
110
|
if (!geolocation) {
|
|
111
111
|
entity.isLoading = false
|
|
112
|
-
api.notify(
|
|
112
|
+
api.notify("geolocationError", createUnsupportedError())
|
|
113
113
|
return
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -121,10 +121,10 @@ export function watch(entity, options = {}, api) {
|
|
|
121
121
|
entity.isWatching = true
|
|
122
122
|
entity.watchId = geolocation.watchPosition(
|
|
123
123
|
(position) => {
|
|
124
|
-
api.notify(
|
|
124
|
+
api.notify("geolocationSuccess", normalizePosition(position))
|
|
125
125
|
},
|
|
126
126
|
(error) => {
|
|
127
|
-
api.notify(
|
|
127
|
+
api.notify("geolocationError", error)
|
|
128
128
|
},
|
|
129
129
|
options,
|
|
130
130
|
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Api } from "./mount"
|
|
2
|
+
|
|
3
|
+
export interface CompassEntity {
|
|
4
|
+
id: string | number
|
|
5
|
+
type?: "Compass"
|
|
6
|
+
error: CompassError | null
|
|
7
|
+
heading: number | null
|
|
8
|
+
isCompassActive: boolean
|
|
9
|
+
isCompassPermissionGranted: boolean
|
|
10
|
+
isLoading: boolean
|
|
11
|
+
isSupported: boolean
|
|
12
|
+
manualOffset: number | null
|
|
13
|
+
_absoluteListener: ((event: DeviceOrientationEvent) => void) | null
|
|
14
|
+
_orientationListener: ((event: DeviceOrientationEvent) => void) | null
|
|
15
|
+
_isUsingAbsolute: boolean
|
|
16
|
+
compassTimeout: number | null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface CompassError {
|
|
20
|
+
code: number
|
|
21
|
+
message: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CompassType {
|
|
25
|
+
create(entity: CompassEntity, payload: unknown, api: Api): void
|
|
26
|
+
destroy(entity: CompassEntity, payload: unknown, api: Api): void
|
|
27
|
+
compassUnwatch(entity: CompassEntity, payload: unknown, api: Api): void
|
|
28
|
+
compassError(entity: CompassEntity, error: CompassError, api: Api): void
|
|
29
|
+
compassPermissionsRequest(
|
|
30
|
+
entity: CompassEntity,
|
|
31
|
+
payload: unknown,
|
|
32
|
+
api: Api,
|
|
33
|
+
): void
|
|
34
|
+
compassPermissionsGrant(
|
|
35
|
+
entity: CompassEntity,
|
|
36
|
+
payload: unknown,
|
|
37
|
+
api: Api,
|
|
38
|
+
): void
|
|
39
|
+
compassWatch(entity: CompassEntity, payload: unknown, api: Api): void
|
|
40
|
+
compassActiveChange(entity: CompassEntity, value: boolean, api: Api): void
|
|
41
|
+
compassHeadingChange(entity: CompassEntity, value: number, api: Api): void
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export declare const Compass: CompassType
|
package/types/geolocation.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Api } from "./mount"
|
|
2
|
+
|
|
1
3
|
export interface GeolocationCoordinates {
|
|
2
4
|
accuracy: number
|
|
3
5
|
altitude: number | null
|
|
@@ -43,13 +45,13 @@ export interface GeolocationType {
|
|
|
43
45
|
request(
|
|
44
46
|
entity: GeolocationEntity,
|
|
45
47
|
options: GeolocationOptions | undefined,
|
|
46
|
-
api:
|
|
48
|
+
api: Api,
|
|
47
49
|
): void
|
|
48
50
|
success(entity: GeolocationEntity, position: GeolocationPosition): void
|
|
49
51
|
watch(
|
|
50
52
|
entity: GeolocationEntity,
|
|
51
53
|
options: GeolocationOptions | undefined,
|
|
52
|
-
api:
|
|
54
|
+
api: Api,
|
|
53
55
|
): void
|
|
54
56
|
}
|
|
55
57
|
|