@urk/adapters 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 (47) hide show
  1. package/README.md +80 -0
  2. package/dist/adapters.d.ts +11 -0
  3. package/dist/adapters.d.ts.map +1 -0
  4. package/dist/adapters.js +11 -0
  5. package/dist/adapters.js.map +1 -0
  6. package/dist/contracts.d.ts +11 -0
  7. package/dist/contracts.d.ts.map +1 -0
  8. package/dist/contracts.js +11 -0
  9. package/dist/contracts.js.map +1 -0
  10. package/dist/index.d.ts +5 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +5 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/input.d.ts +37 -0
  15. package/dist/input.d.ts.map +1 -0
  16. package/dist/input.js +137 -0
  17. package/dist/input.js.map +1 -0
  18. package/dist/loading.d.ts +35 -0
  19. package/dist/loading.d.ts.map +1 -0
  20. package/dist/loading.js +123 -0
  21. package/dist/loading.js.map +1 -0
  22. package/dist/pointer.d.ts +43 -0
  23. package/dist/pointer.d.ts.map +1 -0
  24. package/dist/pointer.js +135 -0
  25. package/dist/pointer.js.map +1 -0
  26. package/dist/storage.d.ts +24 -0
  27. package/dist/storage.d.ts.map +1 -0
  28. package/dist/storage.js +125 -0
  29. package/dist/storage.js.map +1 -0
  30. package/dist/three.d.ts +28 -0
  31. package/dist/three.d.ts.map +1 -0
  32. package/dist/three.js +131 -0
  33. package/dist/three.js.map +1 -0
  34. package/dist/ui-widgets.d.ts +23 -0
  35. package/dist/ui-widgets.d.ts.map +1 -0
  36. package/dist/ui-widgets.js +92 -0
  37. package/dist/ui-widgets.js.map +1 -0
  38. package/package.json +35 -0
  39. package/src/adapters.ts +11 -0
  40. package/src/contracts.ts +15 -0
  41. package/src/index.ts +5 -0
  42. package/src/input.ts +207 -0
  43. package/src/loading.ts +174 -0
  44. package/src/pointer.ts +203 -0
  45. package/src/storage.ts +194 -0
  46. package/src/three.ts +178 -0
  47. package/src/ui-widgets.ts +120 -0
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # @urk/adapters
2
+
3
+ Contract-first capability adapters that prove URK's v0 kernel surface.
4
+
5
+ ## Reference adapters
6
+
7
+ - `createPointerAdapter()` - bind DOM targets or pointer surfaces and emit normalized pointer events
8
+ - `createInputAdapter()` - normalize keyboard input, track pressed keys, and bind simple key handlers
9
+ - `createStorageAdapter()` - provide namespaced local/session key-value persistence with swappable backends
10
+ - `createLoadingAdapter()` - track staged progress with an observable loading snapshot
11
+ - `createThreeAdapter()` - mount a small Three scene surface onto a host element and expose render primitives
12
+ - `createUiWidgetsAdapter()` - mount a small overlay shell with status and callout surfaces
13
+
14
+ ## Usage
15
+
16
+ ```ts
17
+ import { createKernel } from '@urk/core';
18
+ import {
19
+ createInputAdapter,
20
+ createPointerAdapter,
21
+ createStorageAdapter,
22
+ createThreeAdapter,
23
+ createUiWidgetsAdapter,
24
+ } from '@urk/adapters';
25
+
26
+ const kernel = createKernel({
27
+ services: {
28
+ 'three:host': document.querySelector('#scene-host'),
29
+ 'ui:host': document.querySelector('#overlay-host'),
30
+ },
31
+ adapters: [
32
+ createPointerAdapter(),
33
+ createInputAdapter(),
34
+ createStorageAdapter({ namespace: 'demo' }),
35
+ createThreeAdapter(),
36
+ createUiWidgetsAdapter(),
37
+ ],
38
+ });
39
+
40
+ await kernel.boot();
41
+ ```
42
+
43
+ These adapters use the canonical `AdapterRegistration<TApi>` contract from `@urk/core`. They are intentionally small and exist to prove the kernel surface, not to introduce a broad adapter matrix early.
44
+
45
+ `createInputAdapter()` is deliberately keyboard-first in this milestone:
46
+
47
+ - pressed-key tracking through `isPressed(code)`
48
+ - key bindings through `bindKey(binding)`
49
+ - normalized keyboard event subscriptions through `subscribe(listener)`
50
+ - no named action map, gamepad support, text-entry model, or focus-management system yet
51
+
52
+ `createStorageAdapter()` is deliberately small in this milestone:
53
+
54
+ - local and session key-value access through one adapter capability
55
+ - namespaced keys so clear operations do not wipe unrelated browser storage
56
+ - optional `storage:local` and `storage:session` service overrides for swappable backends
57
+ - no IndexedDB, sync, cross-tab coordination, or product-facing save model yet
58
+
59
+ `createPointerAdapter()` now covers two small interaction paths:
60
+
61
+ - `bindTarget(...)` for DOM-target hover and select events
62
+ - `bindSurface(...)` for normalized scene-surface move, leave, and select events
63
+ - no drag model, press-and-hold semantics, or gesture layer yet
64
+
65
+ `createThreeAdapter()` is deliberately scene-surface-first in this milestone:
66
+
67
+ - requires a `three:host` `HTMLElement` service
68
+ - owns the `Scene`, `PerspectiveCamera`, `WebGLRenderer`, and mounted canvas
69
+ - keeps renderer and camera size in sync with the host element
70
+ - exposes `raycast(clientX, clientY, objects)` so controllers can own picking behavior
71
+ - does not own scene objects created by controllers
72
+ - does not own selection state, drag helpers, or its own render loop
73
+
74
+ ## Validation
75
+
76
+ This package is validated for this milestone through type-check/build plus the standalone DOM + Three picking proof in `@urk/examples`.
77
+
78
+ ## Architecture
79
+
80
+ See `/docs/07_URK/URK_ARCHITECTURE.md`
@@ -0,0 +1,11 @@
1
+ /**
2
+ * URK adapter exports.
3
+ */
4
+ export * from './loading';
5
+ export * from './input';
6
+ export * from './pointer';
7
+ export * from './storage';
8
+ export * from './three';
9
+ export * from './ui-widgets';
10
+ export * from './contracts';
11
+ //# sourceMappingURL=adapters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * URK adapter exports.
3
+ */
4
+ export * from './loading';
5
+ export * from './input';
6
+ export * from './pointer';
7
+ export * from './storage';
8
+ export * from './three';
9
+ export * from './ui-widgets';
10
+ export * from './contracts';
11
+ //# sourceMappingURL=adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Company: EonHive Inc.
3
+ * Title: Adapter Contracts
4
+ * Purpose: Re-export the canonical kernel adapter contracts from @urk/core.
5
+ * Author: Stan Nesi
6
+ * Created: 2026-04-12
7
+ * Updated: 2026-04-15
8
+ * Notes: Vibe coded with Codex.
9
+ */
10
+ export type { AdapterRegistration, KernelEvent, RuntimeContext, } from '@urk/core';
11
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,cAAc,GACf,MAAM,WAAW,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Company: EonHive Inc.
3
+ * Title: Adapter Contracts
4
+ * Purpose: Re-export the canonical kernel adapter contracts from @urk/core.
5
+ * Author: Stan Nesi
6
+ * Created: 2026-04-12
7
+ * Updated: 2026-04-15
8
+ * Notes: Vibe coded with Codex.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * URK Adapters - Contract-first capability adapters.
3
+ */
4
+ export * from './adapters';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * URK Adapters - Contract-first capability adapters.
3
+ */
4
+ export * from './adapters';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Company: EonHive Inc.
3
+ * Title: Input Adapter
4
+ * Purpose: Normalize keyboard input into a small reusable runtime capability.
5
+ * Author: Stan Nesi
6
+ * Created: 2026-04-20
7
+ * Updated: 2026-04-20
8
+ * Notes: Vibe coded with Codex.
9
+ */
10
+ import type { AdapterRegistration } from '@urk/core';
11
+ export type InputEventPhase = 'down' | 'up';
12
+ export interface InputKeyEvent {
13
+ code: string;
14
+ key: string;
15
+ phase: InputEventPhase;
16
+ repeat: boolean;
17
+ altKey: boolean;
18
+ ctrlKey: boolean;
19
+ metaKey: boolean;
20
+ shiftKey: boolean;
21
+ nativeEvent: KeyboardEvent;
22
+ }
23
+ export interface InputBinding {
24
+ code: string;
25
+ phase?: InputEventPhase;
26
+ allowRepeat?: boolean;
27
+ handler: (event: InputKeyEvent) => void;
28
+ }
29
+ export type InputListener = (event: InputKeyEvent) => void;
30
+ export interface InputAdapterApi {
31
+ isPressed(code: string): boolean;
32
+ bindKey(binding: InputBinding): () => void;
33
+ subscribe(listener: InputListener): () => void;
34
+ clear(): void;
35
+ }
36
+ export declare function createInputAdapter(id?: string): AdapterRegistration<InputAdapterApi>;
37
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,WAAW,CAAC;AAErE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,IAAI,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,aAAa,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAE3D,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI,CAAC;IAC3C,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,IAAI,CAAC;IAC/C,KAAK,IAAI,IAAI,CAAC;CACf;AAkDD,wBAAgB,kBAAkB,CAChC,EAAE,SAAkB,GACnB,mBAAmB,CAAC,eAAe,CAAC,CAkHtC"}
package/dist/input.js ADDED
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Company: EonHive Inc.
3
+ * Title: Input Adapter
4
+ * Purpose: Normalize keyboard input into a small reusable runtime capability.
5
+ * Author: Stan Nesi
6
+ * Created: 2026-04-20
7
+ * Updated: 2026-04-20
8
+ * Notes: Vibe coded with Codex.
9
+ */
10
+ function resolveInputTarget(ctx) {
11
+ const serviceTarget = ctx.services.get('input:target');
12
+ if (serviceTarget === undefined) {
13
+ return window;
14
+ }
15
+ if (serviceTarget === window) {
16
+ return window;
17
+ }
18
+ if (typeof Document !== 'undefined' && serviceTarget instanceof Document) {
19
+ return serviceTarget;
20
+ }
21
+ if (typeof HTMLElement !== 'undefined' && serviceTarget instanceof HTMLElement) {
22
+ return serviceTarget;
23
+ }
24
+ throw new Error('Service input:target must be a Window, Document, or HTMLElement.');
25
+ }
26
+ function createInputEvent(phase, nativeEvent) {
27
+ return {
28
+ code: nativeEvent.code || nativeEvent.key,
29
+ key: nativeEvent.key,
30
+ phase,
31
+ repeat: nativeEvent.repeat,
32
+ altKey: nativeEvent.altKey,
33
+ ctrlKey: nativeEvent.ctrlKey,
34
+ metaKey: nativeEvent.metaKey,
35
+ shiftKey: nativeEvent.shiftKey,
36
+ nativeEvent,
37
+ };
38
+ }
39
+ export function createInputAdapter(id = 'input-adapter') {
40
+ let disposeTargetListeners = null;
41
+ return {
42
+ id,
43
+ capability: 'input',
44
+ isSupported() {
45
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
46
+ },
47
+ setup(ctx) {
48
+ const target = resolveInputTarget(ctx);
49
+ const resetTarget = window;
50
+ const pressedCodes = new Set();
51
+ const bindings = new Set();
52
+ const listeners = new Set();
53
+ const publish = (event) => {
54
+ ctx.events.emit({
55
+ type: event.phase === 'down' ? 'input:key-down' : 'input:key-up',
56
+ source: id,
57
+ payload: event,
58
+ timestamp: Date.now(),
59
+ });
60
+ for (const listener of [...listeners]) {
61
+ listener(event);
62
+ }
63
+ for (const binding of [...bindings]) {
64
+ if (binding.code !== event.code || binding.phase !== event.phase) {
65
+ continue;
66
+ }
67
+ if (event.repeat && !binding.allowRepeat) {
68
+ continue;
69
+ }
70
+ binding.handler(event);
71
+ }
72
+ };
73
+ const onKeyDown = (nativeEvent) => {
74
+ if (!(nativeEvent instanceof KeyboardEvent)) {
75
+ return;
76
+ }
77
+ const event = createInputEvent('down', nativeEvent);
78
+ pressedCodes.add(event.code);
79
+ publish(event);
80
+ };
81
+ const onKeyUp = (nativeEvent) => {
82
+ if (!(nativeEvent instanceof KeyboardEvent)) {
83
+ return;
84
+ }
85
+ const event = createInputEvent('up', nativeEvent);
86
+ pressedCodes.delete(event.code);
87
+ publish(event);
88
+ };
89
+ const onBlur = () => {
90
+ pressedCodes.clear();
91
+ };
92
+ target.addEventListener('keydown', onKeyDown);
93
+ target.addEventListener('keyup', onKeyUp);
94
+ resetTarget.addEventListener('blur', onBlur);
95
+ // Keep the public API minimal while still ensuring dispose can tear down DOM listeners.
96
+ disposeTargetListeners = () => {
97
+ target.removeEventListener('keydown', onKeyDown);
98
+ target.removeEventListener('keyup', onKeyUp);
99
+ resetTarget.removeEventListener('blur', onBlur);
100
+ };
101
+ return {
102
+ isPressed(code) {
103
+ return pressedCodes.has(code);
104
+ },
105
+ bindKey(binding) {
106
+ const normalizedBinding = {
107
+ code: binding.code,
108
+ phase: binding.phase ?? 'down',
109
+ allowRepeat: binding.allowRepeat ?? false,
110
+ handler: binding.handler,
111
+ };
112
+ bindings.add(normalizedBinding);
113
+ return () => {
114
+ bindings.delete(normalizedBinding);
115
+ };
116
+ },
117
+ subscribe(listener) {
118
+ listeners.add(listener);
119
+ return () => {
120
+ listeners.delete(listener);
121
+ };
122
+ },
123
+ clear() {
124
+ pressedCodes.clear();
125
+ bindings.clear();
126
+ listeners.clear();
127
+ },
128
+ };
129
+ },
130
+ dispose(_ctx, api) {
131
+ disposeTargetListeners?.();
132
+ disposeTargetListeners = null;
133
+ api.clear();
134
+ },
135
+ };
136
+ }
137
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Company: EonHive Inc.
3
+ * Title: Loading Adapter
4
+ * Purpose: Track staged loading progress and expose a small observable API.
5
+ * Author: Stan Nesi
6
+ * Created: 2026-04-12
7
+ * Updated: 2026-04-15
8
+ * Notes: Vibe coded with Codex.
9
+ */
10
+ import type { AdapterRegistration } from '@urk/core';
11
+ export interface LoadingStage {
12
+ id: string;
13
+ label: string;
14
+ weight?: number;
15
+ }
16
+ export interface LoadingSnapshot {
17
+ active: boolean;
18
+ complete: boolean;
19
+ progress: number;
20
+ message: string;
21
+ stageId: string | null;
22
+ stageLabel: string | null;
23
+ stages: LoadingStage[];
24
+ updatedAt: number;
25
+ }
26
+ export type LoadingListener = (snapshot: LoadingSnapshot) => void;
27
+ export interface LoadingAdapterApi {
28
+ begin(stages: LoadingStage[], message?: string): LoadingSnapshot;
29
+ setStage(stageId: string, progressWithinStage: number, message?: string): LoadingSnapshot;
30
+ complete(message?: string): LoadingSnapshot;
31
+ getSnapshot(): LoadingSnapshot;
32
+ subscribe(listener: LoadingListener): () => void;
33
+ }
34
+ export declare function createLoadingAdapter(id?: string): AdapterRegistration<LoadingAdapterApi>;
35
+ //# sourceMappingURL=loading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loading.d.ts","sourceRoot":"","sources":["../src/loading.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;AAElE,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAC1F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAC5C,WAAW,IAAI,eAAe,CAAC;IAC/B,SAAS,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI,CAAC;CAClD;AA8BD,wBAAgB,oBAAoB,CAClC,EAAE,SAAoB,GACrB,mBAAmB,CAAC,iBAAiB,CAAC,CAwGxC"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Company: EonHive Inc.
3
+ * Title: Loading Adapter
4
+ * Purpose: Track staged loading progress and expose a small observable API.
5
+ * Author: Stan Nesi
6
+ * Created: 2026-04-12
7
+ * Updated: 2026-04-15
8
+ * Notes: Vibe coded with Codex.
9
+ */
10
+ function normalizeStages(stages) {
11
+ if (stages.length === 0) {
12
+ throw new Error('Loading adapter requires at least one stage.');
13
+ }
14
+ return stages.map((stage) => ({
15
+ ...stage,
16
+ weight: stage.weight && stage.weight > 0 ? stage.weight : 1,
17
+ }));
18
+ }
19
+ function clampProgress(progress) {
20
+ return Math.max(0, Math.min(progress, 1));
21
+ }
22
+ function createEmptySnapshot() {
23
+ return {
24
+ active: false,
25
+ complete: false,
26
+ progress: 0,
27
+ message: 'Waiting to start',
28
+ stageId: null,
29
+ stageLabel: null,
30
+ stages: [],
31
+ updatedAt: Date.now(),
32
+ };
33
+ }
34
+ export function createLoadingAdapter(id = 'loading-adapter') {
35
+ return {
36
+ id,
37
+ capability: 'loading',
38
+ setup(ctx) {
39
+ let snapshot = createEmptySnapshot();
40
+ const listeners = new Set();
41
+ const publish = () => {
42
+ const next = { ...snapshot, stages: [...snapshot.stages] };
43
+ ctx.events.emit({
44
+ type: 'loading:changed',
45
+ source: id,
46
+ payload: next,
47
+ timestamp: Date.now(),
48
+ });
49
+ for (const listener of [...listeners]) {
50
+ listener(next);
51
+ }
52
+ return next;
53
+ };
54
+ const getTotalWeight = () => {
55
+ return snapshot.stages.reduce((total, stage) => total + (stage.weight ?? 1), 0);
56
+ };
57
+ return {
58
+ begin(stages, message = 'Starting load') {
59
+ const nextStages = normalizeStages(stages);
60
+ const firstStage = nextStages[0];
61
+ snapshot = {
62
+ active: true,
63
+ complete: false,
64
+ progress: 0,
65
+ message,
66
+ stageId: firstStage.id,
67
+ stageLabel: firstStage.label,
68
+ stages: nextStages,
69
+ updatedAt: Date.now(),
70
+ };
71
+ return publish();
72
+ },
73
+ setStage(stageId, progressWithinStage, message) {
74
+ const stageIndex = snapshot.stages.findIndex((stage) => stage.id === stageId);
75
+ if (stageIndex === -1) {
76
+ throw new Error(`Unknown loading stage: ${stageId}`);
77
+ }
78
+ const previousWeight = snapshot.stages
79
+ .slice(0, stageIndex)
80
+ .reduce((total, stage) => total + (stage.weight ?? 1), 0);
81
+ const currentStage = snapshot.stages[stageIndex];
82
+ const totalWeight = getTotalWeight();
83
+ const progress = (previousWeight + (currentStage.weight ?? 1) * clampProgress(progressWithinStage)) /
84
+ totalWeight;
85
+ snapshot = {
86
+ ...snapshot,
87
+ active: true,
88
+ progress,
89
+ message: message ?? snapshot.message,
90
+ stageId: currentStage.id,
91
+ stageLabel: currentStage.label,
92
+ updatedAt: Date.now(),
93
+ };
94
+ return publish();
95
+ },
96
+ complete(message = 'Loading complete') {
97
+ const lastStage = snapshot.stages[snapshot.stages.length - 1] ?? null;
98
+ snapshot = {
99
+ ...snapshot,
100
+ active: false,
101
+ complete: true,
102
+ progress: 1,
103
+ message,
104
+ stageId: lastStage?.id ?? null,
105
+ stageLabel: lastStage?.label ?? null,
106
+ updatedAt: Date.now(),
107
+ };
108
+ return publish();
109
+ },
110
+ getSnapshot() {
111
+ return { ...snapshot, stages: [...snapshot.stages] };
112
+ },
113
+ subscribe(listener) {
114
+ listeners.add(listener);
115
+ return () => {
116
+ listeners.delete(listener);
117
+ };
118
+ },
119
+ };
120
+ },
121
+ };
122
+ }
123
+ //# sourceMappingURL=loading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loading.js","sourceRoot":"","sources":["../src/loading.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Company: EonHive Inc.
3
+ * Title: Pointer Adapter
4
+ * Purpose: Normalize pointer target binding and emit interaction events.
5
+ * Author: Stan Nesi
6
+ * Created: 2026-04-12
7
+ * Updated: 2026-04-22
8
+ * Notes: Vibe coded with Codex.
9
+ */
10
+ import type { AdapterRegistration } from '@urk/core';
11
+ export interface PointerTargetDefinition {
12
+ id: string;
13
+ element: HTMLElement;
14
+ meta?: Record<string, unknown>;
15
+ }
16
+ export interface PointerTargetEventPayload {
17
+ targetId: string;
18
+ element: HTMLElement;
19
+ meta?: Record<string, unknown>;
20
+ nativeEvent: MouseEvent | PointerEvent;
21
+ }
22
+ export interface PointerSurfaceDefinition {
23
+ id: string;
24
+ element: HTMLElement;
25
+ meta?: Record<string, unknown>;
26
+ }
27
+ export interface PointerSurfaceEventPayload {
28
+ surfaceId: string;
29
+ element: HTMLElement;
30
+ meta?: Record<string, unknown>;
31
+ clientX: number;
32
+ clientY: number;
33
+ localX: number;
34
+ localY: number;
35
+ nativeEvent: MouseEvent | PointerEvent;
36
+ }
37
+ export interface PointerAdapterApi {
38
+ bindTarget(target: PointerTargetDefinition): () => void;
39
+ bindSurface(surface: PointerSurfaceDefinition): () => void;
40
+ clear(): void;
41
+ }
42
+ export declare function createPointerAdapter(id?: string): AdapterRegistration<PointerAdapterApi>;
43
+ //# sourceMappingURL=pointer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pointer.d.ts","sourceRoot":"","sources":["../src/pointer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,WAAW,EAAE,UAAU,GAAG,YAAY,CAAC;CACxC;AAED,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,UAAU,GAAG,YAAY,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,MAAM,EAAE,uBAAuB,GAAG,MAAM,IAAI,CAAC;IACxD,WAAW,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,IAAI,CAAC;IAC3D,KAAK,IAAI,IAAI,CAAC;CACf;AAqBD,wBAAgB,oBAAoB,CAClC,EAAE,SAAoB,GACrB,mBAAmB,CAAC,iBAAiB,CAAC,CAqIxC"}