@inglorious/web 5.0.2 → 6.0.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.
- package/README.md +97 -77
- package/package.json +16 -2
- package/src/directives/choose.js +1 -0
- package/src/directives/class-map.js +1 -0
- package/src/directives/ref.js +1 -0
- package/src/directives/repeat.js +1 -0
- package/src/directives/style-map.js +1 -0
- package/src/directives/unsafe-html.js +1 -0
- package/src/directives/when.js +1 -0
- package/src/geolocation/handlers.js +168 -0
- package/src/geolocation/index.js +3 -0
- package/src/index.js +0 -13
- package/src/static.js +1 -0
- package/types/directives/choose.d.ts +1 -0
- package/types/directives/class-map.d.ts +1 -0
- package/types/directives/ref.d.ts +1 -0
- package/types/directives/repeat.d.ts +1 -0
- package/types/directives/style-map.d.ts +1 -0
- package/types/directives/unsafe-html.d.ts +1 -0
- package/types/directives/when.d.ts +1 -0
- package/types/geolocation.d.ts +56 -0
- package/types/index.d.ts +0 -3
- package/types/lit-html.d.ts +1 -9
- package/types/static.d.ts +1 -0
- package/types/store.d.ts +0 -15
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@ 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)**.
|
|
11
|
+
|
|
10
12
|
---
|
|
11
13
|
|
|
12
14
|
## Features
|
|
@@ -26,8 +28,8 @@ Unlike modern frameworks that invent their own languages or rely on signals, pro
|
|
|
26
28
|
Zero magic, zero reactivity graphs, zero compiler.
|
|
27
29
|
Just JavaScript functions and store events.
|
|
28
30
|
|
|
29
|
-
- **Router, Forms,
|
|
30
|
-
High-level primitives built on the same predictable model.
|
|
31
|
+
- **Router, Forms, Geolocation, Async, Testing utilities**
|
|
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)**.
|
|
31
33
|
|
|
32
34
|
- **Zero Component State**
|
|
33
35
|
All state lives in the store — never inside components.
|
|
@@ -283,7 +285,8 @@ First, set up your store with entity types. For each type you want to render, ad
|
|
|
283
285
|
|
|
284
286
|
```javascript
|
|
285
287
|
// store.js
|
|
286
|
-
import { createStore
|
|
288
|
+
import { createStore } from "@inglorious/store"
|
|
289
|
+
import { html } from "@inglorious/web"
|
|
287
290
|
|
|
288
291
|
const types = {
|
|
289
292
|
counter: {
|
|
@@ -346,7 +349,12 @@ One of Inglorious Web's greatest strengths is **testability**. Entity handlers a
|
|
|
346
349
|
|
|
347
350
|
### Testing Utilities
|
|
348
351
|
|
|
349
|
-
|
|
352
|
+
The `@inglorious/web/test` entry point re-exports two helpers so you can test handlers and templates without any extra setup:
|
|
353
|
+
|
|
354
|
+
- **`trigger`** — comes from `@inglorious/store` (`@inglorious/store/test`). It executes an entity handler and returns the new state plus any dispatched events.
|
|
355
|
+
- **`render`** — comes from `lit-html`. It renders a template to a DOM node so you can assert on its output.
|
|
356
|
+
|
|
357
|
+
Both are re-exported from `@inglorious/web/test` purely as a convenience, so a web app only needs to depend on `@inglorious/web` to test its handlers and templates.
|
|
350
358
|
|
|
351
359
|
#### `trigger(entity, handler, payload?, api?)`
|
|
352
360
|
|
|
@@ -503,7 +511,7 @@ test("completed todo has completed class", () => {
|
|
|
503
511
|
#### Integration Test: Full Store
|
|
504
512
|
|
|
505
513
|
```javascript
|
|
506
|
-
import { createStore } from "@inglorious/
|
|
514
|
+
import { createStore } from "@inglorious/store"
|
|
507
515
|
import { Counter } from "./types/counter.js"
|
|
508
516
|
|
|
509
517
|
test("full user interaction flow", () => {
|
|
@@ -527,7 +535,7 @@ test("full user interaction flow", () => {
|
|
|
527
535
|
#### Testing Computed State
|
|
528
536
|
|
|
529
537
|
```javascript
|
|
530
|
-
import { compute } from "@inglorious/store"
|
|
538
|
+
import { compute } from "@inglorious/store/select"
|
|
531
539
|
|
|
532
540
|
test("filtered todos excludes completed", () => {
|
|
533
541
|
const todos = [
|
|
@@ -852,7 +860,6 @@ export const App = {
|
|
|
852
860
|
create(entity) {
|
|
853
861
|
entity.title = "Todos"
|
|
854
862
|
},
|
|
855
|
-
|
|
856
863
|
render(entity, api) {
|
|
857
864
|
return html`
|
|
858
865
|
<div>
|
|
@@ -916,7 +923,7 @@ To enable DevTools, add the middleware provided by `createDevtools()`.
|
|
|
916
923
|
|
|
917
924
|
```javascript
|
|
918
925
|
// middlewares.js
|
|
919
|
-
import { createDevtools } from "@inglorious/
|
|
926
|
+
import { createDevtools } from "@inglorious/store/client/devtools"
|
|
920
927
|
|
|
921
928
|
export const middlewares = []
|
|
922
929
|
|
|
@@ -930,7 +937,7 @@ if (import.meta.env.DEV) {
|
|
|
930
937
|
|
|
931
938
|
```javascript
|
|
932
939
|
// store.js
|
|
933
|
-
import { createStore } from "@inglorious/
|
|
940
|
+
import { createStore } from "@inglorious/store"
|
|
934
941
|
import { middlewares } from "./middlewares.js"
|
|
935
942
|
|
|
936
943
|
export const store = createStore({
|
|
@@ -962,14 +969,13 @@ To enable the router, add it to your store's types and create a `router` entity.
|
|
|
962
969
|
|
|
963
970
|
```javascript
|
|
964
971
|
// store.js
|
|
965
|
-
import { createStore
|
|
972
|
+
import { createStore } from "@inglorious/store"
|
|
973
|
+
import { html } from "@inglorious/web"
|
|
966
974
|
import { Router, setRoutes } from "@inglorious/web/router"
|
|
967
975
|
|
|
968
976
|
const types = {
|
|
969
977
|
// 1. Add the router type to your store's types
|
|
970
|
-
Router,
|
|
971
|
-
|
|
972
|
-
// 2. Define types for your pages
|
|
978
|
+
Router, // 2. Define types for your pages
|
|
973
979
|
HomePage: {
|
|
974
980
|
render: () => html`<h1>Welcome Home!</h1>`,
|
|
975
981
|
},
|
|
@@ -1062,8 +1068,7 @@ const entities = {
|
|
|
1062
1068
|
export const store = createStore({ types, entities })
|
|
1063
1069
|
|
|
1064
1070
|
setRoutes({
|
|
1065
|
-
"/": "homePage",
|
|
1066
|
-
// Lazy load: returns a Promise resolving to a module
|
|
1071
|
+
"/": "homePage", // Lazy load: returns a Promise resolving to a module
|
|
1067
1072
|
"/admin": () => import("./pages/admin.js"),
|
|
1068
1073
|
})
|
|
1069
1074
|
```
|
|
@@ -1115,19 +1120,15 @@ export const requireAuth = (type) => ({
|
|
|
1115
1120
|
|
|
1116
1121
|
```javascript
|
|
1117
1122
|
// store.js
|
|
1118
|
-
import { createStore } from "@inglorious/
|
|
1123
|
+
import { createStore } from "@inglorious/store"
|
|
1119
1124
|
import { Router } from "@inglorious/web/router"
|
|
1120
1125
|
import { requireAuth } from "./guards/require-auth.js"
|
|
1121
1126
|
import { AdminPage } from "./pages/admin.js"
|
|
1122
1127
|
import { LoginPage } from "./pages/login.js"
|
|
1123
1128
|
|
|
1124
1129
|
const types = {
|
|
1125
|
-
Router,
|
|
1126
|
-
|
|
1127
|
-
// Public page - no guard
|
|
1128
|
-
LoginPage,
|
|
1129
|
-
|
|
1130
|
-
// Protected page - composed with requireAuth guard
|
|
1130
|
+
Router, // Public page - no guard
|
|
1131
|
+
LoginPage, // Protected page - composed with requireAuth guard
|
|
1131
1132
|
AdminPage: [AdminPage, requireAuth],
|
|
1132
1133
|
}
|
|
1133
1134
|
|
|
@@ -1173,9 +1174,7 @@ You can compose multiple guards for fine-grained control:
|
|
|
1173
1174
|
```javascript
|
|
1174
1175
|
const types = {
|
|
1175
1176
|
// Require authentication AND admin role
|
|
1176
|
-
AdminPage: [AdminPage, requireAuth, requireAdmin],
|
|
1177
|
-
|
|
1178
|
-
// Require authentication AND resource ownership
|
|
1177
|
+
AdminPage: [AdminPage, requireAuth, requireAdmin], // Require authentication AND resource ownership
|
|
1179
1178
|
UserProfile: [UserProfile, requireAuth, requireOwnership],
|
|
1180
1179
|
}
|
|
1181
1180
|
```
|
|
@@ -1196,9 +1195,7 @@ const logging = (type) => ({
|
|
|
1196
1195
|
render(entity, api) {
|
|
1197
1196
|
console.log(`Rendering ${entity.id}`)
|
|
1198
1197
|
return type.render(entity, api)
|
|
1199
|
-
},
|
|
1200
|
-
|
|
1201
|
-
// Intercept any event
|
|
1198
|
+
}, // Intercept any event
|
|
1202
1199
|
someEvent(entity, payload, api) {
|
|
1203
1200
|
console.log(`Event triggered on ${entity.id}`)
|
|
1204
1201
|
type.someEvent?.(entity, payload, api)
|
|
@@ -1234,6 +1231,50 @@ For ready-made UI primitives (controls, data display, navigation, feedback, layo
|
|
|
1234
1231
|
|
|
1235
1232
|
---
|
|
1236
1233
|
|
|
1234
|
+
## Geolocation
|
|
1235
|
+
|
|
1236
|
+
`@inglorious/web` includes a `Geolocation` type for keeping browser geolocation state inside the store.
|
|
1237
|
+
|
|
1238
|
+
```javascript
|
|
1239
|
+
import { createStore } from "@inglorious/store"
|
|
1240
|
+
import { Geolocation } from "@inglorious/web/geolocation"
|
|
1241
|
+
|
|
1242
|
+
const store = createStore({
|
|
1243
|
+
types: { Geolocation },
|
|
1244
|
+
autoCreateEntities: true,
|
|
1245
|
+
})
|
|
1246
|
+
|
|
1247
|
+
// The store now contains a `geolocation` entity.
|
|
1248
|
+
store.getState().geolocation
|
|
1249
|
+
```
|
|
1250
|
+
|
|
1251
|
+
The entity state contains:
|
|
1252
|
+
|
|
1253
|
+
- `isSupported` — whether `navigator.geolocation` is available
|
|
1254
|
+
- `isLoading` — whether a current-position request or first watch result is pending
|
|
1255
|
+
- `isWatching` — whether a geolocation watch is active
|
|
1256
|
+
- `position` — the latest normalized `{ coords, timestamp }` value
|
|
1257
|
+
- `error` — the latest normalized `{ code, message }` error
|
|
1258
|
+
- `watchId` — the active browser watch id, or `null`
|
|
1259
|
+
|
|
1260
|
+
Events:
|
|
1261
|
+
|
|
1262
|
+
- `#geolocation:getCurrentPosition` — request the current position
|
|
1263
|
+
- `#geolocation:watch` — start watching position changes
|
|
1264
|
+
- `#geolocation:clearWatch` — stop the active watch
|
|
1265
|
+
|
|
1266
|
+
```javascript
|
|
1267
|
+
api.notify("#geolocation:getCurrentPosition", {
|
|
1268
|
+
enableHighAccuracy: true,
|
|
1269
|
+
timeout: 5000,
|
|
1270
|
+
})
|
|
1271
|
+
|
|
1272
|
+
api.notify("#geolocation:watch")
|
|
1273
|
+
api.notify("#geolocation:clearWatch")
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1276
|
+
---
|
|
1277
|
+
|
|
1237
1278
|
## Forms
|
|
1238
1279
|
|
|
1239
1280
|
`@inglorious/web` includes a small but powerful `form` type for managing form state inside your entity store. It offers:
|
|
@@ -1247,7 +1288,7 @@ For ready-made UI primitives (controls, data display, navigation, feedback, layo
|
|
|
1247
1288
|
Include `form` in your `types` and create an entity for the form (use any id you like — `form` is used below for clarity):
|
|
1248
1289
|
|
|
1249
1290
|
```javascript
|
|
1250
|
-
import { createStore } from "@inglorious/
|
|
1291
|
+
import { createStore } from "@inglorious/store"
|
|
1251
1292
|
import { Form } from "@inglorious/web/form"
|
|
1252
1293
|
|
|
1253
1294
|
const types = { Form }
|
|
@@ -1334,11 +1375,9 @@ export const DataGrid = {
|
|
|
1334
1375
|
</div>
|
|
1335
1376
|
`
|
|
1336
1377
|
},
|
|
1337
|
-
|
|
1338
1378
|
renderRow(entity, row, api) {
|
|
1339
1379
|
return html`<div class="data-grid-row">${row.name}</div>`
|
|
1340
1380
|
},
|
|
1341
|
-
|
|
1342
1381
|
rowClick(entity, row) {
|
|
1343
1382
|
entity.selectedRow = row
|
|
1344
1383
|
},
|
|
@@ -1441,14 +1480,11 @@ import "@shoelace-style/shoelace/dist/components/color-picker/color-picker.js"
|
|
|
1441
1480
|
|
|
1442
1481
|
const types = {
|
|
1443
1482
|
// App-specific type - full store integration
|
|
1444
|
-
ProductTable,
|
|
1445
|
-
|
|
1446
|
-
// Web Component - for specialized UI
|
|
1483
|
+
ProductTable, // Web Component - for specialized UI
|
|
1447
1484
|
ThemeEditor: {
|
|
1448
1485
|
colorChange(entity, color) {
|
|
1449
1486
|
entity.primaryColor = color
|
|
1450
1487
|
},
|
|
1451
|
-
|
|
1452
1488
|
render(entity, api) {
|
|
1453
1489
|
return html`
|
|
1454
1490
|
<div>
|
|
@@ -1482,13 +1518,11 @@ const types = {
|
|
|
1482
1518
|
`
|
|
1483
1519
|
},
|
|
1484
1520
|
},
|
|
1485
|
-
|
|
1486
1521
|
Header: {
|
|
1487
1522
|
render(entity, api) {
|
|
1488
1523
|
return html`<header>${entity.title}</header>`
|
|
1489
1524
|
},
|
|
1490
1525
|
},
|
|
1491
|
-
|
|
1492
1526
|
Content: {
|
|
1493
1527
|
render(entity, api) {
|
|
1494
1528
|
return html`<main>${entity.text}</main>`
|
|
@@ -1518,7 +1552,6 @@ const Header = {
|
|
|
1518
1552
|
create(entity) {
|
|
1519
1553
|
entity.title = "Welcome"
|
|
1520
1554
|
},
|
|
1521
|
-
|
|
1522
1555
|
render(entity, api) {
|
|
1523
1556
|
return html`<header>${entity.title}</header>`
|
|
1524
1557
|
},
|
|
@@ -1560,51 +1593,38 @@ The `renderFn` receives a powerful `api` object that contains all methods from t
|
|
|
1560
1593
|
|
|
1561
1594
|
This method is the cornerstone of entity-based rendering. It looks up an entity by its `id`, finds its corresponding type definition, and calls the `render(entity, api)` method on that type. When you pass `typeName` and `Type`, it will lazily register the type with `api.setType(typeName, Type)` if the type is not already present.
|
|
1562
1595
|
|
|
1563
|
-
###
|
|
1596
|
+
### Package Entry Points
|
|
1597
|
+
|
|
1598
|
+
`@inglorious/web` keeps its root entry point intentionally small:
|
|
1599
|
+
|
|
1600
|
+
```javascript
|
|
1601
|
+
import { mount, html, svg } from "@inglorious/web"
|
|
1602
|
+
```
|
|
1564
1603
|
|
|
1565
|
-
|
|
1604
|
+
Import everything else from the package that owns it, or from an explicit `@inglorious/web` subpath:
|
|
1566
1605
|
|
|
1567
1606
|
```javascript
|
|
1568
|
-
import {
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
choose,
|
|
1582
|
-
classMap,
|
|
1583
|
-
ref,
|
|
1584
|
-
repeat,
|
|
1585
|
-
styleMap,
|
|
1586
|
-
unsafeHTML,
|
|
1587
|
-
when,
|
|
1588
|
-
} from "@inglorious/web"
|
|
1589
|
-
|
|
1590
|
-
// Subpath imports for tree-shaking
|
|
1591
|
-
import {
|
|
1592
|
-
Form,
|
|
1593
|
-
getFieldError,
|
|
1594
|
-
getFieldValue,
|
|
1595
|
-
isFieldTouched,
|
|
1596
|
-
} from "@inglorious/web/form"
|
|
1597
|
-
import {
|
|
1598
|
-
Router,
|
|
1599
|
-
getRoutes,
|
|
1600
|
-
getRoute,
|
|
1601
|
-
setRoutes,
|
|
1602
|
-
addRoute,
|
|
1603
|
-
removeRoute,
|
|
1604
|
-
} from "@inglorious/web/router"
|
|
1607
|
+
import { createStore } from "@inglorious/store"
|
|
1608
|
+
import { handleAsync } from "@inglorious/store/async"
|
|
1609
|
+
import { withOptimistic } from "@inglorious/store/optimistic"
|
|
1610
|
+
import { compute, createSelector } from "@inglorious/store/select"
|
|
1611
|
+
import { createDevtools } from "@inglorious/store/client/devtools"
|
|
1612
|
+
|
|
1613
|
+
import { classMap } from "@inglorious/web/directives/class-map"
|
|
1614
|
+
import { ref, createRef } from "@inglorious/web/directives/ref"
|
|
1615
|
+
import { repeat } from "@inglorious/web/directives/repeat"
|
|
1616
|
+
import { styleMap } from "@inglorious/web/directives/style-map"
|
|
1617
|
+
import { unsafeHTML } from "@inglorious/web/directives/unsafe-html"
|
|
1618
|
+
import { when } from "@inglorious/web/directives/when"
|
|
1619
|
+
import { staticHtml, unsafeStatic } from "@inglorious/web/static"
|
|
1605
1620
|
import { render, trigger } from "@inglorious/web/test"
|
|
1621
|
+
|
|
1622
|
+
import { Form } from "@inglorious/web/form"
|
|
1623
|
+
import { Router, setRoutes } from "@inglorious/web/router"
|
|
1606
1624
|
```
|
|
1607
1625
|
|
|
1626
|
+
This keeps `lit-html` as an internal implementation detail while still giving applications stable, tree-shakeable import paths.
|
|
1627
|
+
|
|
1608
1628
|
---
|
|
1609
1629
|
|
|
1610
1630
|
## Error Handling
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/web",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
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,15 +26,27 @@
|
|
|
26
26
|
"types": "./types/index.d.ts",
|
|
27
27
|
"import": "./src/index.js"
|
|
28
28
|
},
|
|
29
|
+
"./directives/*": {
|
|
30
|
+
"types": "./types/directives/*.d.ts",
|
|
31
|
+
"import": "./src/directives/*.js"
|
|
32
|
+
},
|
|
29
33
|
"./form": {
|
|
30
34
|
"types": "./types/form.d.ts",
|
|
31
35
|
"import": "./src/form/index.js"
|
|
32
36
|
},
|
|
37
|
+
"./geolocation": {
|
|
38
|
+
"types": "./types/geolocation.d.ts",
|
|
39
|
+
"import": "./src/geolocation/index.js"
|
|
40
|
+
},
|
|
33
41
|
"./hydrate": "./src/hydrate.js",
|
|
34
42
|
"./router": {
|
|
35
43
|
"types": "./types/router.d.ts",
|
|
36
44
|
"import": "./src/router/index.js"
|
|
37
45
|
},
|
|
46
|
+
"./static": {
|
|
47
|
+
"types": "./types/static.d.ts",
|
|
48
|
+
"import": "./src/static.js"
|
|
49
|
+
},
|
|
38
50
|
"./test": {
|
|
39
51
|
"import": "./src/test.js"
|
|
40
52
|
}
|
|
@@ -51,9 +63,11 @@
|
|
|
51
63
|
"dependencies": {
|
|
52
64
|
"@lit-labs/ssr-client": "^1.1.8",
|
|
53
65
|
"lit-html": "^3.3.1",
|
|
54
|
-
"@inglorious/store": "10.0.0",
|
|
55
66
|
"@inglorious/utils": "3.8.0"
|
|
56
67
|
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"@inglorious/store": "11.0.0"
|
|
70
|
+
},
|
|
57
71
|
"devDependencies": {
|
|
58
72
|
"prettier": "^3.6.2",
|
|
59
73
|
"vitest": "^4.0.15",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { choose } from "lit-html/directives/choose.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { classMap } from "lit-html/directives/class-map.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createRef, ref } from "lit-html/directives/ref.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { repeat } from "lit-html/directives/repeat.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { styleMap } from "lit-html/directives/style-map.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { unsafeHTML } from "lit-html/directives/unsafe-html.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { when } from "lit-html/directives/when.js"
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("../../types/geolocation.js").GeolocationEntity} GeolocationEntity
|
|
3
|
+
* @typedef {import("../../types/geolocation.js").GeolocationOptions} GeolocationOptions
|
|
4
|
+
* @typedef {import("../../types/geolocation.js").GeolocationPosition} GeolocationPosition
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const NO_WATCH_ID = null
|
|
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
|
+
/**
|
|
26
|
+
* Initializes the geolocation entity with default state.
|
|
27
|
+
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
28
|
+
*/
|
|
29
|
+
export function create(entity) {
|
|
30
|
+
entity.error ??= null
|
|
31
|
+
entity.isLoading ??= false
|
|
32
|
+
entity.isSupported = Boolean(getGeolocation())
|
|
33
|
+
entity.isWatching ??= false
|
|
34
|
+
entity.position ??= null
|
|
35
|
+
entity.watchId ??= NO_WATCH_ID
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Clears the geolocation watch before the entity is destroyed.
|
|
40
|
+
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
41
|
+
*/
|
|
42
|
+
export function destroy(entity) {
|
|
43
|
+
unwatch(entity)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Stores a normalized geolocation error.
|
|
48
|
+
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
49
|
+
* @param {GeolocationPositionError} error - The geolocation error.
|
|
50
|
+
*/
|
|
51
|
+
export function error(entity, error) {
|
|
52
|
+
entity.error = normalizeError(error)
|
|
53
|
+
entity.isLoading = false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Requests the current geolocation position.
|
|
58
|
+
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
59
|
+
* @param {GeolocationOptions} options - Position options.
|
|
60
|
+
* @param {{ notify: Function }} api - The store API.
|
|
61
|
+
*/
|
|
62
|
+
export function request(entity, options = {}, api) {
|
|
63
|
+
const geolocation = getGeolocation()
|
|
64
|
+
|
|
65
|
+
entity.isSupported = Boolean(geolocation)
|
|
66
|
+
entity.error = null
|
|
67
|
+
|
|
68
|
+
if (!geolocation) {
|
|
69
|
+
entity.isLoading = false
|
|
70
|
+
api.notify(`#${entity.id}:error`, createUnsupportedError())
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
entity.isLoading = true
|
|
75
|
+
|
|
76
|
+
geolocation.getCurrentPosition(
|
|
77
|
+
(position) => {
|
|
78
|
+
api.notify(`#${entity.id}:success`, normalizePosition(position))
|
|
79
|
+
},
|
|
80
|
+
(error) => {
|
|
81
|
+
api.notify(`#${entity.id}:error`, error)
|
|
82
|
+
},
|
|
83
|
+
options,
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Stores a normalized geolocation position.
|
|
89
|
+
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
90
|
+
* @param {GeolocationPosition} position - The geolocation position.
|
|
91
|
+
*/
|
|
92
|
+
export function success(entity, position) {
|
|
93
|
+
entity.error = null
|
|
94
|
+
entity.isLoading = false
|
|
95
|
+
entity.position = position
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Starts watching geolocation changes.
|
|
100
|
+
* @param {GeolocationEntity} entity - The geolocation entity.
|
|
101
|
+
* @param {GeolocationOptions} options - Watch options.
|
|
102
|
+
* @param {{ notify: Function }} api - The store API.
|
|
103
|
+
*/
|
|
104
|
+
export function watch(entity, options = {}, api) {
|
|
105
|
+
const geolocation = getGeolocation()
|
|
106
|
+
|
|
107
|
+
entity.isSupported = Boolean(geolocation)
|
|
108
|
+
entity.error = null
|
|
109
|
+
|
|
110
|
+
if (!geolocation) {
|
|
111
|
+
entity.isLoading = false
|
|
112
|
+
api.notify(`#${entity.id}:error`, createUnsupportedError())
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (entity.watchId !== NO_WATCH_ID) {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
entity.isLoading = true
|
|
121
|
+
entity.isWatching = true
|
|
122
|
+
entity.watchId = geolocation.watchPosition(
|
|
123
|
+
(position) => {
|
|
124
|
+
api.notify(`#${entity.id}:success`, normalizePosition(position))
|
|
125
|
+
},
|
|
126
|
+
(error) => {
|
|
127
|
+
api.notify(`#${entity.id}:error`, error)
|
|
128
|
+
},
|
|
129
|
+
options,
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function createUnsupportedError() {
|
|
134
|
+
return {
|
|
135
|
+
code: 0,
|
|
136
|
+
message: "Geolocation is not supported by this environment.",
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getGeolocation() {
|
|
141
|
+
return globalThis.navigator?.geolocation
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function normalizeCoords(coords) {
|
|
145
|
+
return {
|
|
146
|
+
accuracy: coords.accuracy,
|
|
147
|
+
altitude: coords.altitude,
|
|
148
|
+
altitudeAccuracy: coords.altitudeAccuracy,
|
|
149
|
+
heading: coords.heading,
|
|
150
|
+
latitude: coords.latitude,
|
|
151
|
+
longitude: coords.longitude,
|
|
152
|
+
speed: coords.speed,
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function normalizeError(error) {
|
|
157
|
+
return {
|
|
158
|
+
code: error.code,
|
|
159
|
+
message: error.message,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function normalizePosition(position) {
|
|
164
|
+
return {
|
|
165
|
+
coords: normalizeCoords(position.coords),
|
|
166
|
+
timestamp: position.timestamp,
|
|
167
|
+
}
|
|
168
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,15 +1,2 @@
|
|
|
1
1
|
export { mount } from "./mount.js"
|
|
2
|
-
export { createStore } from "@inglorious/store"
|
|
3
|
-
export { createDevtools } from "@inglorious/store/client/devtools.js"
|
|
4
|
-
export { compute } from "@inglorious/store/select.js"
|
|
5
|
-
export { createSelector } from "@inglorious/store/select.js"
|
|
6
|
-
export { trigger } from "@inglorious/store/test.js"
|
|
7
2
|
export { html, svg } from "lit-html"
|
|
8
|
-
export { choose } from "lit-html/directives/choose.js"
|
|
9
|
-
export { classMap } from "lit-html/directives/class-map.js"
|
|
10
|
-
export { ref } from "lit-html/directives/ref.js"
|
|
11
|
-
export { repeat } from "lit-html/directives/repeat.js"
|
|
12
|
-
export { styleMap } from "lit-html/directives/style-map.js"
|
|
13
|
-
export { unsafeHTML } from "lit-html/directives/unsafe-html.js"
|
|
14
|
-
export { when } from "lit-html/directives/when.js"
|
|
15
|
-
export { html as staticHtml, unsafeStatic } from "lit-html/static.js"
|
package/src/static.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { html as staticHtml, unsafeStatic } from "lit-html/static.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { choose } from "lit-html/directives/choose"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { classMap } from "lit-html/directives/class-map"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createRef, ref } from "lit-html/directives/ref"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { repeat } from "lit-html/directives/repeat"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { styleMap } from "lit-html/directives/style-map"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { unsafeHTML } from "lit-html/directives/unsafe-html"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { when } from "lit-html/directives/when"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface GeolocationCoordinates {
|
|
2
|
+
accuracy: number
|
|
3
|
+
altitude: number | null
|
|
4
|
+
altitudeAccuracy: number | null
|
|
5
|
+
heading: number | null
|
|
6
|
+
latitude: number
|
|
7
|
+
longitude: number
|
|
8
|
+
speed: number | null
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface GeolocationEntity {
|
|
12
|
+
error: GeolocationError | null
|
|
13
|
+
id: string | number
|
|
14
|
+
isLoading: boolean
|
|
15
|
+
isSupported: boolean
|
|
16
|
+
isWatching: boolean
|
|
17
|
+
position: GeolocationPosition | null
|
|
18
|
+
type?: "Geolocation"
|
|
19
|
+
watchId: number | null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface GeolocationError {
|
|
23
|
+
code: number
|
|
24
|
+
message: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface GeolocationOptions {
|
|
28
|
+
enableHighAccuracy?: boolean
|
|
29
|
+
maximumAge?: number
|
|
30
|
+
timeout?: number
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface GeolocationPosition {
|
|
34
|
+
coords: GeolocationCoordinates
|
|
35
|
+
timestamp: number
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface GeolocationType {
|
|
39
|
+
unwatch(entity: GeolocationEntity): void
|
|
40
|
+
create(entity: GeolocationEntity): void
|
|
41
|
+
destroy(entity: GeolocationEntity): void
|
|
42
|
+
error(entity: GeolocationEntity, error: GeolocationError): void
|
|
43
|
+
request(
|
|
44
|
+
entity: GeolocationEntity,
|
|
45
|
+
options: GeolocationOptions | undefined,
|
|
46
|
+
api: { notify: (event: string, payload?: unknown) => void },
|
|
47
|
+
): void
|
|
48
|
+
success(entity: GeolocationEntity, position: GeolocationPosition): void
|
|
49
|
+
watch(
|
|
50
|
+
entity: GeolocationEntity,
|
|
51
|
+
options: GeolocationOptions | undefined,
|
|
52
|
+
api: { notify: (event: string, payload?: unknown) => void },
|
|
53
|
+
): void
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export declare const Geolocation: GeolocationType
|
package/types/index.d.ts
CHANGED
package/types/lit-html.d.ts
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
export { html, TemplateResult } from "lit-html"
|
|
2
|
-
|
|
3
|
-
export { choose } from "lit-html/directives/choose"
|
|
4
|
-
export { classMap } from "lit-html/directives/class-map"
|
|
5
|
-
export { ref } from "lit-html/directives/ref"
|
|
6
|
-
export { repeat } from "lit-html/directives/repeat"
|
|
7
|
-
export { styleMap } from "lit-html/directives/style-map"
|
|
8
|
-
export { unsafeHTML } from "lit-html/directives/unsafe-html"
|
|
9
|
-
export { when } from "lit-html/directives/when"
|
|
1
|
+
export { html, svg, TemplateResult } from "lit-html"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { html as staticHtml, unsafeStatic } from "lit-html/static"
|
package/types/store.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
BaseEntity,
|
|
3
|
-
EntitiesState,
|
|
4
|
-
Event,
|
|
5
|
-
Middleware,
|
|
6
|
-
createStore,
|
|
7
|
-
TypesConfig,
|
|
8
|
-
} from "@inglorious/store"
|
|
9
|
-
|
|
10
|
-
export { compute } from "@inglorious/store/select"
|
|
11
|
-
export { createSelector } from "@inglorious/store/select"
|
|
12
|
-
export { trigger } from "@inglorious/store/test"
|
|
13
|
-
|
|
14
|
-
export { createDevtools } from "@inglorious/store/client/devtools"
|
|
15
|
-
export { multiplayerMiddleware } from "@inglorious/store/client/multiplayer-middleware"
|