@excom/provider-orientation 0.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.
Files changed (31) hide show
  1. package/.rush/temp/chunked-rush-logs/provider-orientation.apply-exports.chunks.jsonl +1 -0
  2. package/.rush/temp/chunked-rush-logs/provider-orientation.build_docs.chunks.jsonl +1 -0
  3. package/.rush/temp/chunked-rush-logs/provider-orientation.build_package-metas.chunks.jsonl +1 -0
  4. package/.rush/temp/operation/apply-exports/all.log +1 -0
  5. package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
  6. package/.rush/temp/operation/apply-exports/state.json +3 -0
  7. package/.rush/temp/operation/build_docs/all.log +1 -0
  8. package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
  9. package/.rush/temp/operation/build_docs/state.json +3 -0
  10. package/.rush/temp/operation/build_package-metas/all.log +1 -0
  11. package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
  12. package/.rush/temp/operation/build_package-metas/state.json +3 -0
  13. package/.rush/temp/shrinkwrap-deps.json +3 -0
  14. package/config/rig.json +5 -0
  15. package/index.ts +18 -0
  16. package/package.json +42 -0
  17. package/provider-orientation.ts +225 -0
  18. package/rush-logs/provider-orientation.apply-exports.cache.log +1 -0
  19. package/rush-logs/provider-orientation.apply-exports.log +1 -0
  20. package/rush-logs/provider-orientation.build_docs.cache.log +1 -0
  21. package/rush-logs/provider-orientation.build_docs.log +1 -0
  22. package/rush-logs/provider-orientation.build_package-metas.cache.log +1 -0
  23. package/rush-logs/provider-orientation.build_package-metas.log +1 -0
  24. package/support/custom-elements.json +208 -0
  25. package/support/demos/request.html +14 -0
  26. package/support/dist-docs/provider-orientation.md +126 -0
  27. package/support/docs/README.md +52 -0
  28. package/support/package-meta.json +127 -0
  29. package/support/tests/provider-orientation.test.ts +624 -0
  30. package/support/tests/request.view.test.ts +39 -0
  31. package/tsconfig.json +5 -0
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: cd \"$RUSH_PROJECT_FOLDER\" && node ../heft-rig/scripts/apply-exports.mjs \n"}
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs \n"}
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs \n"}
@@ -0,0 +1 @@
1
+ Invoking: cd "$RUSH_PROJECT_FOLDER" && node ../heft-rig/scripts/apply-exports.mjs
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: cd \"$RUSH_PROJECT_FOLDER\" && node ../heft-rig/scripts/apply-exports.mjs \n"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "nonCachedDurationMs": 37.539288999999826
3
+ }
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs \n"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "nonCachedDurationMs": 44.635099999999966
3
+ }
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs \n"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "nonCachedDurationMs": 107.37227900000016
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "../../packages/provider-orientation": "../../packages/provider-orientation:YAC8G8l1nkKknuTXH370JI0/DynCPkP81MNQcvbO6fA=:"
3
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
3
+ "rigPackageName": "@excom/heft-rig",
4
+ "rigProfile": "default"
5
+ }
package/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { ProviderOrientation } from "./provider-orientation";
2
+
3
+ ProviderOrientation.define();
4
+
5
+ export { ProviderOrientation };
6
+
7
+ type T_HTMLProviderOrientationElement =
8
+ typeof ProviderOrientation.CustomElement;
9
+ declare global {
10
+ interface HTMLProviderOrientationElement extends T_HTMLProviderOrientationElement {}
11
+ interface Window {
12
+ HTMLProviderOrientationElement: HTMLProviderOrientationElement;
13
+ }
14
+ interface HTMLElementTagNameMap {
15
+ "provider-orientation": HTMLProviderOrientationElement;
16
+ }
17
+ }
18
+ export type { HTMLProviderOrientationElement };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@excom/provider-orientation",
3
+ "version": "0.1.0",
4
+ "description": "<provider-orientation> custom element",
5
+ "license": "MIT",
6
+ "engines": {
7
+ "node": ">=24.13.0"
8
+ },
9
+ "type": "module",
10
+ "dependencies": {
11
+ "@excom/neutron": "^0.1.0"
12
+ },
13
+ "peerDependencies": {},
14
+ "devDependencies": {
15
+ "@excom/heft-rig": "^0.1.0"
16
+ },
17
+ "repository": {
18
+ "url": "excom-dev/nucleus",
19
+ "directory": "packages/provider-orientation"
20
+ },
21
+ "homepage": "https://github.com/excom-dev/nucleus/tree/main/packages/provider-orientation/support/docs/README.md",
22
+ "bugs": "https://github.com/excom-dev/nucleus/issues",
23
+ "keywords": [
24
+ "provider-orientation",
25
+ "neutron",
26
+ "custom-elements"
27
+ ],
28
+ "excom": {
29
+ "packageType": "kit-element"
30
+ },
31
+ "scripts": {
32
+ "build": "node node_modules/@excom/heft-rig/scripts/vite-build.mjs",
33
+ "build:watch": "node node_modules/@excom/heft-rig/scripts/vite-build-watch.mjs",
34
+ "format": "node node_modules/@excom/heft-rig/scripts/format.mjs",
35
+ "test": "node node_modules/@excom/heft-rig/scripts/vitest.mjs",
36
+ "coverage": "node node_modules/@excom/heft-rig/scripts/coverage.mjs",
37
+ "dev": "node node_modules/@excom/heft-rig/scripts/vite-dev.mjs",
38
+ "preview": "node node_modules/@excom/heft-rig/scripts/vite-preview.mjs",
39
+ "build:package-metas": "node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs",
40
+ "build:docs": "node node_modules/@excom/heft-rig/scripts/build-docs.mjs"
41
+ }
42
+ }
@@ -0,0 +1,225 @@
1
+ import { ConstructorType, Neutron, TEvent } from "@excom/neutron";
2
+
3
+ export type ProviderOrientationSuccess = {
4
+ bearing: number;
5
+ alpha: number | null;
6
+ };
7
+
8
+ export type ProviderOrientationError = string | Error;
9
+
10
+ export type ProviderOrientationSuccessEvent = TEvent & {
11
+ type: "provider-orientation-success";
12
+ detail: ProviderOrientationSuccess;
13
+ };
14
+
15
+ export type ProviderOrientationErrorEvent = TEvent & {
16
+ type: "provider-orientation-error";
17
+ detail: ProviderOrientationError;
18
+ };
19
+
20
+ /**
21
+ * Wraps the device orientation / compass APIs — request a heading and
22
+ * read updates from attributes/state, no app JS required. Requests on
23
+ * connect unless `is-paused`, same as the other `provider-*` elements —
24
+ * but on iOS that request must happen synchronously inside a user
25
+ * gesture (`DeviceOrientationEvent.requestPermission()`), so a
26
+ * connect-time request will silently fail there. **Set `is-paused` and
27
+ * invoke the `--request` command from a button instead** unless you know
28
+ * your app only targets Android/desktop (the handler runs in a microtask
29
+ * of the click, inside its user activation).
30
+ *
31
+ * Bearing (`provision.bearing`) is normalized to degrees clockwise from
32
+ * magnetic north (`0`–`360`) across both the iOS
33
+ * (`webkitCompassHeading`) and Android/absolute (`alpha`) code paths, so
34
+ * consumers don't need to branch on platform.
35
+ *
36
+ * Lifecycle: the `window` listener is tracked by Neutron — removed when
37
+ * the element leaves the document, restored (and the request repeated
38
+ * unless `is-paused`) when it is reconnected, and kept across a DOM move.
39
+ * Removing the element while an iOS permission prompt is still open
40
+ * abandons that request: nothing is attached when it settles, and a
41
+ * later reconnect requests again.
42
+ *
43
+ * @fires provider-orientation-success - Dispatched on every compass
44
+ * update (throttled by `compass-throttle-ms`). `bearing` is
45
+ * normalized 0-360°; `alpha` is the raw
46
+ * `DeviceOrientationEvent.alpha` where available.
47
+ * @type ProviderOrientationSuccessEvent
48
+ * @fires provider-orientation-error - Dispatched when the permission
49
+ * request is denied, or fails for any other reason.
50
+ * @type ProviderOrientationErrorEvent
51
+ * @command --request - Requests permission (iOS) and starts listening for
52
+ * orientation updates. Invoke it from a button (`<button
53
+ * command="--request" commandfor="…">`) so the user activation is there.
54
+ * @default-action provider-orientation-success - Stores `{ bearing,
55
+ * alpha }` in `provision` and sets `is-success` (clearing `is-requesting` /
56
+ * `is-error`).
57
+ * @default-action provider-orientation-error - Stores the error in
58
+ * `provision` and sets `is-error` (clearing `is-requesting` /
59
+ * `is-success`).
60
+ */
61
+ export const ProviderOrientation = Neutron({
62
+ tag: "provider-orientation",
63
+ props: {
64
+ // options
65
+ /**
66
+ * @option
67
+ * Skip requesting on connect. On iOS this is effectively required
68
+ * (a connect-time request happens outside a user gesture and will
69
+ * be denied) — pair with `provider-orientation-request` from a
70
+ * click handler instead (see class docs).
71
+ */
72
+ isPaused: Boolean,
73
+ /**
74
+ * @option
75
+ * Minimum ms between `provider-orientation-success` updates.
76
+ * Android can fire `deviceorientationabsolute` at 60-200 Hz;
77
+ * without throttling that floods listeners and CSS/Quark bindings.
78
+ * @default 100
79
+ */
80
+ compassThrottleMs: {
81
+ type: Number,
82
+ defaultValue: () => 100,
83
+ },
84
+ // state
85
+ /**
86
+ * @state
87
+ * iOS only: the permission request is pending (between
88
+ * `provider-orientation-request` and the user's response).
89
+ */
90
+ isRequesting: Boolean,
91
+ /**
92
+ * @state
93
+ * Listening for orientation updates (permission granted where
94
+ * required). Stays set across updates.
95
+ */
96
+ isSuccess: Boolean,
97
+ /**
98
+ * @state
99
+ * The permission request was denied, or listening failed to start.
100
+ */
101
+ isError: Boolean,
102
+ /**
103
+ * @provision
104
+ * Latest reading: `{ bearing, alpha }` on success, or the error on
105
+ * failure. Not reflected as an attribute.
106
+ * @type ProviderOrientationSuccess
107
+ */
108
+ provision: Object as unknown as ConstructorType<any>,
109
+ // private
110
+ permissionPromise: Promise as unknown as ConstructorType<
111
+ Promise<PermissionStatus>
112
+ >,
113
+ lastCompassUpdate: {
114
+ type: Number,
115
+ defaultValue: () => 0,
116
+ },
117
+ },
118
+ })
119
+ .defineMethods({
120
+ handleSuccess: (_, { bearing, alpha }) => ({
121
+ // Emit success event for continuous updates
122
+ emit: ["provider-orientation-success", { detail: { bearing, alpha } }],
123
+ }),
124
+ handleError: (_, error) => ({
125
+ emit: ["provider-orientation-error", { detail: error }],
126
+ }),
127
+ makeRequest: () => {
128
+ const DOE =
129
+ typeof DeviceOrientationEvent !== "undefined"
130
+ ? (DeviceOrientationEvent as any)
131
+ : null;
132
+ if (DOE && typeof DOE.requestPermission === "function") {
133
+ // iOS: request permission (async) from a user-gesture context
134
+ return {
135
+ permissionPromise: DOE.requestPermission(),
136
+ isRequesting: true,
137
+ };
138
+ }
139
+ /* Android / desktop: no permission here. Attach synchronously so it
140
+ stays in the user-gesture context; some Android browser / PWA
141
+ combos silently block `deviceorientation` outside a gesture. */
142
+ return {
143
+ _attachCompassListener: [],
144
+ isRequesting: false,
145
+ isSuccess: true,
146
+ isError: false,
147
+ };
148
+ },
149
+ /**
150
+ * Register the `window` orientation listener once, via Neutron's
151
+ * tracked registry (`target: window`). Dropped on disconnect,
152
+ * restored on reconnect, never added twice.
153
+ */
154
+ // @ts-ignore TODO fix defineMethods sibling references
155
+ _attachCompassListener: ({ compassHandler }) => ({
156
+ addListener: [
157
+ "ondeviceorientationabsolute" in window
158
+ ? "deviceorientationabsolute"
159
+ : "deviceorientation",
160
+ compassHandler,
161
+ { capture: true, target: window },
162
+ ],
163
+ }),
164
+ compassHandler: ({ compassThrottleMs, lastCompassUpdate }, e: any) => {
165
+ // Throttle: Android fires `deviceorientationabsolute` at 60-200 Hz
166
+ const now = Date.now();
167
+ if (now - lastCompassUpdate < compassThrottleMs) return;
168
+
169
+ let bearing: number | null = null;
170
+
171
+ // iOS: `webkitCompassHeading` (degrees from magnetic north, 0-360)
172
+ if (typeof e.webkitCompassHeading === "number") {
173
+ bearing = e.webkitCompassHeading;
174
+ } else if (typeof e.alpha === "number" && e.absolute) {
175
+ // Android / absolute: `alpha` is degrees from north
176
+ bearing = (360 - e.alpha) % 360;
177
+ }
178
+
179
+ if (bearing !== null) {
180
+ return {
181
+ lastCompassUpdate: now,
182
+ handleSuccess: [{ bearing, alpha: e.alpha ?? undefined }],
183
+ };
184
+ }
185
+ },
186
+ })
187
+ .onConnected(
188
+ // A DOM move keeps the listener (Neutron restores it). Only a fresh
189
+ // connect or a real reconnect requests again.
190
+ ({ isPaused, isMoving }) =>
191
+ !isPaused &&
192
+ !isMoving && {
193
+ makeRequest: [],
194
+ }
195
+ )
196
+ .onPropUnset("isPaused", () => ({
197
+ makeRequest: [],
198
+ }))
199
+ .onPromiseResolved("permissionPromise", (element, result) => {
200
+ /* Removed while the permission prompt was open: no disconnect will
201
+ clean up, so attach nothing. A later reconnect requests again via
202
+ `onConnected`. */
203
+ if (!element.isConnected) return;
204
+ // @ts-ignore TODO fix onPromiseResolved types
205
+ if (result?.permissionPromise === "granted") {
206
+ return { _attachCompassListener: [] };
207
+ }
208
+ return { handleError: ["Device orientation permission denied"] };
209
+ })
210
+ .onPromiseRejected("permissionPromise", (_, err) => ({
211
+ handleError: [err],
212
+ }))
213
+ .onCommand("--request", () => ({ makeRequest: [] }))
214
+ .onEventDefault("provider-orientation-success", (_, { detail }) => ({
215
+ provision: detail,
216
+ isRequesting: false,
217
+ isSuccess: true,
218
+ isError: false,
219
+ }))
220
+ .onEventDefault("provider-orientation-error", (_, { detail }) => ({
221
+ provision: detail,
222
+ isRequesting: false,
223
+ isSuccess: false,
224
+ isError: true,
225
+ }));
@@ -0,0 +1 @@
1
+ Caching has been disabled for this project's "apply-exports" command.
@@ -0,0 +1 @@
1
+ Invoking: cd "$RUSH_PROJECT_FOLDER" && node ../heft-rig/scripts/apply-exports.mjs
@@ -0,0 +1 @@
1
+ This project does not define the caching behavior of the "build:docs" command, so caching has been disabled.
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs
@@ -0,0 +1 @@
1
+ This project does not define the caching behavior of the "build:package-metas" command, so caching has been disabled.
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs
@@ -0,0 +1,208 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "modules": [
4
+ {
5
+ "kind": "javascript-module",
6
+ "path": "provider-orientation.ts",
7
+ "declarations": [
8
+ {
9
+ "kind": "class",
10
+ "name": "ProviderOrientation",
11
+ "customElement": true,
12
+ "tagName": "provider-orientation",
13
+ "description": "Wraps the device orientation / compass APIs — request a heading and read updates from attributes/state, no app JS required. Requests on connect unless `is-paused`, same as the other `provider-*` elements — but on iOS that request must happen synchronously inside a user gesture (`DeviceOrientationEvent.requestPermission()`), so a connect-time request will silently fail there. **Set `is-paused` and invoke the `--request` command from a button instead** unless you know your app only targets Android/desktop (the handler runs in a microtask of the click, inside its user activation). Bearing (`provision.bearing`) is normalized to degrees clockwise from magnetic north (`0`–`360`) across both the iOS (`webkitCompassHeading`) and Android/absolute (`alpha`) code paths, so consumers don't need to branch on platform. Lifecycle: the `window` listener is tracked by Neutron — removed when the element leaves the document, restored (and the request repeated unless `is-paused`) when it is reconnected, and kept across a DOM move. Removing the element while an iOS permission prompt is still open abandons that request: nothing is attached when it settles, and a later reconnect requests again.",
14
+ "attributes": [
15
+ {
16
+ "name": "is-paused",
17
+ "type": {
18
+ "text": "boolean"
19
+ },
20
+ "description": "Skip requesting on connect. On iOS this is effectively required (a connect-time request happens outside a user gesture and will be denied) — pair with `provider-orientation-request` from a click handler instead (see class docs).",
21
+ "fieldName": "isPaused"
22
+ },
23
+ {
24
+ "name": "compass-throttle-ms",
25
+ "type": {
26
+ "text": "number"
27
+ },
28
+ "description": "Minimum ms between `provider-orientation-success` updates. Android can fire `deviceorientationabsolute` at 60-200 Hz; without throttling that floods listeners and CSS/Quark bindings.",
29
+ "fieldName": "compassThrottleMs",
30
+ "default": 100
31
+ },
32
+ {
33
+ "name": "is-requesting",
34
+ "type": {
35
+ "text": "boolean"
36
+ },
37
+ "description": "iOS only: the permission request is pending (between `provider-orientation-request` and the user's response).",
38
+ "fieldName": "isRequesting"
39
+ },
40
+ {
41
+ "name": "is-success",
42
+ "type": {
43
+ "text": "boolean"
44
+ },
45
+ "description": "Listening for orientation updates (permission granted where required). Stays set across updates.",
46
+ "fieldName": "isSuccess"
47
+ },
48
+ {
49
+ "name": "is-error",
50
+ "type": {
51
+ "text": "boolean"
52
+ },
53
+ "description": "The permission request was denied, or listening failed to start.",
54
+ "fieldName": "isError"
55
+ }
56
+ ],
57
+ "members": [
58
+ {
59
+ "kind": "field",
60
+ "name": "isPaused",
61
+ "type": {
62
+ "text": "boolean"
63
+ },
64
+ "privacy": "public",
65
+ "readonly": false,
66
+ "description": "Skip requesting on connect. On iOS this is effectively required (a connect-time request happens outside a user gesture and will be denied) — pair with `provider-orientation-request` from a click handler instead (see class docs).",
67
+ "_neutron": {
68
+ "surface": "option"
69
+ }
70
+ },
71
+ {
72
+ "kind": "field",
73
+ "name": "compassThrottleMs",
74
+ "type": {
75
+ "text": "number"
76
+ },
77
+ "privacy": "public",
78
+ "readonly": false,
79
+ "description": "Minimum ms between `provider-orientation-success` updates. Android can fire `deviceorientationabsolute` at 60-200 Hz; without throttling that floods listeners and CSS/Quark bindings.",
80
+ "default": 100,
81
+ "_neutron": {
82
+ "surface": "option"
83
+ }
84
+ },
85
+ {
86
+ "kind": "field",
87
+ "name": "isRequesting",
88
+ "type": {
89
+ "text": "boolean"
90
+ },
91
+ "privacy": "public",
92
+ "readonly": true,
93
+ "description": "iOS only: the permission request is pending (between `provider-orientation-request` and the user's response).",
94
+ "_neutron": {
95
+ "surface": "state"
96
+ }
97
+ },
98
+ {
99
+ "kind": "field",
100
+ "name": "isSuccess",
101
+ "type": {
102
+ "text": "boolean"
103
+ },
104
+ "privacy": "public",
105
+ "readonly": true,
106
+ "description": "Listening for orientation updates (permission granted where required). Stays set across updates.",
107
+ "_neutron": {
108
+ "surface": "state"
109
+ }
110
+ },
111
+ {
112
+ "kind": "field",
113
+ "name": "isError",
114
+ "type": {
115
+ "text": "boolean"
116
+ },
117
+ "privacy": "public",
118
+ "readonly": true,
119
+ "description": "The permission request was denied, or listening failed to start.",
120
+ "_neutron": {
121
+ "surface": "state"
122
+ }
123
+ },
124
+ {
125
+ "kind": "field",
126
+ "name": "provision",
127
+ "type": {
128
+ "text": "ProviderOrientationSuccess",
129
+ "expanded": "{ bearing: number; alpha: number | null; }"
130
+ },
131
+ "privacy": "public",
132
+ "readonly": false,
133
+ "description": "Latest reading: `{ bearing, alpha }` on success, or the error on failure. Not reflected as an attribute.",
134
+ "_neutron": {
135
+ "surface": "option"
136
+ }
137
+ }
138
+ ],
139
+ "events": [
140
+ {
141
+ "name": "provider-orientation-success",
142
+ "description": "Dispatched on every compass update (throttled by `compass-throttle-ms`). `bearing` is normalized 0-360°; `alpha` is the raw `DeviceOrientationEvent.alpha` where available.",
143
+ "type": {
144
+ "text": "ProviderOrientationSuccessEvent",
145
+ "expanded": "CustomEvent & { type: \"provider-orientation-success\"; detail: { bearing: number; alpha: number | null; }; bubbles: true; cancelable: true; composed: true }"
146
+ }
147
+ },
148
+ {
149
+ "name": "provider-orientation-error",
150
+ "description": "Dispatched when the permission request is denied, or fails for any other reason.",
151
+ "type": {
152
+ "text": "ProviderOrientationErrorEvent",
153
+ "expanded": "CustomEvent & { type: \"provider-orientation-error\"; detail: string | Error; bubbles: true; cancelable: true; composed: true }"
154
+ }
155
+ }
156
+ ],
157
+ "_neutron": {
158
+ "provisions": [
159
+ {
160
+ "name": "provision",
161
+ "type": {
162
+ "text": "ProviderOrientationSuccess",
163
+ "expanded": "{ bearing: number; alpha: number | null; }"
164
+ },
165
+ "description": "Latest reading: `{ bearing, alpha }` on success, or the error on failure. Not reflected as an attribute.",
166
+ "fieldName": "provision"
167
+ }
168
+ ],
169
+ "commands": [
170
+ {
171
+ "name": "--request",
172
+ "description": "Requests permission (iOS) and starts listening for orientation updates. Invoke it from a button (`<button command=\"--request\" commandfor=\"…\">`) so the user activation is there."
173
+ }
174
+ ],
175
+ "defaultActions": [
176
+ {
177
+ "name": "provider-orientation-success",
178
+ "description": "Stores `{ bearing, alpha }` in `provision` and sets `is-success` (clearing `is-requesting` / `is-error`)."
179
+ },
180
+ {
181
+ "name": "provider-orientation-error",
182
+ "description": "Stores the error in `provision` and sets `is-error` (clearing `is-requesting` / `is-success`)."
183
+ }
184
+ ]
185
+ }
186
+ }
187
+ ],
188
+ "exports": [
189
+ {
190
+ "kind": "js",
191
+ "name": "ProviderOrientation",
192
+ "declaration": {
193
+ "name": "ProviderOrientation",
194
+ "module": "provider-orientation.ts"
195
+ }
196
+ },
197
+ {
198
+ "kind": "custom-element-definition",
199
+ "name": "provider-orientation",
200
+ "declaration": {
201
+ "name": "ProviderOrientation",
202
+ "module": "provider-orientation.ts"
203
+ }
204
+ }
205
+ ]
206
+ }
207
+ ]
208
+ }
@@ -0,0 +1,14 @@
1
+ <div id="orient-demo">
2
+ <button type="button" command="--request" commandfor="orient">
3
+ Enable compass
4
+ </button>
5
+ <provider-orientation id="orient" is-paused></provider-orientation>
6
+ <p class="status">No reading yet — click above. Requires a device
7
+ sensor (desktop browsers usually have none).</p>
8
+ <output>Waiting…</output>
9
+ <quark-sheet>
10
+ @use "/demo-utils" as *;
11
+
12
+ #orient-demo { @on neutron-provision (handle: setOutputFromElementData); }
13
+ </quark-sheet>
14
+ </div>