cereb 0.10.0 → 0.11.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Cereb
2
2
 
3
3
  **User input handling and orchestration** libray,
4
- From low-level events (keyboard, wheel, pointer) to high-level gestures (pan, pinch)
4
+ From low-level events (keyboard, wheel, pointer, ...) to high-level gestures (pan, pinch, ...)
5
5
 
6
6
  ```bash
7
7
  npm install --save cereb
@@ -115,42 +115,39 @@ Model events as streams, and you get readable, reusable, extensible declarative
115
115
 
116
116
  ```typescript
117
117
  // After: Clear flow, no side effects, composable
118
- import { keyboard, keyboardHeld, wheel, domEvent } from "cereb";
119
- import { zoom, extend, when } from "cereb/operators";
118
+ import { keydown, keyheld, wheel, domEvent } from "cereb";
119
+ import { zoom as createZoom, when, extend, spy } from "cereb/operators";
120
120
  import { pinch } from "@cereb/pinch";
121
121
 
122
- const MIN_SCALE = 0.2, MAX_SCALE = 5;
122
+ const zoomMode$ = keyheld(window, { code: "KeyZ" });
123
+ const zoom = (op) => createZoom({ minScale: 0.5, maxScale: 3.0, baseScale: getScale, ...op });
123
124
 
124
- // 'z' key pressed to enter Zoom Mode Stream
125
- const isInZoomMode$ = keyboardHeld(window, { key: "z" });
126
- isInZoomMode$.on(toggleZoomModeIndicator);
127
-
128
- // Pinch Zoom
129
- pinch(box, { threshold: 10 })
130
- .pipe(zoom({ minScale: MIN_SCALE, maxScale: MAX_SCALE }))
131
- .on(render);
125
+ // Pinch zoom - baseScale syncs with external state
126
+ pinch(element)
127
+ .pipe(zoom())
128
+ .on(applyScale);
132
129
 
133
- // 'z' + '+/-'
134
- keyboard(window, { key: ["+", "=", "-"], preventDefault: true })
130
+ // z + wheel zoom - ratio as multiplicative factor
131
+ wheel(element, { passive: false })
135
132
  .pipe(
136
- when(isInZoomMode$),
137
- extend<KeyboardSignal, ZoomInput>((signal) => ({
138
- ratio: zoomManager.getScale() + (signal.value.key === "+" || signal.value.key === "=" ? 0.15 : -0.15),
139
- })),
140
- zoom({ minScale: MIN_SCALE, maxScale: MAX_SCALE }),
141
- ).on(render);
133
+ when(zoomMode$),
134
+ spy((signal) => signal.value.originalEvent.preventDefault()),
135
+ extend((signal) => ({ ratio: Math.exp(-signal.value.deltaY * 0.005) })),
136
+ zoom(),
137
+ )
138
+ .on(applyScale);
142
139
 
143
- // 'z' + 'wheel'
144
- wheel(box, { passive: false, preventDefault: true })
140
+ // z + '+/-' zoom - ratio as multiplier
141
+ keydown(window, { code: ["Equal", "Minus"] })
145
142
  .pipe(
146
- when(isInZoomMode$),
147
- extend<WheelSignal, ZoomInput>((signal) => ({
148
- ratio: zoomManager.getScale() + (-signal.value.deltaY * 0.005),
149
- })),
150
- zoom({ minScale: MIN_SCALE, maxScale: MAX_SCALE }),
151
- ).on(render);
143
+ when(zoomMode$),
144
+ spy((signal) => signal.value.originalEvent.preventDefault()),
145
+ extend((signal) => ({ ratio: signal.value.code === "Equal" ? 1.2 : 1 / 1.2 })),
146
+ zoom(),
147
+ )
148
+ .on(applyScale);
152
149
 
153
- // 'Slider Input'
150
+ // 'Slider Input' - sets absolute scale, so ratio is the target scale itself
154
151
  domEvent(slider, "input")
155
152
  .pipe(
156
153
  extend<DomEventSignal<Event>, ZoomInput>((signal) => {
@@ -162,7 +159,7 @@ domEvent(slider, "input")
162
159
  ratio: clamp(scale, MIN_SCALE, MAX_SCALE),
163
160
  };
164
161
  }),
165
- zoom({ minScale: MIN_SCALE, maxScale: MAX_SCALE, baseScale: zoomManager.getScale() }),
162
+ zoom({ baseScale: 1.0 }), // baseScale = 1.0 for absolute scale
166
163
  ).on(render);
167
164
  ```
168
165
 
@@ -1,4 +1,6 @@
1
+ export * from './key-code.js';
1
2
  export * from './keyboard.js';
2
- export * from './keyboard-held.js';
3
3
  export * from './keyboard-signal.js';
4
+ export * from './keydown.js';
5
+ export * from './keyheld.js';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * KeyboardEvent.code values for physical key identification.
3
+ * Based on W3C UI Events KeyboardEvent code Values specification.
4
+ *
5
+ * @see https://www.w3.org/TR/uievents-code/
6
+ */
7
+ /** Alphanumeric keys (US QWERTY writing system) */
8
+ type AlphaKey = "KeyA" | "KeyB" | "KeyC" | "KeyD" | "KeyE" | "KeyF" | "KeyG" | "KeyH" | "KeyI" | "KeyJ" | "KeyK" | "KeyL" | "KeyM" | "KeyN" | "KeyO" | "KeyP" | "KeyQ" | "KeyR" | "KeyS" | "KeyT" | "KeyU" | "KeyV" | "KeyW" | "KeyX" | "KeyY" | "KeyZ";
9
+ type DigitKey = "Digit0" | "Digit1" | "Digit2" | "Digit3" | "Digit4" | "Digit5" | "Digit6" | "Digit7" | "Digit8" | "Digit9";
10
+ /** Punctuation and special character keys */
11
+ type PunctuationKey = "Backquote" | "Minus" | "Equal" | "BracketLeft" | "BracketRight" | "Backslash" | "Semicolon" | "Quote" | "Comma" | "Period" | "Slash" | "IntlBackslash" | "IntlRo" | "IntlYen";
12
+ /** Function keys */
13
+ type FunctionKey = "Escape" | "F1" | "F2" | "F3" | "F4" | "F5" | "F6" | "F7" | "F8" | "F9" | "F10" | "F11" | "F12" | "F13" | "F14" | "F15" | "F16" | "F17" | "F18" | "F19" | "F20" | "F21" | "F22" | "F23" | "F24" | "PrintScreen" | "ScrollLock" | "Pause";
14
+ /** Navigation keys */
15
+ type NavigationKey = "ArrowUp" | "ArrowDown" | "ArrowLeft" | "ArrowRight" | "Home" | "End" | "PageUp" | "PageDown";
16
+ /** Editing keys */
17
+ type EditingKey = "Backspace" | "Tab" | "Enter" | "CapsLock" | "Space" | "Insert" | "Delete" | "NumLock";
18
+ /** Modifier keys */
19
+ type ModifierKeyCode = "ShiftLeft" | "ShiftRight" | "ControlLeft" | "ControlRight" | "AltLeft" | "AltRight" | "MetaLeft" | "MetaRight" | "ContextMenu";
20
+ /** Numpad keys */
21
+ type NumpadKey = "Numpad0" | "Numpad1" | "Numpad2" | "Numpad3" | "Numpad4" | "Numpad5" | "Numpad6" | "Numpad7" | "Numpad8" | "Numpad9" | "NumpadAdd" | "NumpadSubtract" | "NumpadMultiply" | "NumpadDivide" | "NumpadDecimal" | "NumpadEnter" | "NumpadEqual" | "NumpadComma" | "NumpadParenLeft" | "NumpadParenRight";
22
+ /**
23
+ * All valid KeyboardEvent.code values.
24
+ * Use this type for physical key identification regardless of keyboard layout.
25
+ *
26
+ * @see https://www.w3.org/TR/uievents-code/
27
+ * @example
28
+ * keydown(window, { code: 'KeyZ' }) // Physical Z key position
29
+ * keydown(window, { code: 'Space' }) // Spacebar
30
+ */
31
+ export type KeyCode = AlphaKey | DigitKey | PunctuationKey | FunctionKey | NavigationKey | EditingKey | ModifierKeyCode | NumpadKey;
32
+ export {};
33
+ //# sourceMappingURL=key-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-code.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/key-code.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,mDAAmD;AACnD,KAAK,QAAQ,GACT,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,CAAC;AAEX,KAAK,QAAQ,GACT,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,QAAQ,CAAC;AAEb,6CAA6C;AAC7C,KAAK,cAAc,GACf,WAAW,GACX,OAAO,GACP,OAAO,GACP,aAAa,GACb,cAAc,GACd,WAAW,GACX,WAAW,GACX,OAAO,GACP,OAAO,GACP,QAAQ,GACR,OAAO,GACP,eAAe,GACf,QAAQ,GACR,SAAS,CAAC;AAEd,oBAAoB;AACpB,KAAK,WAAW,GACZ,QAAQ,GACR,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,IAAI,GACJ,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,aAAa,GACb,YAAY,GACZ,OAAO,CAAC;AAEZ,sBAAsB;AACtB,KAAK,aAAa,GACd,SAAS,GACT,WAAW,GACX,WAAW,GACX,YAAY,GACZ,MAAM,GACN,KAAK,GACL,QAAQ,GACR,UAAU,CAAC;AAEf,mBAAmB;AACnB,KAAK,UAAU,GACX,WAAW,GACX,KAAK,GACL,OAAO,GACP,UAAU,GACV,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,SAAS,CAAC;AAEd,oBAAoB;AACpB,KAAK,eAAe,GAChB,WAAW,GACX,YAAY,GACZ,aAAa,GACb,cAAc,GACd,SAAS,GACT,UAAU,GACV,UAAU,GACV,WAAW,GACX,aAAa,CAAC;AAElB,kBAAkB;AAClB,KAAK,SAAS,GACV,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,WAAW,GACX,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,GACd,eAAe,GACf,aAAa,GACb,aAAa,GACb,aAAa,GACb,iBAAiB,GACjB,kBAAkB,CAAC;AAEvB;;;;;;;;GAQG;AACH,MAAM,MAAM,OAAO,GACf,QAAQ,GACR,QAAQ,GACR,cAAc,GACd,WAAW,GACX,aAAa,GACb,UAAU,GACV,eAAe,GACf,SAAS,CAAC"}
@@ -1,22 +1,28 @@
1
1
  import { Stream } from '../../core/stream.js';
2
+ import { KeyCode } from './key-code.js';
2
3
  import { KeyboardSignal } from './keyboard-signal.js';
3
4
  export type ModifierKey = "meta" | "ctrl" | "alt" | "shift";
4
5
  export interface KeyboardOptions {
5
- /** Filter by key value(s). Case-insensitive. Uses OR logic if array. */
6
- key?: string | string[];
6
+ /**
7
+ * Filter by physical key code(s). Uses OR logic if array.
8
+ * @see https://www.w3.org/TR/uievents-code/
9
+ * @example 'KeyZ', 'Space', ['KeyA', 'KeyB']
10
+ */
11
+ code?: KeyCode | KeyCode[];
7
12
  /** Filter by modifier keys. Uses OR logic. */
8
13
  modifiers?: ModifierKey[];
9
- /** If true, calls preventDefault() on matching events. @default false */
14
+ /** If true, calls preventDefault() on matching events. @default true */
10
15
  preventDefault?: boolean;
11
16
  /** If true, allows repeated keydown events. @default false */
12
17
  allowRepeat?: boolean;
13
18
  }
14
19
  /**
15
- * Creates a keyboard signal stream. Shares underlying listeners per EventTarget.
20
+ * Creates a keyboard signal stream (keydown + keyup).
21
+ * Shares underlying listeners per EventTarget.
16
22
  *
17
23
  * @example
18
- * keyboard(window).on(signal => console.log(signal.value.key));
19
- * keyboard(window, { key: 'z', modifiers: ['meta'] }).on(handleUndo);
24
+ * keyboard(window).on(signal => console.log(signal.value.code));
25
+ * keyboard(window, { code: 'KeyZ', modifiers: ['meta'] }).on(handleUndo);
20
26
  */
21
27
  export declare function keyboard(target: EventTarget, options?: KeyboardOptions): Stream<KeyboardSignal>;
22
28
  //# sourceMappingURL=keyboard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/keyboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,cAAc,CAAC,CA2D/F"}
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/keyboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAC3B,8CAA8C;IAC9C,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,wEAAwE;IACxE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAAC,cAAc,CAAC,CAoD/F"}
@@ -0,0 +1,28 @@
1
+ import { Stream } from '../../core/stream.js';
2
+ import { KeyCode } from './key-code.js';
3
+ import { ModifierKey } from './keyboard.js';
4
+ import { KeyboardSignal } from './keyboard-signal.js';
5
+ export interface KeydownOptions {
6
+ /**
7
+ * Filter by physical key code(s). Uses OR logic if array.
8
+ * @see https://www.w3.org/TR/uievents-code/
9
+ * @example 'KeyZ', 'Space', ['KeyA', 'KeyB']
10
+ */
11
+ code?: KeyCode | KeyCode[];
12
+ /** Filter by modifier keys. Uses OR logic. */
13
+ modifiers?: ModifierKey[];
14
+ /** If true, calls preventDefault() on matching events. @default true */
15
+ preventDefault?: boolean;
16
+ /** If true, allows repeated keydown events. @default false */
17
+ allowRepeat?: boolean;
18
+ }
19
+ /**
20
+ * Creates a keydown-only signal stream.
21
+ * Shares underlying listeners per EventTarget.
22
+ *
23
+ * @example
24
+ * keydown(window).on(signal => console.log(signal.value.code));
25
+ * keydown(window, { code: 'KeyZ', modifiers: ['meta'] }).on(handleUndo);
26
+ */
27
+ export declare function keydown(target: EventTarget, options?: KeydownOptions): Stream<KeyboardSignal>;
28
+ //# sourceMappingURL=keydown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keydown.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/keydown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IAC3B,8CAA8C;IAC9C,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,wEAAwE;IACxE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC,CAoD7F"}
@@ -0,0 +1,34 @@
1
+ import { Signal } from '../../core/signal.js';
2
+ import { Stream } from '../../core/stream.js';
3
+ import { KeyCode } from './key-code.js';
4
+ interface KeyheldValue {
5
+ held: boolean;
6
+ }
7
+ export interface KeyheldSignal extends Signal<"keyheld", KeyheldValue> {
8
+ }
9
+ export declare const KEYHELD_SIGNAL_KIND: "keyheld";
10
+ export interface KeyheldOptions {
11
+ /**
12
+ * The physical key code to track.
13
+ * @see https://www.w3.org/TR/uievents-code/
14
+ * @example 'KeyZ', 'Space', 'Escape'
15
+ */
16
+ code: KeyCode;
17
+ }
18
+ /**
19
+ * Tracks whether a specific key is being held down.
20
+ * Emits only when state changes.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const spaceHeld$ = keyheld(window, { code: 'Space' });
25
+ * spaceHeld$.on(signal => {
26
+ * if (signal.value.held) {
27
+ * console.log('Space is held');
28
+ * }
29
+ * });
30
+ * ```
31
+ */
32
+ export declare function keyheld(target: EventTarget, options: KeyheldOptions): Stream<KeyheldSignal>;
33
+ export {};
34
+ //# sourceMappingURL=keyheld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyheld.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/keyheld.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,UAAU,YAAY;IACpB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC;CAAG;AAEzE,eAAO,MAAM,mBAAmB,EAAG,SAAkB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAAC,aAAa,CAAC,CA6B3F"}
@@ -2,6 +2,6 @@ import { Stream } from '../../core/stream.js';
2
2
  import { KeyboardSignal } from './keyboard-signal.js';
3
3
  /** Shared keyboard stream for the given target. */
4
4
  export declare function getSharedKeyboard(target: EventTarget): Stream<KeyboardSignal>;
5
- /** Shared keyboard stream filtered by a specific key. Filters out repeated events. */
6
- export declare function getSharedKeyboardForKey(target: EventTarget, key: string): Stream<KeyboardSignal>;
5
+ /** Shared keydown stream for the given target. */
6
+ export declare function getSharedKeydown(target: EventTarget): Stream<KeyboardSignal>;
7
7
  //# sourceMappingURL=shared.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAiC,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAyB1F,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,CAO7E;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CA4BhG"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/browser/keyboard/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAiC,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAyB1F,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,CAO7E;AAgBD,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,CAO5E"}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("./stream-BvdJvQie.cjs"),m=require("./recognizer-DbiEtBOM.cjs"),I=require("./share-vzh9f3Jn.cjs"),X=require("./types-BGR5Mhw9.cjs"),F=require("./single-pointer/pointer.cjs"),q="dom-event";function L(e){return m.createSignal(q,e)}function $(e,r,o){return d.createStream(t=>{const n=c=>{t.next(L(c))};return e.addEventListener(r,n,o),()=>{e.removeEventListener(r,n,o)}})}const K=["mousedown","mousemove","mouseup"];function U(e,r){return d.createStream(o=>{const t=n=>{o.next(L(n))};for(let n=0;n<K.length;n++){const c=K[n];e.addEventListener(c,t,r)}return()=>{for(let n=0;n<K.length;n++){const c=K[n];e.removeEventListener(c,t,r)}}})}const S=["pointerdown","pointermove","pointerup","pointercancel"];function N(e,r){return d.createStream(o=>{const t=n=>{o.next(L(n))};for(let n=0;n<S.length;n++){const c=S[n];e.addEventListener(c,t,r)}return()=>{for(let n=0;n<S.length;n++){const c=S[n];e.removeEventListener(c,t,r)}}})}const E=["touchstart","touchmove","touchend","touchcancel"];function V(e,r){return d.createStream(o=>{const t=n=>{o.next(L(n))};for(let n=0;n<E.length;n++){const c=E[n];e.addEventListener(c,t,r)}return()=>{for(let n=0;n<E.length;n++){const c=E[n];e.removeEventListener(c,t,r)}}})}const M="keyboard";function T(e){return m.createSignal(M,e)}function P(e,r){return T({phase:r,key:e.key,code:e.code,repeat:e.repeat,altKey:e.altKey,ctrlKey:e.ctrlKey,metaKey:e.metaKey,shiftKey:e.shiftKey,originalEvent:e})}const x=new WeakMap,D=new WeakMap;function B(e){return d.createStream(r=>{const o=n=>{r.next(P(n,"down"))},t=n=>{r.next(P(n,"up"))};return e.addEventListener("keydown",o),e.addEventListener("keyup",t),()=>{e.removeEventListener("keydown",o),e.removeEventListener("keyup",t)}})}function w(e){let r=x.get(e);return r||(r=I.share()(B(e)),x.set(e,r)),r}function b(e,r){const o=r.toLowerCase();let t=D.get(e);t||(t=new Map,D.set(e,t));let n=t.get(o);if(!n){const c=w(e),s=d.createStream(i=>c.on({next(u){u.value.repeat||u.value.key.toLowerCase()===o&&i.next(u)},error:i.error?.bind(i),complete:i.complete?.bind(i)}));n=I.share()(s),t.set(o,n)}return n}function Z(e,r){if(!r)return w(e);const o=r.modifiers,t=r.preventDefault??!1,n=r.allowRepeat??!1,c=typeof r.key=="string",s=r.key&&Array.isArray(r.key)?r.key.map(a=>a.toLowerCase()):null,i=c?b(e,r.key):w(e);if(c&&!o&&!t&&!n)return i;const u=a=>s?s.includes(a.toLowerCase()):!0,f=a=>!o||o.length===0?!0:o.some(l=>{switch(l){case"meta":return a.metaKey;case"ctrl":return a.ctrlKey;case"alt":return a.altKey;case"shift":return a.shiftKey;default:return!1}});return d.createStream(a=>i.on({next(l){const{key:y,repeat:k}=l.value;!n&&k||u(y)&&f(l.value)&&(t&&l.value.originalEvent.preventDefault(),a.next(l))},error:a.error?.bind(a),complete:a.complete?.bind(a)}))}const A="keyboard-held";function j(e,r){const{key:o,modifiers:t}=r,n=o.toLowerCase(),s=t&&t.length>0?w(e):b(e,o),i=new Set;if(t)for(const a of t)a==="meta"&&i.add("meta"),a==="ctrl"&&i.add("control"),a==="alt"&&i.add("alt"),a==="shift"&&i.add("shift");const u=a=>i.has(a.toLowerCase()),f=a=>!t||t.length===0?!0:t.some(l=>{switch(l){case"meta":return a.metaKey;case"ctrl":return a.ctrlKey;case"alt":return a.altKey;case"shift":return a.shiftKey;default:return!1}});return d.createStream(a=>{let l=!1,y;const k=h=>{h!==y&&(y=h,a.next(m.createSignal(A,{opened:h})))};return s.on({next(h){try{const{key:p,phase:v,repeat:Y}=h.value;if(Y)return;const z=p.toLowerCase()===n,G=u(p);z?l=v==="down":(v==="down"||G&&v==="up")&&(l=!1);const O=f(h.value);k(l&&O)}catch(p){a.error?.(p)}},error:a.error?.bind(a),complete:a.complete?.bind(a)})})}const J="multi-pointer";function Q(e){return m.createSignal(J,e)}function ee(e,r={}){const o={maxPointers:r.maxPointers??2},t=new Map;let n="idle";function c(s,i){return s===0?n==="active"&&i>0?"ended":"idle":"active"}return{process(s){const i=e(s,t,o);if(i===null)return null;const u=i.endedPointerIds;for(const y of u)t.delete(y);const f=Array.from(t.values()),a=c(f.length,u.length);n=a==="ended"?"idle":a;const l={phase:a,pointers:f,count:f.length};return Q(l)},get isActive(){return t.size>0},get activeCount(){return t.size},reset(){t.clear(),n="idle"},dispose(){this.reset()}}}function te(e={}){function r(o,t,n){const c=o.value,s=`${c.pointerType}-${c.pointerId}`,i=[];switch(c.type){case"pointerdown":{if(t.size>=n.maxPointers)return null;t.set(s,g(c,"start"));break}case"pointermove":{if(!t.has(s))return null;t.set(s,g(c,"move"));break}case"pointerup":{if(!t.has(s))return null;t.set(s,g(c,"end")),i.push(s);break}case"pointercancel":{if(!t.has(s))return null;t.set(s,g(c,"cancel")),i.push(s);break}default:return null}return{pointers:t,endedPointerIds:i}}return ee(r,e)}function C(e={}){return r=>d.createStream(o=>{const t=te(e),n=r.on({next(c){const s=t.process(c);s&&o.next(s)},error(c){o.error?.(c)},complete(){o.complete?.()}});return()=>{n(),t.dispose()}})}function g(e,r){const o=r==="start"||r==="end"?X.toSinglePointerButton(e.button):"none";return{id:`${e.pointerType}-${e.pointerId}`,phase:r,x:e.clientX,y:e.clientY,pageX:e.pageX,pageY:e.pageY,pointerType:re(e.pointerType),button:o,pressure:e.pressure}}function re(e){switch(e){case"mouse":return"mouse";case"touch":return"touch";case"pen":return"pen";default:return"unknown"}}function ne(e,r={}){const o=N(e);return C(r)(o)}function oe(e,r={}){const o=N(e);return F.singlePointerRecognizer(r)(o)}const W="wheel";function H(e){return m.createSignal(W,e)}function ae(e){switch(e){case 0:return"pixel";case 1:return"line";case 2:return"page";default:return"pixel"}}function R(e){return H({deltaX:e.deltaX,deltaY:e.deltaY,deltaZ:e.deltaZ,deltaMode:ae(e.deltaMode),x:e.clientX,y:e.clientY,pageX:e.pageX,pageY:e.pageY,altKey:e.altKey,ctrlKey:e.ctrlKey,metaKey:e.metaKey,shiftKey:e.shiftKey,originalEvent:e})}const _=new WeakMap;function ce(e,r){let o=_.get(e);o||(o=new Map,_.set(e,o));let t=o.get(r);return t||(t=I.share()(ie(e,r)),o.set(r,t)),t}function ie(e,r){return d.createStream(o=>{const t=n=>{o.next(R(n))};return e.addEventListener("wheel",t,{passive:r}),()=>{e.removeEventListener("wheel",t)}})}function se(e,r){const o=r?.passive??!0,t=r?.modifiers,n=r?.preventDefault??!1,c=ce(e,o);if(!t?.length&&!n)return c;const s=i=>!t||t.length===0?!0:t.some(u=>{switch(u){case"meta":return i.metaKey;case"ctrl":return i.ctrlKey;case"alt":return i.altKey;case"shift":return i.shiftKey;default:return!1}});return d.createStream(i=>c.on({next(u){try{s(u.value)&&(n&&u.value.originalEvent.preventDefault(),i.next(u))}catch(f){i.error?.(f)}},error:i.error?.bind(i),complete:i.complete?.bind(i)}))}exports.createStream=d.createStream;exports.createSignal=m.createSignal;exports.setCerebDeviceId=m.setCerebDeviceId;exports.HELD_SIGNAL_KIND=A;exports.KEYBOARD_SIGNAL_KIND=M;exports.WHEEL_SIGNAL_KIND=W;exports.createKeyboardSignal=T;exports.createKeyboardSignalFromEvent=P;exports.createWheelSignal=H;exports.createWheelSignalFromEvent=R;exports.domEvent=$;exports.keyboard=Z;exports.keyboardHeld=j;exports.mouseEvents=U;exports.multiPointer=ne;exports.multiPointerFromPointer=C;exports.pointerEvents=N;exports.singlePointer=oe;exports.touchEvents=V;exports.wheel=se;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("./stream-BvdJvQie.cjs"),m=require("./recognizer-DbiEtBOM.cjs"),g=require("./share-vzh9f3Jn.cjs"),W=require("./types-BGR5Mhw9.cjs"),Y=require("./single-pointer/pointer.cjs"),b="dom-event";function K(e){return m.createSignal(b,e)}function M(e,t,o){return d.createStream(n=>{const r=c=>{n.next(K(c))};return e.addEventListener(t,r,o),()=>{e.removeEventListener(t,r,o)}})}const h=["mousedown","mousemove","mouseup"];function z(e,t){return d.createStream(o=>{const n=r=>{o.next(K(r))};for(let r=0;r<h.length;r++){const c=h[r];e.addEventListener(c,n,t)}return()=>{for(let r=0;r<h.length;r++){const c=h[r];e.removeEventListener(c,n,t)}}})}const y=["pointerdown","pointermove","pointerup","pointercancel"];function L(e,t){return d.createStream(o=>{const n=r=>{o.next(K(r))};for(let r=0;r<y.length;r++){const c=y[r];e.addEventListener(c,n,t)}return()=>{for(let r=0;r<y.length;r++){const c=y[r];e.removeEventListener(c,n,t)}}})}const p=["touchstart","touchmove","touchend","touchcancel"];function G(e,t){return d.createStream(o=>{const n=r=>{o.next(K(r))};for(let r=0;r<p.length;r++){const c=p[r];e.addEventListener(c,n,t)}return()=>{for(let r=0;r<p.length;r++){const c=p[r];e.removeEventListener(c,n,t)}}})}const N="keyboard";function x(e){return m.createSignal(N,e)}function E(e,t){return x({phase:t,key:e.key,code:e.code,repeat:e.repeat,altKey:e.altKey,ctrlKey:e.ctrlKey,metaKey:e.metaKey,shiftKey:e.shiftKey,originalEvent:e})}const v=new WeakMap,P=new WeakMap;function O(e){return d.createStream(t=>{const o=r=>{t.next(E(r,"down"))},n=r=>{t.next(E(r,"up"))};return e.addEventListener("keydown",o),e.addEventListener("keyup",n),()=>{e.removeEventListener("keydown",o),e.removeEventListener("keyup",n)}})}function w(e){let t=v.get(e);return t||(t=g.share()(O(e)),v.set(e,t)),t}function X(e){return d.createStream(t=>{const o=n=>{t.next(E(n,"down"))};return e.addEventListener("keydown",o),()=>{e.removeEventListener("keydown",o)}})}function D(e){let t=P.get(e);return t||(t=g.share()(X(e)),P.set(e,t)),t}function F(e,t){if(!t)return w(e);const o=t.modifiers,n=t.preventDefault??!0,r=t.allowRepeat??!1,c=t.code?Array.isArray(t.code)?t.code.map(a=>a.toLowerCase()):[t.code.toLowerCase()]:null,u=w(e),i=a=>c?c.includes(a.code.toLowerCase()):!0,l=a=>!o||o.length===0?!0:o.some(s=>{switch(s){case"meta":return a.metaKey;case"ctrl":return a.ctrlKey;case"alt":return a.altKey;case"shift":return a.shiftKey;default:return!1}});return d.createStream(a=>u.on({next(s){const{repeat:f}=s.value;!r&&f||i(s.value)&&l(s.value)&&(n&&s.value.originalEvent.preventDefault(),a.next(s))},error:a.error?.bind(a),complete:a.complete?.bind(a)}))}function H(e,t){if(!t)return D(e);const o=t.modifiers,n=t.preventDefault??!0,r=t.allowRepeat??!1,c=t.code?Array.isArray(t.code)?t.code.map(a=>a.toLowerCase()):[t.code.toLowerCase()]:null,u=D(e),i=a=>c?c.includes(a.code.toLowerCase()):!0,l=a=>!o||o.length===0?!0:o.some(s=>{switch(s){case"meta":return a.metaKey;case"ctrl":return a.ctrlKey;case"alt":return a.altKey;case"shift":return a.shiftKey;default:return!1}});return d.createStream(a=>u.on({next(s){const{repeat:f}=s.value;!r&&f||i(s.value)&&l(s.value)&&(n&&s.value.originalEvent.preventDefault(),a.next(s))},error:a.error?.bind(a),complete:a.complete?.bind(a)}))}const k="keyheld";function q(e,t){const{code:o}=t,n=o.toLowerCase(),r=w(e);return d.createStream(c=>{let u;const i=l=>{l!==u&&(u=l,c.next(m.createSignal(k,{held:l})))};return r.on({next(l){const{code:a,phase:s,repeat:f}=l.value;f||a.toLowerCase()===n&&i(s==="down")},error:c.error?.bind(c),complete:c.complete?.bind(c)})})}const U="multi-pointer";function V(e){return m.createSignal(U,e)}function $(e,t={}){const o={maxPointers:t.maxPointers??2},n=new Map;let r="idle";function c(u,i){return u===0?r==="active"&&i>0?"ended":"idle":"active"}return{process(u){const i=e(u,n,o);if(i===null)return null;const l=i.endedPointerIds;for(const R of l)n.delete(R);const a=Array.from(n.values()),s=c(a.length,l.length);r=s==="ended"?"idle":s;const f={phase:s,pointers:a,count:a.length};return V(f)},get isActive(){return n.size>0},get activeCount(){return n.size},reset(){n.clear(),r="idle"},dispose(){this.reset()}}}function B(e={}){function t(o,n,r){const c=o.value,u=`${c.pointerType}-${c.pointerId}`,i=[];switch(c.type){case"pointerdown":{if(n.size>=r.maxPointers)return null;n.set(u,S(c,"start"));break}case"pointermove":{if(!n.has(u))return null;n.set(u,S(c,"move"));break}case"pointerup":{if(!n.has(u))return null;n.set(u,S(c,"end")),i.push(u);break}case"pointercancel":{if(!n.has(u))return null;n.set(u,S(c,"cancel")),i.push(u);break}default:return null}return{pointers:n,endedPointerIds:i}}return $(t,e)}function _(e={}){return t=>d.createStream(o=>{const n=B(e),r=t.on({next(c){const u=n.process(c);u&&o.next(u)},error(c){o.error?.(c)},complete(){o.complete?.()}});return()=>{r(),n.dispose()}})}function S(e,t){const o=t==="start"||t==="end"?W.toSinglePointerButton(e.button):"none";return{id:`${e.pointerType}-${e.pointerId}`,phase:t,x:e.clientX,y:e.clientY,pageX:e.pageX,pageY:e.pageY,pointerType:Z(e.pointerType),button:o,pressure:e.pressure}}function Z(e){switch(e){case"mouse":return"mouse";case"touch":return"touch";case"pen":return"pen";default:return"unknown"}}function j(e,t={}){const o=L(e);return _(t)(o)}function J(e,t={}){const o=L(e);return Y.singlePointerRecognizer(t)(o)}const C="wheel";function A(e){return m.createSignal(C,e)}function Q(e){switch(e){case 0:return"pixel";case 1:return"line";case 2:return"page";default:return"pixel"}}function T(e){return A({deltaX:e.deltaX,deltaY:e.deltaY,deltaZ:e.deltaZ,deltaMode:Q(e.deltaMode),x:e.clientX,y:e.clientY,pageX:e.pageX,pageY:e.pageY,altKey:e.altKey,ctrlKey:e.ctrlKey,metaKey:e.metaKey,shiftKey:e.shiftKey,originalEvent:e})}const I=new WeakMap;function ee(e,t){let o=I.get(e);o||(o=new Map,I.set(e,o));let n=o.get(t);return n||(n=g.share()(te(e,t)),o.set(t,n)),n}function te(e,t){return d.createStream(o=>{const n=r=>{o.next(T(r))};return e.addEventListener("wheel",n,{passive:t}),()=>{e.removeEventListener("wheel",n)}})}function re(e,t){const o=t?.passive??!0,n=t?.modifiers,r=t?.preventDefault??!1,c=ee(e,o);if(!n?.length&&!r)return c;const u=i=>!n||n.length===0?!0:n.some(l=>{switch(l){case"meta":return i.metaKey;case"ctrl":return i.ctrlKey;case"alt":return i.altKey;case"shift":return i.shiftKey;default:return!1}});return d.createStream(i=>c.on({next(l){try{u(l.value)&&(r&&l.value.originalEvent.preventDefault(),i.next(l))}catch(a){i.error?.(a)}},error:i.error?.bind(i),complete:i.complete?.bind(i)}))}exports.createStream=d.createStream;exports.createSignal=m.createSignal;exports.setCerebDeviceId=m.setCerebDeviceId;exports.KEYBOARD_SIGNAL_KIND=N;exports.KEYHELD_SIGNAL_KIND=k;exports.WHEEL_SIGNAL_KIND=C;exports.createKeyboardSignal=x;exports.createKeyboardSignalFromEvent=E;exports.createWheelSignal=A;exports.createWheelSignalFromEvent=T;exports.domEvent=M;exports.keyboard=F;exports.keydown=H;exports.keyheld=q;exports.mouseEvents=z;exports.multiPointer=j;exports.multiPointerFromPointer=_;exports.pointerEvents=L;exports.singlePointer=J;exports.touchEvents=G;exports.wheel=re;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/browser/dom-event/dom-event-signal.ts","../src/browser/dom-event/dom-event.ts","../src/browser/dom-event/mouse-events.ts","../src/browser/dom-event/pointer-events.ts","../src/browser/dom-event/touch-events.ts","../src/browser/keyboard/keyboard-signal.ts","../src/browser/keyboard/shared.ts","../src/browser/keyboard/keyboard.ts","../src/browser/keyboard/keyboard-held.ts","../src/browser/multi-pointer/multi-pointer-signal.ts","../src/browser/multi-pointer/recognizer.ts","../src/browser/multi-pointer/recognizer-from-pointer.ts","../src/browser/multi-pointer/default-factory.ts","../src/browser/single-pointer/default-factory.ts","../src/browser/wheel/wheel-signal.ts","../src/browser/wheel/wheel.ts"],"sourcesContent":["import { createSignal, type Signal } from \"../../core/signal.js\";\n\nexport interface DomEventSignal<E extends Event> extends Signal<\"dom-event\", E> {}\n\nexport const DOM_EVENT_SIGNAL_KIND = \"dom-event\" as const;\n\nexport function createDomEventSignal<E extends Event>(event: E): DomEventSignal<E> {\n return createSignal(DOM_EVENT_SIGNAL_KIND, event);\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\ntype AnyEventMap = Record<string, Event>;\n\n/**\n * Strongly-typed event target for custom event maps.\n * Useful for non-DOM EventTargets that still have named events.\n */\nexport type TypedEventTarget<M extends AnyEventMap> = EventTarget & {\n addEventListener<K extends keyof M>(\n type: K,\n listener: (event: M[K]) => void,\n options?: AddEventListenerOptions,\n ): void;\n removeEventListener<K extends keyof M>(\n type: K,\n listener: (event: M[K]) => void,\n options?: AddEventListenerOptions,\n ): void;\n};\n\nexport function domEvent<K extends keyof WindowEventMap>(\n target: Window,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<WindowEventMap[K]>>;\nexport function domEvent<K extends keyof DocumentEventMap>(\n target: Document,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<DocumentEventMap[K]>>;\nexport function domEvent<K extends keyof HTMLElementEventMap>(\n target: HTMLElement,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<HTMLElementEventMap[K]>>;\nexport function domEvent<K extends keyof SVGElementEventMap>(\n target: SVGElement,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<SVGElementEventMap[K]>>;\nexport function domEvent<M extends AnyEventMap, K extends keyof M>(\n target: TypedEventTarget<M>,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<M[K]>>;\nexport function domEvent<E extends Event = Event>(\n target: EventTarget,\n eventName: string,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<E>>;\nexport function domEvent<E extends Event = Event>(\n target: EventTarget,\n eventName: string,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<E>> {\n return createStream<DomEventSignal<E>>((observer) => {\n // NOTE: EventTarget's base signature expects an EventListener (Event),\n // so we accept Event and cast to the inferred event type for the signal.\n const handler: EventListener = (event) => {\n observer.next(createDomEventSignal(event as E));\n };\n\n target.addEventListener(eventName, handler, options);\n\n return () => {\n target.removeEventListener(eventName, handler, options);\n };\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\nconst MOUSE_EVENTS = [\"mousedown\", \"mousemove\", \"mouseup\"] as const;\n\nexport function mouseEvents(\n target: EventTarget,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<MouseEvent>> {\n return createStream<DomEventSignal<MouseEvent>>((observer) => {\n const handler = (event: Event) => {\n observer.next(createDomEventSignal(event as MouseEvent));\n };\n\n for (let i = 0; i < MOUSE_EVENTS.length; i++) {\n const eventName = MOUSE_EVENTS[i];\n target.addEventListener(eventName, handler, options);\n }\n\n return () => {\n for (let i = 0; i < MOUSE_EVENTS.length; i++) {\n const eventName = MOUSE_EVENTS[i];\n target.removeEventListener(eventName, handler, options);\n }\n };\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\nconst POINTER_EVENTS = [\"pointerdown\", \"pointermove\", \"pointerup\", \"pointercancel\"] as const;\n\nexport function pointerEvents(\n target: EventTarget,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<PointerEvent>> {\n return createStream<DomEventSignal<PointerEvent>>((observer) => {\n const handler = (event: Event) => {\n observer.next(createDomEventSignal(event as PointerEvent));\n };\n\n for (let i = 0; i < POINTER_EVENTS.length; i++) {\n const eventName = POINTER_EVENTS[i];\n target.addEventListener(eventName, handler, options);\n }\n\n return () => {\n for (let i = 0; i < POINTER_EVENTS.length; i++) {\n const eventName = POINTER_EVENTS[i];\n target.removeEventListener(eventName, handler, options);\n }\n };\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\nconst TOUCH_EVENTS = [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"] as const;\n\nexport function touchEvents(\n target: EventTarget,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<TouchEvent>> {\n return createStream((observer) => {\n const handler = (event: Event) => {\n observer.next(createDomEventSignal(event as TouchEvent));\n };\n\n for (let i = 0; i < TOUCH_EVENTS.length; i++) {\n const eventName = TOUCH_EVENTS[i];\n target.addEventListener(eventName, handler, options);\n }\n\n return () => {\n for (let i = 0; i < TOUCH_EVENTS.length; i++) {\n const eventName = TOUCH_EVENTS[i];\n target.removeEventListener(eventName, handler, options);\n }\n };\n });\n}\n","import { createSignal, type Signal } from \"../../core/signal.js\";\n\nexport type KeyboardPhase = \"down\" | \"up\";\n\n/**\n * Keyboard event data normalized into a consistent structure.\n * Provides both logical key (what the key represents) and physical code (where the key is).\n */\nexport interface KeyboardValue {\n phase: KeyboardPhase;\n /** Logical key value (e.g., \"+\", \"-\", \"a\", \"Meta\", \"Control\") */\n key: string;\n /** Physical key code (e.g., \"Equal\", \"Minus\", \"KeyA\", \"MetaLeft\") */\n code: string;\n /** True if this is a repeat event from holding the key down */\n repeat: boolean;\n altKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n /** Original DOM KeyboardEvent for advanced use cases like preventDefault */\n originalEvent: KeyboardEvent;\n}\n\nexport interface KeyboardSignal extends Signal<\"keyboard\", KeyboardValue> {}\n\nexport const KEYBOARD_SIGNAL_KIND = \"keyboard\" as const;\n\nexport function createKeyboardSignal(value: KeyboardValue): KeyboardSignal {\n return createSignal(KEYBOARD_SIGNAL_KIND, value);\n}\n\nexport function createKeyboardSignalFromEvent(\n event: KeyboardEvent,\n phase: KeyboardPhase,\n): KeyboardSignal {\n return createKeyboardSignal({\n phase,\n key: event.key,\n code: event.code,\n repeat: event.repeat,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n originalEvent: event,\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { share } from \"../../operators/share.js\";\nimport { createKeyboardSignalFromEvent, type KeyboardSignal } from \"./keyboard-signal.js\";\n\nconst sharedKeyboardStreams = new WeakMap<EventTarget, Stream<KeyboardSignal>>();\nconst sharedKeyStreams = new WeakMap<EventTarget, Map<string, Stream<KeyboardSignal>>>();\n\nfunction createRawKeyboardStream(target: EventTarget): Stream<KeyboardSignal> {\n return createStream<KeyboardSignal>((observer) => {\n const handleKeyDown = (e: Event) => {\n observer.next(createKeyboardSignalFromEvent(e as KeyboardEvent, \"down\"));\n };\n\n const handleKeyUp = (e: Event) => {\n observer.next(createKeyboardSignalFromEvent(e as KeyboardEvent, \"up\"));\n };\n\n target.addEventListener(\"keydown\", handleKeyDown);\n target.addEventListener(\"keyup\", handleKeyUp);\n\n return () => {\n target.removeEventListener(\"keydown\", handleKeyDown);\n target.removeEventListener(\"keyup\", handleKeyUp);\n };\n });\n}\n\n/** Shared keyboard stream for the given target. */\nexport function getSharedKeyboard(target: EventTarget): Stream<KeyboardSignal> {\n let stream = sharedKeyboardStreams.get(target);\n if (!stream) {\n stream = share<KeyboardSignal>()(createRawKeyboardStream(target));\n sharedKeyboardStreams.set(target, stream);\n }\n return stream;\n}\n\n/** Shared keyboard stream filtered by a specific key. Filters out repeated events. */\nexport function getSharedKeyboardForKey(target: EventTarget, key: string): Stream<KeyboardSignal> {\n const keyLower = key.toLowerCase();\n\n let keyMap = sharedKeyStreams.get(target);\n if (!keyMap) {\n keyMap = new Map();\n sharedKeyStreams.set(target, keyMap);\n }\n\n let stream = keyMap.get(keyLower);\n if (!stream) {\n const baseStream = getSharedKeyboard(target);\n const filteredStream = createStream<KeyboardSignal>((observer) => {\n return baseStream.on({\n next(signal) {\n if (signal.value.repeat) return;\n if (signal.value.key.toLowerCase() !== keyLower) return;\n observer.next(signal);\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n stream = share<KeyboardSignal>()(filteredStream);\n keyMap.set(keyLower, stream);\n }\n\n return stream;\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport type { KeyboardSignal } from \"./keyboard-signal.js\";\nimport { getSharedKeyboard, getSharedKeyboardForKey } from \"./shared.js\";\n\nexport type ModifierKey = \"meta\" | \"ctrl\" | \"alt\" | \"shift\";\n\nexport interface KeyboardOptions {\n /** Filter by key value(s). Case-insensitive. Uses OR logic if array. */\n key?: string | string[];\n /** Filter by modifier keys. Uses OR logic. */\n modifiers?: ModifierKey[];\n /** If true, calls preventDefault() on matching events. @default false */\n preventDefault?: boolean;\n /** If true, allows repeated keydown events. @default false */\n allowRepeat?: boolean;\n}\n\n/**\n * Creates a keyboard signal stream. Shares underlying listeners per EventTarget.\n *\n * @example\n * keyboard(window).on(signal => console.log(signal.value.key));\n * keyboard(window, { key: 'z', modifiers: ['meta'] }).on(handleUndo);\n */\nexport function keyboard(target: EventTarget, options?: KeyboardOptions): Stream<KeyboardSignal> {\n if (!options) return getSharedKeyboard(target);\n\n const modifiers = options.modifiers;\n const preventDefault = options.preventDefault ?? false;\n const allowRepeat = options.allowRepeat ?? false;\n\n const isSingleKey = typeof options.key === \"string\";\n const keyList = options.key\n ? Array.isArray(options.key)\n ? options.key.map((k) => k.toLowerCase())\n : null\n : null;\n\n const baseStream = isSingleKey\n ? getSharedKeyboardForKey(target, options.key as string)\n : getSharedKeyboard(target);\n\n if (isSingleKey && !modifiers && !preventDefault && !allowRepeat) {\n return baseStream;\n }\n\n const matchesKey = (key: string): boolean => {\n if (!keyList) return true;\n return keyList.includes(key.toLowerCase());\n };\n\n const matchesModifiers = (value: KeyboardSignal[\"value\"]): boolean => {\n if (!modifiers || modifiers.length === 0) return true;\n return modifiers.some((mod) => {\n switch (mod) {\n case \"meta\":\n return value.metaKey;\n case \"ctrl\":\n return value.ctrlKey;\n case \"alt\":\n return value.altKey;\n case \"shift\":\n return value.shiftKey;\n default:\n return false;\n }\n });\n };\n\n return createStream<KeyboardSignal>((observer) => {\n return baseStream.on({\n next(signal) {\n const { key, repeat } = signal.value;\n if (!allowRepeat && repeat) return;\n if (!matchesKey(key)) return;\n if (!matchesModifiers(signal.value)) return;\n if (preventDefault) signal.value.originalEvent.preventDefault();\n observer.next(signal);\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n}\n","import type { Signal } from \"../../core/signal.js\";\nimport { createSignal } from \"../../core/signal.js\";\nimport type { Stream } from \"../../core/stream.js\";\nimport { createStream } from \"../../core/stream.js\";\nimport type { ModifierKey } from \"./keyboard.js\";\nimport type { KeyboardSignal } from \"./keyboard-signal.js\";\nimport { getSharedKeyboard, getSharedKeyboardForKey } from \"./shared.js\";\n\ninterface HeldValue {\n opened: boolean;\n}\n\nexport interface HeldSignal extends Signal<\"keyboard-held\", HeldValue> {}\n\nexport const HELD_SIGNAL_KIND = \"keyboard-held\" as const;\n\nexport interface KeyboardHeldOptions {\n /**\n * The key to track. Case-insensitive.\n * @example 'z', 'Space', 'Escape'\n */\n key: string;\n\n /**\n * Modifier keys that must also be held. Uses OR logic.\n *\n * ⚠️ WARNING: On macOS, OS-level modifiers (especially Meta/Command) can swallow\n * keyup events. This is a known platform limitation, not a bug. For reliable\n * \"hold to activate\" behavior, prefer using non-modifier keys (Space, Shift, etc.)\n * as the primary key instead of relying on modifier combinations.\n *\n * @example ['meta', 'ctrl'] - matches if metaKey OR ctrlKey is pressed\n */\n modifiers?: ModifierKey[];\n}\n\n/**\n * Tracks whether a specific key (with optional modifiers) is being held down.\n * Emits only when state changes.\n *\n * @example\n * ```typescript\n * // Prefer: use non-modifier key for reliable hold detection\n * const spaceHeld$ = keyboardHeld(window, { key: 'Space' });\n *\n * // Caution: modifier combos may miss keyup on macOS\n * const cmdZHeld$ = keyboardHeld(window, { key: 'z', modifiers: ['meta'] });\n * ```\n */\nexport function keyboardHeld(\n target: EventTarget,\n options: KeyboardHeldOptions,\n): Stream<HeldSignal> {\n const { key, modifiers } = options;\n const keyLower = key.toLowerCase();\n const hasModifiers = modifiers && modifiers.length > 0;\n\n // With modifiers, use base stream to receive modifier keyup events\n const source = hasModifiers ? getSharedKeyboard(target) : getSharedKeyboardForKey(target, key);\n\n const modifierKeyNames = new Set<string>();\n if (modifiers) {\n for (const mod of modifiers) {\n if (mod === \"meta\") modifierKeyNames.add(\"meta\");\n if (mod === \"ctrl\") modifierKeyNames.add(\"control\");\n if (mod === \"alt\") modifierKeyNames.add(\"alt\");\n if (mod === \"shift\") modifierKeyNames.add(\"shift\");\n }\n }\n\n const isModifierKey = (eventKey: string): boolean => {\n return modifierKeyNames.has(eventKey.toLowerCase());\n };\n\n const checkModifiers = (value: KeyboardSignal[\"value\"]): boolean => {\n if (!modifiers || modifiers.length === 0) return true;\n return modifiers.some((mod) => {\n switch (mod) {\n case \"meta\":\n return value.metaKey;\n case \"ctrl\":\n return value.ctrlKey;\n case \"alt\":\n return value.altKey;\n case \"shift\":\n return value.shiftKey;\n default:\n return false;\n }\n });\n };\n\n return createStream((observer) => {\n let keyHeld = false;\n let lastEmittedHeld: boolean | undefined;\n\n const emitIfChanged = (held: boolean) => {\n if (held !== lastEmittedHeld) {\n lastEmittedHeld = held;\n observer.next(createSignal(HELD_SIGNAL_KIND, { opened: held }));\n }\n };\n\n return source.on({\n next(signal) {\n try {\n const { key: eventKey, phase, repeat } = signal.value;\n if (repeat) return;\n\n const eventKeyLower = eventKey.toLowerCase();\n const isTargetKey = eventKeyLower === keyLower;\n const isModifier = isModifierKey(eventKey);\n\n if (isTargetKey) {\n keyHeld = phase === \"down\";\n } else if (phase === \"down\" || (isModifier && phase === \"up\")) {\n // Reset on any other keydown or modifier keyup (handles missing keyup on macOS)\n keyHeld = false;\n }\n\n const modifierHeld = checkModifiers(signal.value);\n const held = keyHeld && modifierHeld;\n emitIfChanged(held);\n } catch (err) {\n observer.error?.(err);\n }\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n}\n","import { createSignal, type Signal } from \"../../core/signal.js\";\nimport type {\n SinglePointerButton,\n SinglePointerPhase,\n SinglePointerType,\n} from \"../single-pointer/types.js\";\n\nexport interface MultiPointerSignal extends Signal<\"multi-pointer\", MultiPointer> {}\n\nexport const MULTI_POINTER_SIGNAL_KIND = \"multi-pointer\" as const;\n\n/**\n * Represents the complete state of all active pointers at a given moment.\n * Emitted as a snapshot whenever any pointer changes state.\n */\nexport interface MultiPointer {\n /** Session-level phase: tracks the overall multi-pointer interaction lifecycle */\n phase: MultiPointerPhase;\n /** Array of currently active pointers */\n pointers: readonly PointerInfo[];\n /** Total number of active pointers */\n count: number;\n}\n\n/**\n * Session-level phase for multi-pointer interactions:\n * - \"idle\": No active pointers\n * - \"active\": One or more pointers are active\n * - \"ended\": All pointers have ended (transition state)\n */\nexport type MultiPointerPhase = \"idle\" | \"active\" | \"ended\";\n\n/**\n * Information about a single pointer within a multi-pointer context.\n */\nexport interface PointerInfo {\n id: string;\n phase: SinglePointerPhase;\n x: number;\n y: number;\n pageX: number;\n pageY: number;\n pointerType: SinglePointerType;\n button: SinglePointerButton;\n /** 0.0 ~ 1.0, default 0.5 if unsupported */\n pressure: number;\n}\n\nexport function createMultiPointerSignal(multiPointer: MultiPointer): MultiPointerSignal {\n return createSignal(MULTI_POINTER_SIGNAL_KIND, multiPointer);\n}\n\nexport function createDefaultPointerInfo(): PointerInfo {\n return {\n id: \"\",\n phase: \"move\",\n x: 0,\n y: 0,\n pageX: 0,\n pageY: 0,\n pointerType: \"unknown\",\n button: \"none\",\n pressure: 0.5,\n };\n}\n","import type { Signal } from \"../../core/signal.js\";\nimport {\n createMultiPointerSignal,\n type MultiPointer,\n type MultiPointerPhase,\n type MultiPointerSignal,\n type PointerInfo,\n} from \"./multi-pointer-signal.js\";\nimport type { MultiPointerOptions } from \"./types.js\";\n\nexport interface MultiPointerRecognizer<InputSignal extends Signal> {\n process(event: InputSignal): MultiPointerSignal | null;\n readonly isActive: boolean;\n readonly activeCount: number;\n reset(): void;\n dispose(): void;\n}\n\n/**\n * Result of processing an input event.\n * - null: No signal should be emitted (e.g., pointer ignored due to maxPointers)\n * - pointers: Updated pointer map after processing the event\n */\nexport interface PointerUpdateResult {\n pointers: Map<string, PointerInfo>;\n endedPointerIds: string[];\n}\n\n/**\n * Creates a recognizer that tracks multiple pointers and emits snapshot signals.\n * Maintains internal state of all active pointers using a Map.\n */\nexport function createMultiPointerRecognizer<InputSignal extends Signal>(\n processor: (\n inputSignal: InputSignal,\n pointerMap: Map<string, PointerInfo>,\n options: Required<MultiPointerOptions>,\n ) => PointerUpdateResult | null,\n options: MultiPointerOptions = {},\n): MultiPointerRecognizer<InputSignal> {\n const opts: Required<MultiPointerOptions> = {\n maxPointers: options.maxPointers ?? 2,\n };\n\n const activePointers = new Map<string, PointerInfo>();\n let previousPhase: MultiPointerPhase = \"idle\";\n\n function computePhase(count: number, endedCount: number): MultiPointerPhase {\n if (count === 0) {\n return previousPhase === \"active\" && endedCount > 0 ? \"ended\" : \"idle\";\n }\n return \"active\";\n }\n\n return {\n process(inputSignal: InputSignal): MultiPointerSignal | null {\n const result = processor(inputSignal, activePointers, opts);\n if (result === null) {\n return null;\n }\n\n const endedPointerIds = result.endedPointerIds;\n for (const id of endedPointerIds) {\n activePointers.delete(id);\n }\n\n const pointers = Array.from(activePointers.values());\n const phase = computePhase(pointers.length, endedPointerIds.length);\n previousPhase = phase === \"ended\" ? \"idle\" : phase;\n\n const multiPointer: MultiPointer = {\n phase,\n pointers,\n count: pointers.length,\n };\n\n return createMultiPointerSignal(multiPointer);\n },\n\n get isActive(): boolean {\n return activePointers.size > 0;\n },\n\n get activeCount(): number {\n return activePointers.size;\n },\n\n reset(): void {\n activePointers.clear();\n previousPhase = \"idle\";\n },\n\n dispose(): void {\n this.reset();\n },\n };\n}\n","import type { Operator } from \"../../core/stream.js\";\nimport { createStream } from \"../../core/stream.js\";\nimport type { DomEventSignal } from \"../dom-event/dom-event-signal.js\";\nimport type {\n SinglePointerButton,\n SinglePointerPhase,\n SinglePointerType,\n} from \"../single-pointer/types.js\";\nimport { toSinglePointerButton } from \"../single-pointer/types.js\";\nimport type { MultiPointerSignal, PointerInfo } from \"./multi-pointer-signal.js\";\nimport {\n createMultiPointerRecognizer,\n type MultiPointerRecognizer,\n type PointerUpdateResult,\n} from \"./recognizer.js\";\nimport type { MultiPointerOptions } from \"./types.js\";\n\nexport function createPointerRecognizer(\n options: MultiPointerOptions = {},\n): MultiPointerRecognizer<DomEventSignal<PointerEvent>> {\n function processor(\n domEventSignal: DomEventSignal<PointerEvent>,\n pointerMap: Map<string, PointerInfo>,\n opts: Required<MultiPointerOptions>,\n ): PointerUpdateResult | null {\n const e = domEventSignal.value;\n const id = `${e.pointerType}-${e.pointerId}`;\n const endedPointerIds: string[] = [];\n\n switch (e.type) {\n case \"pointerdown\": {\n if (pointerMap.size >= opts.maxPointers) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"start\"));\n break;\n }\n\n case \"pointermove\": {\n if (!pointerMap.has(id)) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"move\"));\n break;\n }\n\n case \"pointerup\": {\n if (!pointerMap.has(id)) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"end\"));\n endedPointerIds.push(id);\n break;\n }\n\n case \"pointercancel\": {\n if (!pointerMap.has(id)) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"cancel\"));\n endedPointerIds.push(id);\n break;\n }\n\n default:\n return null;\n }\n\n return { pointers: pointerMap, endedPointerIds };\n }\n\n return createMultiPointerRecognizer(processor, options);\n}\n\nexport function multiPointerFromPointer(\n options: MultiPointerOptions = {},\n): Operator<DomEventSignal<PointerEvent>, MultiPointerSignal> {\n return (source) =>\n createStream((observer) => {\n const recognizer = createPointerRecognizer(options);\n\n const unsub = source.on({\n next(event) {\n const signal = recognizer.process(event);\n if (signal) {\n observer.next(signal);\n }\n },\n error(err) {\n observer.error?.(err);\n },\n complete() {\n observer.complete?.();\n },\n });\n\n return () => {\n unsub();\n recognizer.dispose();\n };\n });\n}\n\nfunction createPointerInfo(e: PointerEvent, phase: SinglePointerPhase): PointerInfo {\n const button: SinglePointerButton =\n phase === \"start\" || phase === \"end\" ? toSinglePointerButton(e.button) : \"none\";\n\n return {\n id: `${e.pointerType}-${e.pointerId}`,\n phase,\n x: e.clientX,\n y: e.clientY,\n pageX: e.pageX,\n pageY: e.pageY,\n pointerType: normalizePointerType(e.pointerType),\n button,\n pressure: e.pressure,\n };\n}\n\nfunction normalizePointerType(type: string): SinglePointerType {\n switch (type) {\n case \"mouse\":\n return \"mouse\";\n case \"touch\":\n return \"touch\";\n case \"pen\":\n return \"pen\";\n default:\n return \"unknown\";\n }\n}\n","import type { Stream } from \"../../core/stream.js\";\nimport { pointerEvents } from \"../dom-event/pointer-events.js\";\nimport type { MultiPointerSignal } from \"./multi-pointer-signal.js\";\nimport { multiPointerFromPointer } from \"./recognizer-from-pointer.js\";\nimport type { MultiPointerOptions } from \"./types.js\";\n\nexport function multiPointer(\n target: EventTarget,\n options: MultiPointerOptions = {},\n): Stream<MultiPointerSignal> {\n const source = pointerEvents(target);\n return multiPointerFromPointer(options)(source);\n}\n","import type { Stream } from \"../../core/stream.js\";\nimport { pointerEvents } from \"../dom-event/pointer-events.js\";\nimport { singlePointerFromPointer } from \"./recognizer-from-pointer.js\";\nimport type { SinglePointerSignal } from \"./single-pointer-signal.js\";\nimport type { SinglePointerOptions } from \"./types.js\";\n\nexport function singlePointer(\n target: EventTarget,\n options: SinglePointerOptions = {},\n): Stream<SinglePointerSignal> {\n const source = pointerEvents(target);\n return singlePointerFromPointer(options)(source);\n}\n","import { createSignal, type Signal } from \"../../core/signal.js\";\n\nexport type WheelDeltaMode = \"pixel\" | \"line\" | \"page\";\n\n/**\n * Wheel event data normalized into a consistent structure.\n * Provides scroll deltas and position information.\n */\nexport interface WheelValue {\n /** Horizontal scroll delta */\n deltaX: number;\n /** Vertical scroll delta (positive = scroll down/zoom out) */\n deltaY: number;\n /** Z-axis scroll delta (rare, used by some 3D mice) */\n deltaZ: number;\n /** Unit of the delta values */\n deltaMode: WheelDeltaMode;\n /** Client X coordinate (viewport-relative) */\n x: number;\n /** Client Y coordinate (viewport-relative) */\n y: number;\n /** Page X coordinate (document-relative) */\n pageX: number;\n /** Page Y coordinate (document-relative) */\n pageY: number;\n altKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n /** Original DOM WheelEvent for advanced use cases like preventDefault */\n originalEvent: WheelEvent;\n}\n\nexport interface WheelSignal extends Signal<\"wheel\", WheelValue> {}\n\nexport const WHEEL_SIGNAL_KIND = \"wheel\" as const;\n\nexport function createWheelSignal(value: WheelValue): WheelSignal {\n return createSignal(WHEEL_SIGNAL_KIND, value);\n}\n\nfunction toDeltaMode(mode: number): WheelDeltaMode {\n switch (mode) {\n case 0:\n return \"pixel\";\n case 1:\n return \"line\";\n case 2:\n return \"page\";\n default:\n return \"pixel\";\n }\n}\n\nexport function createWheelSignalFromEvent(event: WheelEvent): WheelSignal {\n return createWheelSignal({\n deltaX: event.deltaX,\n deltaY: event.deltaY,\n deltaZ: event.deltaZ,\n deltaMode: toDeltaMode(event.deltaMode),\n x: event.clientX,\n y: event.clientY,\n pageX: event.pageX,\n pageY: event.pageY,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n originalEvent: event,\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { share } from \"../../operators/share.js\";\nimport type { ModifierKey } from \"../keyboard/keyboard.js\";\nimport { createWheelSignalFromEvent, type WheelSignal } from \"./wheel-signal.js\";\n\nexport interface WheelOptions {\n /**\n * Whether to use passive event listener.\n * Set to false if you need to call preventDefault() on the originalEvent.\n * @default true\n */\n passive?: boolean;\n\n /**\n * Filter by modifier keys. Uses OR logic (matches if any is pressed).\n * @example ['meta', 'ctrl'] - matches if metaKey OR ctrlKey is pressed\n */\n modifiers?: ModifierKey[];\n\n /**\n * If true, calls preventDefault() on matching events.\n * Requires passive: false to work.\n * @default false\n */\n preventDefault?: boolean;\n}\n\n/**\n * Cache for shared wheel streams per EventTarget and passive option.\n * Using WeakMap ensures streams are garbage collected when targets are removed.\n */\nconst sharedWheelStreams = new WeakMap<EventTarget, Map<boolean, Stream<WheelSignal>>>();\n\nfunction getSharedWheel(target: EventTarget, passive: boolean): Stream<WheelSignal> {\n let passiveMap = sharedWheelStreams.get(target);\n if (!passiveMap) {\n passiveMap = new Map();\n sharedWheelStreams.set(target, passiveMap);\n }\n\n let stream = passiveMap.get(passive);\n if (!stream) {\n stream = share<WheelSignal>()(createWheelStream(target, passive));\n passiveMap.set(passive, stream);\n }\n return stream;\n}\n\nfunction createWheelStream(target: EventTarget, passive: boolean): Stream<WheelSignal> {\n return createStream<WheelSignal>((observer) => {\n const handler = (e: Event) => {\n observer.next(createWheelSignalFromEvent(e as WheelEvent));\n };\n\n target.addEventListener(\"wheel\", handler, { passive });\n\n return () => {\n target.removeEventListener(\"wheel\", handler);\n };\n });\n}\n\n/**\n * Creates a stream of wheel signals from wheel events on the target.\n * Automatically shares the wheel stream for the same EventTarget and passive option.\n *\n * @example\n * ```typescript\n * // Basic usage (passive by default for performance)\n * wheel(element).on(signal => {\n * console.log(signal.value.deltaY);\n * });\n *\n * // With modifier filter and preventDefault\n * wheel(element, {\n * passive: false,\n * modifiers: ['meta', 'ctrl'],\n * preventDefault: true\n * }).on(signal => {\n * // Only fires when Ctrl or Cmd is held\n * });\n * ```\n */\nexport function wheel(target: EventTarget, options?: WheelOptions): Stream<WheelSignal> {\n const passive = options?.passive ?? true;\n const modifiers = options?.modifiers;\n const preventDefault = options?.preventDefault ?? false;\n\n const source = getSharedWheel(target, passive);\n\n // If no filtering needed, return shared stream directly\n if (!modifiers?.length && !preventDefault) {\n return source;\n }\n\n const matchesModifiers = (value: WheelSignal[\"value\"]): boolean => {\n if (!modifiers || modifiers.length === 0) return true;\n return modifiers.some((mod) => {\n switch (mod) {\n case \"meta\":\n return value.metaKey;\n case \"ctrl\":\n return value.ctrlKey;\n case \"alt\":\n return value.altKey;\n case \"shift\":\n return value.shiftKey;\n default:\n return false;\n }\n });\n };\n\n return createStream<WheelSignal>((observer) => {\n return source.on({\n next(signal) {\n try {\n if (matchesModifiers(signal.value)) {\n if (preventDefault) {\n signal.value.originalEvent.preventDefault();\n }\n observer.next(signal);\n }\n } catch (err) {\n observer.error?.(err);\n }\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n}\n"],"names":["DOM_EVENT_SIGNAL_KIND","createDomEventSignal","event","createSignal","domEvent","target","eventName","options","createStream","observer","handler","MOUSE_EVENTS","mouseEvents","i","POINTER_EVENTS","pointerEvents","TOUCH_EVENTS","touchEvents","KEYBOARD_SIGNAL_KIND","createKeyboardSignal","value","createKeyboardSignalFromEvent","phase","sharedKeyboardStreams","sharedKeyStreams","createRawKeyboardStream","handleKeyDown","e","handleKeyUp","getSharedKeyboard","stream","share","getSharedKeyboardForKey","key","keyLower","keyMap","baseStream","filteredStream","signal","keyboard","modifiers","preventDefault","allowRepeat","isSingleKey","keyList","k","matchesKey","matchesModifiers","mod","repeat","HELD_SIGNAL_KIND","keyboardHeld","source","modifierKeyNames","isModifierKey","eventKey","checkModifiers","keyHeld","lastEmittedHeld","emitIfChanged","held","isTargetKey","isModifier","modifierHeld","err","MULTI_POINTER_SIGNAL_KIND","createMultiPointerSignal","multiPointer","createMultiPointerRecognizer","processor","opts","activePointers","previousPhase","computePhase","count","endedCount","inputSignal","result","endedPointerIds","id","pointers","createPointerRecognizer","domEventSignal","pointerMap","createPointerInfo","multiPointerFromPointer","recognizer","unsub","button","toSinglePointerButton","normalizePointerType","type","singlePointer","singlePointerFromPointer","WHEEL_SIGNAL_KIND","createWheelSignal","toDeltaMode","mode","createWheelSignalFromEvent","sharedWheelStreams","getSharedWheel","passive","passiveMap","createWheelStream","wheel"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/browser/dom-event/dom-event-signal.ts","../src/browser/dom-event/dom-event.ts","../src/browser/dom-event/mouse-events.ts","../src/browser/dom-event/pointer-events.ts","../src/browser/dom-event/touch-events.ts","../src/browser/keyboard/keyboard-signal.ts","../src/browser/keyboard/shared.ts","../src/browser/keyboard/keyboard.ts","../src/browser/keyboard/keydown.ts","../src/browser/keyboard/keyheld.ts","../src/browser/multi-pointer/multi-pointer-signal.ts","../src/browser/multi-pointer/recognizer.ts","../src/browser/multi-pointer/recognizer-from-pointer.ts","../src/browser/multi-pointer/default-factory.ts","../src/browser/single-pointer/default-factory.ts","../src/browser/wheel/wheel-signal.ts","../src/browser/wheel/wheel.ts"],"sourcesContent":["import { createSignal, type Signal } from \"../../core/signal.js\";\n\nexport interface DomEventSignal<E extends Event> extends Signal<\"dom-event\", E> {}\n\nexport const DOM_EVENT_SIGNAL_KIND = \"dom-event\" as const;\n\nexport function createDomEventSignal<E extends Event>(event: E): DomEventSignal<E> {\n return createSignal(DOM_EVENT_SIGNAL_KIND, event);\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\ntype AnyEventMap = Record<string, Event>;\n\n/**\n * Strongly-typed event target for custom event maps.\n * Useful for non-DOM EventTargets that still have named events.\n */\nexport type TypedEventTarget<M extends AnyEventMap> = EventTarget & {\n addEventListener<K extends keyof M>(\n type: K,\n listener: (event: M[K]) => void,\n options?: AddEventListenerOptions,\n ): void;\n removeEventListener<K extends keyof M>(\n type: K,\n listener: (event: M[K]) => void,\n options?: AddEventListenerOptions,\n ): void;\n};\n\nexport function domEvent<K extends keyof WindowEventMap>(\n target: Window,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<WindowEventMap[K]>>;\nexport function domEvent<K extends keyof DocumentEventMap>(\n target: Document,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<DocumentEventMap[K]>>;\nexport function domEvent<K extends keyof HTMLElementEventMap>(\n target: HTMLElement,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<HTMLElementEventMap[K]>>;\nexport function domEvent<K extends keyof SVGElementEventMap>(\n target: SVGElement,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<SVGElementEventMap[K]>>;\nexport function domEvent<M extends AnyEventMap, K extends keyof M>(\n target: TypedEventTarget<M>,\n eventName: K,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<M[K]>>;\nexport function domEvent<E extends Event = Event>(\n target: EventTarget,\n eventName: string,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<E>>;\nexport function domEvent<E extends Event = Event>(\n target: EventTarget,\n eventName: string,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<E>> {\n return createStream<DomEventSignal<E>>((observer) => {\n // NOTE: EventTarget's base signature expects an EventListener (Event),\n // so we accept Event and cast to the inferred event type for the signal.\n const handler: EventListener = (event) => {\n observer.next(createDomEventSignal(event as E));\n };\n\n target.addEventListener(eventName, handler, options);\n\n return () => {\n target.removeEventListener(eventName, handler, options);\n };\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\nconst MOUSE_EVENTS = [\"mousedown\", \"mousemove\", \"mouseup\"] as const;\n\nexport function mouseEvents(\n target: EventTarget,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<MouseEvent>> {\n return createStream<DomEventSignal<MouseEvent>>((observer) => {\n const handler = (event: Event) => {\n observer.next(createDomEventSignal(event as MouseEvent));\n };\n\n for (let i = 0; i < MOUSE_EVENTS.length; i++) {\n const eventName = MOUSE_EVENTS[i];\n target.addEventListener(eventName, handler, options);\n }\n\n return () => {\n for (let i = 0; i < MOUSE_EVENTS.length; i++) {\n const eventName = MOUSE_EVENTS[i];\n target.removeEventListener(eventName, handler, options);\n }\n };\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\nconst POINTER_EVENTS = [\"pointerdown\", \"pointermove\", \"pointerup\", \"pointercancel\"] as const;\n\nexport function pointerEvents(\n target: EventTarget,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<PointerEvent>> {\n return createStream<DomEventSignal<PointerEvent>>((observer) => {\n const handler = (event: Event) => {\n observer.next(createDomEventSignal(event as PointerEvent));\n };\n\n for (let i = 0; i < POINTER_EVENTS.length; i++) {\n const eventName = POINTER_EVENTS[i];\n target.addEventListener(eventName, handler, options);\n }\n\n return () => {\n for (let i = 0; i < POINTER_EVENTS.length; i++) {\n const eventName = POINTER_EVENTS[i];\n target.removeEventListener(eventName, handler, options);\n }\n };\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { createDomEventSignal, type DomEventSignal } from \"./dom-event-signal.js\";\n\nconst TOUCH_EVENTS = [\"touchstart\", \"touchmove\", \"touchend\", \"touchcancel\"] as const;\n\nexport function touchEvents(\n target: EventTarget,\n options?: AddEventListenerOptions,\n): Stream<DomEventSignal<TouchEvent>> {\n return createStream((observer) => {\n const handler = (event: Event) => {\n observer.next(createDomEventSignal(event as TouchEvent));\n };\n\n for (let i = 0; i < TOUCH_EVENTS.length; i++) {\n const eventName = TOUCH_EVENTS[i];\n target.addEventListener(eventName, handler, options);\n }\n\n return () => {\n for (let i = 0; i < TOUCH_EVENTS.length; i++) {\n const eventName = TOUCH_EVENTS[i];\n target.removeEventListener(eventName, handler, options);\n }\n };\n });\n}\n","import { createSignal, type Signal } from \"../../core/signal.js\";\n\nexport type KeyboardPhase = \"down\" | \"up\";\n\n/**\n * Keyboard event data normalized into a consistent structure.\n * Provides both logical key (what the key represents) and physical code (where the key is).\n */\nexport interface KeyboardValue {\n phase: KeyboardPhase;\n /** Logical key value (e.g., \"+\", \"-\", \"a\", \"Meta\", \"Control\") */\n key: string;\n /** Physical key code (e.g., \"Equal\", \"Minus\", \"KeyA\", \"MetaLeft\") */\n code: string;\n /** True if this is a repeat event from holding the key down */\n repeat: boolean;\n altKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n /** Original DOM KeyboardEvent for advanced use cases like preventDefault */\n originalEvent: KeyboardEvent;\n}\n\nexport interface KeyboardSignal extends Signal<\"keyboard\", KeyboardValue> {}\n\nexport const KEYBOARD_SIGNAL_KIND = \"keyboard\" as const;\n\nexport function createKeyboardSignal(value: KeyboardValue): KeyboardSignal {\n return createSignal(KEYBOARD_SIGNAL_KIND, value);\n}\n\nexport function createKeyboardSignalFromEvent(\n event: KeyboardEvent,\n phase: KeyboardPhase,\n): KeyboardSignal {\n return createKeyboardSignal({\n phase,\n key: event.key,\n code: event.code,\n repeat: event.repeat,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n originalEvent: event,\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { share } from \"../../operators/share.js\";\nimport { createKeyboardSignalFromEvent, type KeyboardSignal } from \"./keyboard-signal.js\";\n\nconst sharedKeyboardStreams = new WeakMap<EventTarget, Stream<KeyboardSignal>>();\nconst sharedKeydownStreams = new WeakMap<EventTarget, Stream<KeyboardSignal>>();\n\nfunction createRawKeyboardStream(target: EventTarget): Stream<KeyboardSignal> {\n return createStream<KeyboardSignal>((observer) => {\n const handleKeyDown = (e: Event) => {\n observer.next(createKeyboardSignalFromEvent(e as KeyboardEvent, \"down\"));\n };\n\n const handleKeyUp = (e: Event) => {\n observer.next(createKeyboardSignalFromEvent(e as KeyboardEvent, \"up\"));\n };\n\n target.addEventListener(\"keydown\", handleKeyDown);\n target.addEventListener(\"keyup\", handleKeyUp);\n\n return () => {\n target.removeEventListener(\"keydown\", handleKeyDown);\n target.removeEventListener(\"keyup\", handleKeyUp);\n };\n });\n}\n\n/** Shared keyboard stream for the given target. */\nexport function getSharedKeyboard(target: EventTarget): Stream<KeyboardSignal> {\n let stream = sharedKeyboardStreams.get(target);\n if (!stream) {\n stream = share<KeyboardSignal>()(createRawKeyboardStream(target));\n sharedKeyboardStreams.set(target, stream);\n }\n return stream;\n}\n\nfunction createRawKeydownStream(target: EventTarget): Stream<KeyboardSignal> {\n return createStream<KeyboardSignal>((observer) => {\n const handleKeyDown = (e: Event) => {\n observer.next(createKeyboardSignalFromEvent(e as KeyboardEvent, \"down\"));\n };\n\n target.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n target.removeEventListener(\"keydown\", handleKeyDown);\n };\n });\n}\n\n/** Shared keydown stream for the given target. */\nexport function getSharedKeydown(target: EventTarget): Stream<KeyboardSignal> {\n let stream = sharedKeydownStreams.get(target);\n if (!stream) {\n stream = share<KeyboardSignal>()(createRawKeydownStream(target));\n sharedKeydownStreams.set(target, stream);\n }\n return stream;\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport type { KeyCode } from \"./key-code.js\";\nimport type { KeyboardSignal } from \"./keyboard-signal.js\";\nimport { getSharedKeyboard } from \"./shared.js\";\n\nexport type ModifierKey = \"meta\" | \"ctrl\" | \"alt\" | \"shift\";\n\nexport interface KeyboardOptions {\n /**\n * Filter by physical key code(s). Uses OR logic if array.\n * @see https://www.w3.org/TR/uievents-code/\n * @example 'KeyZ', 'Space', ['KeyA', 'KeyB']\n */\n code?: KeyCode | KeyCode[];\n /** Filter by modifier keys. Uses OR logic. */\n modifiers?: ModifierKey[];\n /** If true, calls preventDefault() on matching events. @default true */\n preventDefault?: boolean;\n /** If true, allows repeated keydown events. @default false */\n allowRepeat?: boolean;\n}\n\n/**\n * Creates a keyboard signal stream (keydown + keyup).\n * Shares underlying listeners per EventTarget.\n *\n * @example\n * keyboard(window).on(signal => console.log(signal.value.code));\n * keyboard(window, { code: 'KeyZ', modifiers: ['meta'] }).on(handleUndo);\n */\nexport function keyboard(target: EventTarget, options?: KeyboardOptions): Stream<KeyboardSignal> {\n if (!options) return getSharedKeyboard(target);\n\n const modifiers = options.modifiers;\n const preventDefault = options.preventDefault ?? true;\n const allowRepeat = options.allowRepeat ?? false;\n\n const codeList = options.code\n ? Array.isArray(options.code)\n ? options.code.map((c) => c.toLowerCase())\n : [options.code.toLowerCase()]\n : null;\n\n const baseStream = getSharedKeyboard(target);\n\n const matchesCode = (value: KeyboardSignal[\"value\"]): boolean => {\n if (!codeList) return true;\n return codeList.includes(value.code.toLowerCase());\n };\n\n const matchesModifiers = (value: KeyboardSignal[\"value\"]): boolean => {\n if (!modifiers || modifiers.length === 0) return true;\n return modifiers.some((mod) => {\n switch (mod) {\n case \"meta\":\n return value.metaKey;\n case \"ctrl\":\n return value.ctrlKey;\n case \"alt\":\n return value.altKey;\n case \"shift\":\n return value.shiftKey;\n default:\n return false;\n }\n });\n };\n\n return createStream<KeyboardSignal>((observer) => {\n return baseStream.on({\n next(signal) {\n const { repeat } = signal.value;\n if (!allowRepeat && repeat) return;\n if (!matchesCode(signal.value)) return;\n if (!matchesModifiers(signal.value)) return;\n if (preventDefault) signal.value.originalEvent.preventDefault();\n observer.next(signal);\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport type { KeyCode } from \"./key-code.js\";\nimport type { ModifierKey } from \"./keyboard.js\";\nimport type { KeyboardSignal } from \"./keyboard-signal.js\";\nimport { getSharedKeydown } from \"./shared.js\";\n\nexport interface KeydownOptions {\n /**\n * Filter by physical key code(s). Uses OR logic if array.\n * @see https://www.w3.org/TR/uievents-code/\n * @example 'KeyZ', 'Space', ['KeyA', 'KeyB']\n */\n code?: KeyCode | KeyCode[];\n /** Filter by modifier keys. Uses OR logic. */\n modifiers?: ModifierKey[];\n /** If true, calls preventDefault() on matching events. @default true */\n preventDefault?: boolean;\n /** If true, allows repeated keydown events. @default false */\n allowRepeat?: boolean;\n}\n\n/**\n * Creates a keydown-only signal stream.\n * Shares underlying listeners per EventTarget.\n *\n * @example\n * keydown(window).on(signal => console.log(signal.value.code));\n * keydown(window, { code: 'KeyZ', modifiers: ['meta'] }).on(handleUndo);\n */\nexport function keydown(target: EventTarget, options?: KeydownOptions): Stream<KeyboardSignal> {\n if (!options) return getSharedKeydown(target);\n\n const modifiers = options.modifiers;\n const preventDefault = options.preventDefault ?? true;\n const allowRepeat = options.allowRepeat ?? false;\n\n const codeList = options.code\n ? Array.isArray(options.code)\n ? options.code.map((c) => c.toLowerCase())\n : [options.code.toLowerCase()]\n : null;\n\n const baseStream = getSharedKeydown(target);\n\n const matchesCode = (value: KeyboardSignal[\"value\"]): boolean => {\n if (!codeList) return true;\n return codeList.includes(value.code.toLowerCase());\n };\n\n const matchesModifiers = (value: KeyboardSignal[\"value\"]): boolean => {\n if (!modifiers || modifiers.length === 0) return true;\n return modifiers.some((mod) => {\n switch (mod) {\n case \"meta\":\n return value.metaKey;\n case \"ctrl\":\n return value.ctrlKey;\n case \"alt\":\n return value.altKey;\n case \"shift\":\n return value.shiftKey;\n default:\n return false;\n }\n });\n };\n\n return createStream<KeyboardSignal>((observer) => {\n return baseStream.on({\n next(signal) {\n const { repeat } = signal.value;\n if (!allowRepeat && repeat) return;\n if (!matchesCode(signal.value)) return;\n if (!matchesModifiers(signal.value)) return;\n if (preventDefault) signal.value.originalEvent.preventDefault();\n observer.next(signal);\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n}\n","import type { Signal } from \"../../core/signal.js\";\nimport { createSignal } from \"../../core/signal.js\";\nimport type { Stream } from \"../../core/stream.js\";\nimport { createStream } from \"../../core/stream.js\";\nimport type { KeyCode } from \"./key-code.js\";\nimport { getSharedKeyboard } from \"./shared.js\";\n\ninterface KeyheldValue {\n held: boolean;\n}\n\nexport interface KeyheldSignal extends Signal<\"keyheld\", KeyheldValue> {}\n\nexport const KEYHELD_SIGNAL_KIND = \"keyheld\" as const;\n\nexport interface KeyheldOptions {\n /**\n * The physical key code to track.\n * @see https://www.w3.org/TR/uievents-code/\n * @example 'KeyZ', 'Space', 'Escape'\n */\n code: KeyCode;\n}\n\n/**\n * Tracks whether a specific key is being held down.\n * Emits only when state changes.\n *\n * @example\n * ```typescript\n * const spaceHeld$ = keyheld(window, { code: 'Space' });\n * spaceHeld$.on(signal => {\n * if (signal.value.held) {\n * console.log('Space is held');\n * }\n * });\n * ```\n */\nexport function keyheld(target: EventTarget, options: KeyheldOptions): Stream<KeyheldSignal> {\n const { code } = options;\n const targetCode = code.toLowerCase();\n\n const source = getSharedKeyboard(target);\n\n return createStream((observer) => {\n let lastHeld: boolean | undefined;\n\n const emitIfChanged = (held: boolean) => {\n if (held !== lastHeld) {\n lastHeld = held;\n observer.next(createSignal(KEYHELD_SIGNAL_KIND, { held }));\n }\n };\n\n return source.on({\n next(signal) {\n const { code: eventCode, phase, repeat } = signal.value;\n if (repeat) return;\n\n if (eventCode.toLowerCase() === targetCode) {\n emitIfChanged(phase === \"down\");\n }\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n}\n","import { createSignal, type Signal } from \"../../core/signal.js\";\nimport type {\n SinglePointerButton,\n SinglePointerPhase,\n SinglePointerType,\n} from \"../single-pointer/types.js\";\n\nexport interface MultiPointerSignal extends Signal<\"multi-pointer\", MultiPointer> {}\n\nexport const MULTI_POINTER_SIGNAL_KIND = \"multi-pointer\" as const;\n\n/**\n * Represents the complete state of all active pointers at a given moment.\n * Emitted as a snapshot whenever any pointer changes state.\n */\nexport interface MultiPointer {\n /** Session-level phase: tracks the overall multi-pointer interaction lifecycle */\n phase: MultiPointerPhase;\n /** Array of currently active pointers */\n pointers: readonly PointerInfo[];\n /** Total number of active pointers */\n count: number;\n}\n\n/**\n * Session-level phase for multi-pointer interactions:\n * - \"idle\": No active pointers\n * - \"active\": One or more pointers are active\n * - \"ended\": All pointers have ended (transition state)\n */\nexport type MultiPointerPhase = \"idle\" | \"active\" | \"ended\";\n\n/**\n * Information about a single pointer within a multi-pointer context.\n */\nexport interface PointerInfo {\n id: string;\n phase: SinglePointerPhase;\n x: number;\n y: number;\n pageX: number;\n pageY: number;\n pointerType: SinglePointerType;\n button: SinglePointerButton;\n /** 0.0 ~ 1.0, default 0.5 if unsupported */\n pressure: number;\n}\n\nexport function createMultiPointerSignal(multiPointer: MultiPointer): MultiPointerSignal {\n return createSignal(MULTI_POINTER_SIGNAL_KIND, multiPointer);\n}\n\nexport function createDefaultPointerInfo(): PointerInfo {\n return {\n id: \"\",\n phase: \"move\",\n x: 0,\n y: 0,\n pageX: 0,\n pageY: 0,\n pointerType: \"unknown\",\n button: \"none\",\n pressure: 0.5,\n };\n}\n","import type { Signal } from \"../../core/signal.js\";\nimport {\n createMultiPointerSignal,\n type MultiPointer,\n type MultiPointerPhase,\n type MultiPointerSignal,\n type PointerInfo,\n} from \"./multi-pointer-signal.js\";\nimport type { MultiPointerOptions } from \"./types.js\";\n\nexport interface MultiPointerRecognizer<InputSignal extends Signal> {\n process(event: InputSignal): MultiPointerSignal | null;\n readonly isActive: boolean;\n readonly activeCount: number;\n reset(): void;\n dispose(): void;\n}\n\n/**\n * Result of processing an input event.\n * - null: No signal should be emitted (e.g., pointer ignored due to maxPointers)\n * - pointers: Updated pointer map after processing the event\n */\nexport interface PointerUpdateResult {\n pointers: Map<string, PointerInfo>;\n endedPointerIds: string[];\n}\n\n/**\n * Creates a recognizer that tracks multiple pointers and emits snapshot signals.\n * Maintains internal state of all active pointers using a Map.\n */\nexport function createMultiPointerRecognizer<InputSignal extends Signal>(\n processor: (\n inputSignal: InputSignal,\n pointerMap: Map<string, PointerInfo>,\n options: Required<MultiPointerOptions>,\n ) => PointerUpdateResult | null,\n options: MultiPointerOptions = {},\n): MultiPointerRecognizer<InputSignal> {\n const opts: Required<MultiPointerOptions> = {\n maxPointers: options.maxPointers ?? 2,\n };\n\n const activePointers = new Map<string, PointerInfo>();\n let previousPhase: MultiPointerPhase = \"idle\";\n\n function computePhase(count: number, endedCount: number): MultiPointerPhase {\n if (count === 0) {\n return previousPhase === \"active\" && endedCount > 0 ? \"ended\" : \"idle\";\n }\n return \"active\";\n }\n\n return {\n process(inputSignal: InputSignal): MultiPointerSignal | null {\n const result = processor(inputSignal, activePointers, opts);\n if (result === null) {\n return null;\n }\n\n const endedPointerIds = result.endedPointerIds;\n for (const id of endedPointerIds) {\n activePointers.delete(id);\n }\n\n const pointers = Array.from(activePointers.values());\n const phase = computePhase(pointers.length, endedPointerIds.length);\n previousPhase = phase === \"ended\" ? \"idle\" : phase;\n\n const multiPointer: MultiPointer = {\n phase,\n pointers,\n count: pointers.length,\n };\n\n return createMultiPointerSignal(multiPointer);\n },\n\n get isActive(): boolean {\n return activePointers.size > 0;\n },\n\n get activeCount(): number {\n return activePointers.size;\n },\n\n reset(): void {\n activePointers.clear();\n previousPhase = \"idle\";\n },\n\n dispose(): void {\n this.reset();\n },\n };\n}\n","import type { Operator } from \"../../core/stream.js\";\nimport { createStream } from \"../../core/stream.js\";\nimport type { DomEventSignal } from \"../dom-event/dom-event-signal.js\";\nimport type {\n SinglePointerButton,\n SinglePointerPhase,\n SinglePointerType,\n} from \"../single-pointer/types.js\";\nimport { toSinglePointerButton } from \"../single-pointer/types.js\";\nimport type { MultiPointerSignal, PointerInfo } from \"./multi-pointer-signal.js\";\nimport {\n createMultiPointerRecognizer,\n type MultiPointerRecognizer,\n type PointerUpdateResult,\n} from \"./recognizer.js\";\nimport type { MultiPointerOptions } from \"./types.js\";\n\nexport function createPointerRecognizer(\n options: MultiPointerOptions = {},\n): MultiPointerRecognizer<DomEventSignal<PointerEvent>> {\n function processor(\n domEventSignal: DomEventSignal<PointerEvent>,\n pointerMap: Map<string, PointerInfo>,\n opts: Required<MultiPointerOptions>,\n ): PointerUpdateResult | null {\n const e = domEventSignal.value;\n const id = `${e.pointerType}-${e.pointerId}`;\n const endedPointerIds: string[] = [];\n\n switch (e.type) {\n case \"pointerdown\": {\n if (pointerMap.size >= opts.maxPointers) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"start\"));\n break;\n }\n\n case \"pointermove\": {\n if (!pointerMap.has(id)) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"move\"));\n break;\n }\n\n case \"pointerup\": {\n if (!pointerMap.has(id)) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"end\"));\n endedPointerIds.push(id);\n break;\n }\n\n case \"pointercancel\": {\n if (!pointerMap.has(id)) {\n return null;\n }\n pointerMap.set(id, createPointerInfo(e, \"cancel\"));\n endedPointerIds.push(id);\n break;\n }\n\n default:\n return null;\n }\n\n return { pointers: pointerMap, endedPointerIds };\n }\n\n return createMultiPointerRecognizer(processor, options);\n}\n\nexport function multiPointerFromPointer(\n options: MultiPointerOptions = {},\n): Operator<DomEventSignal<PointerEvent>, MultiPointerSignal> {\n return (source) =>\n createStream((observer) => {\n const recognizer = createPointerRecognizer(options);\n\n const unsub = source.on({\n next(event) {\n const signal = recognizer.process(event);\n if (signal) {\n observer.next(signal);\n }\n },\n error(err) {\n observer.error?.(err);\n },\n complete() {\n observer.complete?.();\n },\n });\n\n return () => {\n unsub();\n recognizer.dispose();\n };\n });\n}\n\nfunction createPointerInfo(e: PointerEvent, phase: SinglePointerPhase): PointerInfo {\n const button: SinglePointerButton =\n phase === \"start\" || phase === \"end\" ? toSinglePointerButton(e.button) : \"none\";\n\n return {\n id: `${e.pointerType}-${e.pointerId}`,\n phase,\n x: e.clientX,\n y: e.clientY,\n pageX: e.pageX,\n pageY: e.pageY,\n pointerType: normalizePointerType(e.pointerType),\n button,\n pressure: e.pressure,\n };\n}\n\nfunction normalizePointerType(type: string): SinglePointerType {\n switch (type) {\n case \"mouse\":\n return \"mouse\";\n case \"touch\":\n return \"touch\";\n case \"pen\":\n return \"pen\";\n default:\n return \"unknown\";\n }\n}\n","import type { Stream } from \"../../core/stream.js\";\nimport { pointerEvents } from \"../dom-event/pointer-events.js\";\nimport type { MultiPointerSignal } from \"./multi-pointer-signal.js\";\nimport { multiPointerFromPointer } from \"./recognizer-from-pointer.js\";\nimport type { MultiPointerOptions } from \"./types.js\";\n\nexport function multiPointer(\n target: EventTarget,\n options: MultiPointerOptions = {},\n): Stream<MultiPointerSignal> {\n const source = pointerEvents(target);\n return multiPointerFromPointer(options)(source);\n}\n","import type { Stream } from \"../../core/stream.js\";\nimport { pointerEvents } from \"../dom-event/pointer-events.js\";\nimport { singlePointerFromPointer } from \"./recognizer-from-pointer.js\";\nimport type { SinglePointerSignal } from \"./single-pointer-signal.js\";\nimport type { SinglePointerOptions } from \"./types.js\";\n\nexport function singlePointer(\n target: EventTarget,\n options: SinglePointerOptions = {},\n): Stream<SinglePointerSignal> {\n const source = pointerEvents(target);\n return singlePointerFromPointer(options)(source);\n}\n","import { createSignal, type Signal } from \"../../core/signal.js\";\n\nexport type WheelDeltaMode = \"pixel\" | \"line\" | \"page\";\n\n/**\n * Wheel event data normalized into a consistent structure.\n * Provides scroll deltas and position information.\n */\nexport interface WheelValue {\n /** Horizontal scroll delta */\n deltaX: number;\n /** Vertical scroll delta (positive = scroll down/zoom out) */\n deltaY: number;\n /** Z-axis scroll delta (rare, used by some 3D mice) */\n deltaZ: number;\n /** Unit of the delta values */\n deltaMode: WheelDeltaMode;\n /** Client X coordinate (viewport-relative) */\n x: number;\n /** Client Y coordinate (viewport-relative) */\n y: number;\n /** Page X coordinate (document-relative) */\n pageX: number;\n /** Page Y coordinate (document-relative) */\n pageY: number;\n altKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n /** Original DOM WheelEvent for advanced use cases like preventDefault */\n originalEvent: WheelEvent;\n}\n\nexport interface WheelSignal extends Signal<\"wheel\", WheelValue> {}\n\nexport const WHEEL_SIGNAL_KIND = \"wheel\" as const;\n\nexport function createWheelSignal(value: WheelValue): WheelSignal {\n return createSignal(WHEEL_SIGNAL_KIND, value);\n}\n\nfunction toDeltaMode(mode: number): WheelDeltaMode {\n switch (mode) {\n case 0:\n return \"pixel\";\n case 1:\n return \"line\";\n case 2:\n return \"page\";\n default:\n return \"pixel\";\n }\n}\n\nexport function createWheelSignalFromEvent(event: WheelEvent): WheelSignal {\n return createWheelSignal({\n deltaX: event.deltaX,\n deltaY: event.deltaY,\n deltaZ: event.deltaZ,\n deltaMode: toDeltaMode(event.deltaMode),\n x: event.clientX,\n y: event.clientY,\n pageX: event.pageX,\n pageY: event.pageY,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n originalEvent: event,\n });\n}\n","import { createStream, type Stream } from \"../../core/stream.js\";\nimport { share } from \"../../operators/share.js\";\nimport type { ModifierKey } from \"../keyboard/keyboard.js\";\nimport { createWheelSignalFromEvent, type WheelSignal } from \"./wheel-signal.js\";\n\nexport interface WheelOptions {\n /**\n * Whether to use passive event listener.\n * Set to false if you need to call preventDefault() on the originalEvent.\n * @default true\n */\n passive?: boolean;\n\n /**\n * Filter by modifier keys. Uses OR logic (matches if any is pressed).\n * @example ['meta', 'ctrl'] - matches if metaKey OR ctrlKey is pressed\n */\n modifiers?: ModifierKey[];\n\n /**\n * If true, calls preventDefault() on matching events.\n * Requires passive: false to work.\n * @default false\n */\n preventDefault?: boolean;\n}\n\n/**\n * Cache for shared wheel streams per EventTarget and passive option.\n * Using WeakMap ensures streams are garbage collected when targets are removed.\n */\nconst sharedWheelStreams = new WeakMap<EventTarget, Map<boolean, Stream<WheelSignal>>>();\n\nfunction getSharedWheel(target: EventTarget, passive: boolean): Stream<WheelSignal> {\n let passiveMap = sharedWheelStreams.get(target);\n if (!passiveMap) {\n passiveMap = new Map();\n sharedWheelStreams.set(target, passiveMap);\n }\n\n let stream = passiveMap.get(passive);\n if (!stream) {\n stream = share<WheelSignal>()(createWheelStream(target, passive));\n passiveMap.set(passive, stream);\n }\n return stream;\n}\n\nfunction createWheelStream(target: EventTarget, passive: boolean): Stream<WheelSignal> {\n return createStream<WheelSignal>((observer) => {\n const handler = (e: Event) => {\n observer.next(createWheelSignalFromEvent(e as WheelEvent));\n };\n\n target.addEventListener(\"wheel\", handler, { passive });\n\n return () => {\n target.removeEventListener(\"wheel\", handler);\n };\n });\n}\n\n/**\n * Creates a stream of wheel signals from wheel events on the target.\n * Automatically shares the wheel stream for the same EventTarget and passive option.\n *\n * @example\n * ```typescript\n * // Basic usage (passive by default for performance)\n * wheel(element).on(signal => {\n * console.log(signal.value.deltaY);\n * });\n *\n * // With modifier filter and preventDefault\n * wheel(element, {\n * passive: false,\n * modifiers: ['meta', 'ctrl'],\n * preventDefault: true\n * }).on(signal => {\n * // Only fires when Ctrl or Cmd is held\n * });\n * ```\n */\nexport function wheel(target: EventTarget, options?: WheelOptions): Stream<WheelSignal> {\n const passive = options?.passive ?? true;\n const modifiers = options?.modifiers;\n const preventDefault = options?.preventDefault ?? false;\n\n const source = getSharedWheel(target, passive);\n\n // If no filtering needed, return shared stream directly\n if (!modifiers?.length && !preventDefault) {\n return source;\n }\n\n const matchesModifiers = (value: WheelSignal[\"value\"]): boolean => {\n if (!modifiers || modifiers.length === 0) return true;\n return modifiers.some((mod) => {\n switch (mod) {\n case \"meta\":\n return value.metaKey;\n case \"ctrl\":\n return value.ctrlKey;\n case \"alt\":\n return value.altKey;\n case \"shift\":\n return value.shiftKey;\n default:\n return false;\n }\n });\n };\n\n return createStream<WheelSignal>((observer) => {\n return source.on({\n next(signal) {\n try {\n if (matchesModifiers(signal.value)) {\n if (preventDefault) {\n signal.value.originalEvent.preventDefault();\n }\n observer.next(signal);\n }\n } catch (err) {\n observer.error?.(err);\n }\n },\n error: observer.error?.bind(observer),\n complete: observer.complete?.bind(observer),\n });\n });\n}\n"],"names":["DOM_EVENT_SIGNAL_KIND","createDomEventSignal","event","createSignal","domEvent","target","eventName","options","createStream","observer","handler","MOUSE_EVENTS","mouseEvents","i","POINTER_EVENTS","pointerEvents","TOUCH_EVENTS","touchEvents","KEYBOARD_SIGNAL_KIND","createKeyboardSignal","value","createKeyboardSignalFromEvent","phase","sharedKeyboardStreams","sharedKeydownStreams","createRawKeyboardStream","handleKeyDown","e","handleKeyUp","getSharedKeyboard","stream","share","createRawKeydownStream","getSharedKeydown","keyboard","modifiers","preventDefault","allowRepeat","codeList","c","baseStream","matchesCode","matchesModifiers","mod","signal","repeat","keydown","KEYHELD_SIGNAL_KIND","keyheld","code","targetCode","source","lastHeld","emitIfChanged","held","eventCode","MULTI_POINTER_SIGNAL_KIND","createMultiPointerSignal","multiPointer","createMultiPointerRecognizer","processor","opts","activePointers","previousPhase","computePhase","count","endedCount","inputSignal","result","endedPointerIds","id","pointers","createPointerRecognizer","domEventSignal","pointerMap","createPointerInfo","multiPointerFromPointer","recognizer","unsub","err","button","toSinglePointerButton","normalizePointerType","type","singlePointer","singlePointerFromPointer","WHEEL_SIGNAL_KIND","createWheelSignal","toDeltaMode","mode","createWheelSignalFromEvent","sharedWheelStreams","getSharedWheel","passive","passiveMap","createWheelStream","wheel"],"mappings":"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"}