@thi.ng/rstream-gestures 5.0.36 → 5.0.37

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-09T19:12:03Z
3
+ - **Last updated**: 2023-12-11T10:07:09Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/api.js CHANGED
@@ -1 +0,0 @@
1
- export {};
package/gesture-stream.js CHANGED
@@ -5,217 +5,182 @@ import { fromDOMEvent } from "@thi.ng/rstream/event";
5
5
  import { __nextID } from "@thi.ng/rstream/idgen";
6
6
  import { merge } from "@thi.ng/rstream/merge";
7
7
  import { map } from "@thi.ng/transducers/map";
8
- const START_EVENTS = new Set([
9
- "mousedown",
10
- "touchmove",
11
- "touchstart",
12
- "mousemove",
8
+ const START_EVENTS = /* @__PURE__ */ new Set([
9
+ "mousedown",
10
+ "touchmove",
11
+ "touchstart",
12
+ "mousemove"
13
13
  ]);
14
- const END_EVENTS = new Set(["mouseup", "touchend", "touchcancel"]);
14
+ const END_EVENTS = /* @__PURE__ */ new Set(["mouseup", "touchend", "touchcancel"]);
15
15
  const BASE_EVENTS = ["mousemove", "mousedown", "touchstart", "wheel"];
16
16
  const EVENT_GESTURETYPES = {
17
- touchstart: "start",
18
- touchmove: "drag",
19
- touchend: "end",
20
- touchcancel: "end",
21
- mousedown: "start",
22
- mouseup: "end",
23
- wheel: "zoom",
17
+ touchstart: "start",
18
+ touchmove: "drag",
19
+ touchend: "end",
20
+ touchcancel: "end",
21
+ mousedown: "start",
22
+ mouseup: "end",
23
+ wheel: "zoom"
24
24
  };
25
- /**
26
- * Attaches mouse & touch event listeners to given DOM element and returns a
27
- * stream of {@link GestureEvent}s and their {@link GestureInfo} details.
28
- *
29
- * In multi-touch environments, a `GestureEvent` can contain multiple such
30
- * `GestureInfo` objects (one per active touch). In general, the `click` and
31
- * `delta` values are only present if the abstracted event `type == "drag"`.
32
- * Both (and `pos` too) are 2-element arrays of `[x,y]` coordinates.
33
- *
34
- * The `zoom` value is always present, but is only updated with wheel events.
35
- * The value will be constrained to `minZoom` ... `maxZoom` interval (provided
36
- * via options object).
37
- *
38
- * Note: If using `preventDefault` and attaching the event stream to
39
- * `document.body`, the following event listener options SHOULD be used:
40
- *
41
- * @example
42
- * ```ts
43
- * eventOpts: { passive: false }
44
- * ```
45
- *
46
- * https://www.chromestatus.com/features/5093566007214080
47
- *
48
- * @param el -
49
- * @param opts -
50
- */
51
- export const gestureStream = (el, _opts) => {
52
- const opts = {
53
- zoom: 1,
54
- absZoom: true,
55
- minZoom: 0.25,
56
- maxZoom: 4,
57
- smooth: 1,
58
- eventOpts: { capture: true },
59
- preventDefault: true,
60
- preventScrollOnZoom: true,
61
- preventContextMenu: true,
62
- local: true,
63
- scale: false,
64
- ..._opts,
65
- };
66
- opts.id = opts.id || `gestures-${__nextID()}`;
67
- const active = [];
68
- let zoom = clamp(isNumber(opts.zoom) ? opts.zoom : opts.zoom.deref() || 1, opts.minZoom, opts.maxZoom);
69
- let zoomDelta = 0;
70
- let numTouches = 0;
71
- let lastPos = [0, 0];
72
- let tempStreams;
73
- const isBody = el === document.body;
74
- const tempEvents = [
75
- "touchend",
76
- "touchcancel",
77
- "touchmove",
78
- "mouseup",
79
- ];
80
- !isBody && tempEvents.push("mousemove");
81
- opts.preventContextMenu &&
82
- el.addEventListener("contextmenu", (e) => e.preventDefault());
83
- const gestureStart = (etype, events, bounds, isTouch) => {
84
- const isStart = etype === "mousedown" || etype === "touchstart";
85
- for (let t of events) {
86
- const id = t.identifier || 0;
87
- const pos = getPos(t, bounds, opts.local, opts.scale);
88
- let touch = active.find((t) => t.id === id);
89
- if (!touch && isStart) {
90
- touch = { id, start: pos };
91
- active.push(touch);
92
- numTouches++;
93
- }
94
- if (touch) {
95
- touch.pos = pos;
96
- touch.delta = [
97
- pos[0] - touch.start[0],
98
- pos[1] - touch.start[1],
99
- ];
100
- if (isTouch) {
101
- touch.force = t.force;
102
- }
103
- }
104
- }
105
- if (isStart && !tempStreams) {
106
- tempStreams = tempEvents.map((id) => eventSource(document.body, id, opts, "-temp"));
107
- stream.addAll(tempStreams);
108
- !isBody && stream.removeID("mousemove");
109
- }
110
- };
111
- const gestureEnd = (events) => {
112
- for (let t of events) {
113
- const id = t.identifier || 0;
114
- const idx = active.findIndex((t) => t.id === id);
115
- if (idx !== -1) {
116
- active.splice(idx, 1);
117
- numTouches--;
118
- }
119
- }
120
- if (numTouches === 0) {
121
- stream.removeAll(tempStreams);
122
- !isBody && stream.add(eventSource(el, "mousemove", opts));
123
- tempStreams = undefined;
25
+ const gestureStream = (el, _opts) => {
26
+ const opts = {
27
+ zoom: 1,
28
+ absZoom: true,
29
+ minZoom: 0.25,
30
+ maxZoom: 4,
31
+ smooth: 1,
32
+ eventOpts: { capture: true },
33
+ preventDefault: true,
34
+ preventScrollOnZoom: true,
35
+ preventContextMenu: true,
36
+ local: true,
37
+ scale: false,
38
+ ..._opts
39
+ };
40
+ opts.id = opts.id || `gestures-${__nextID()}`;
41
+ const active = [];
42
+ let zoom = clamp(
43
+ isNumber(opts.zoom) ? opts.zoom : opts.zoom.deref() || 1,
44
+ opts.minZoom,
45
+ opts.maxZoom
46
+ );
47
+ let zoomDelta = 0;
48
+ let numTouches = 0;
49
+ let lastPos = [0, 0];
50
+ let tempStreams;
51
+ const isBody = el === document.body;
52
+ const tempEvents = [
53
+ "touchend",
54
+ "touchcancel",
55
+ "touchmove",
56
+ "mouseup"
57
+ ];
58
+ !isBody && tempEvents.push("mousemove");
59
+ opts.preventContextMenu && el.addEventListener("contextmenu", (e) => e.preventDefault());
60
+ const gestureStart = (etype, events, bounds, isTouch) => {
61
+ const isStart = etype === "mousedown" || etype === "touchstart";
62
+ for (let t of events) {
63
+ const id = t.identifier || 0;
64
+ const pos = getPos(t, bounds, opts.local, opts.scale);
65
+ let touch = active.find((t2) => t2.id === id);
66
+ if (!touch && isStart) {
67
+ touch = { id, start: pos };
68
+ active.push(touch);
69
+ numTouches++;
70
+ }
71
+ if (touch) {
72
+ touch.pos = pos;
73
+ touch.delta = [
74
+ pos[0] - touch.start[0],
75
+ pos[1] - touch.start[1]
76
+ ];
77
+ if (isTouch) {
78
+ touch.force = t.force;
124
79
  }
125
- };
126
- const updateZoom = (e) => {
127
- const zdelta = opts.smooth *
128
- ("wheelDeltaY" in e
129
- ? -e.wheelDeltaY / 120
130
- : e.deltaY / 40);
131
- zoom = opts.absZoom
132
- ? clamp(zoom + zdelta, opts.minZoom, opts.maxZoom)
133
- : zdelta;
134
- zoomDelta = zdelta;
135
- };
136
- const stream = merge({
137
- id: opts.id,
138
- src: BASE_EVENTS.map((id) => eventSource(el, id, opts)),
139
- xform: map((e) => {
140
- const etype = e.type;
141
- if (etype === "$zoom") {
142
- zoomDelta = e.value - zoom;
143
- if (opts.absZoom) {
144
- zoom = clamp(zoom + zoomDelta, opts.minZoom, opts.maxZoom);
145
- }
146
- else {
147
- zoom = zoomDelta;
148
- }
149
- return {
150
- pos: lastPos.slice(),
151
- buttons: 0,
152
- type: "zoom",
153
- active,
154
- zoom,
155
- zoomDelta,
156
- isTouch: false,
157
- };
158
- }
159
- const type = classifyEventType(etype, !!tempStreams);
160
- let isTouch = !!e.touches;
161
- let events = isTouch
162
- ? Array.from(e.changedTouches)
163
- : [e];
164
- const bounds = el.getBoundingClientRect();
165
- if (START_EVENTS.has(etype)) {
166
- gestureStart(etype, events, bounds, isTouch);
167
- }
168
- else if (END_EVENTS.has(etype)) {
169
- gestureEnd(events);
170
- }
171
- else if (type === "zoom") {
172
- updateZoom(e);
173
- }
174
- lastPos = getPos(events[0], bounds, opts.local, opts.scale);
175
- opts.preventDefault && e.preventDefault();
176
- return {
177
- event: e,
178
- pos: lastPos,
179
- buttons: isTouch ? active.length : e.buttons,
180
- type,
181
- active,
182
- zoom,
183
- zoomDelta,
184
- isTouch,
185
- };
186
- }),
187
- });
188
- // attach zoom reset
189
- if (!isNumber(opts.zoom)) {
190
- stream.add(opts.zoom.map((x) => ({ type: "$zoom", value: x })));
80
+ }
81
+ }
82
+ if (isStart && !tempStreams) {
83
+ tempStreams = tempEvents.map(
84
+ (id) => eventSource(document.body, id, opts, "-temp")
85
+ );
86
+ stream.addAll(tempStreams);
87
+ !isBody && stream.removeID("mousemove");
88
+ }
89
+ };
90
+ const gestureEnd = (events) => {
91
+ for (let t of events) {
92
+ const id = t.identifier || 0;
93
+ const idx = active.findIndex((t2) => t2.id === id);
94
+ if (idx !== -1) {
95
+ active.splice(idx, 1);
96
+ numTouches--;
97
+ }
191
98
  }
192
- return stream;
99
+ if (numTouches === 0) {
100
+ stream.removeAll(tempStreams);
101
+ !isBody && stream.add(eventSource(el, "mousemove", opts));
102
+ tempStreams = void 0;
103
+ }
104
+ };
105
+ const updateZoom = (e) => {
106
+ const zdelta = opts.smooth * ("wheelDeltaY" in e ? -e.wheelDeltaY / 120 : e.deltaY / 40);
107
+ zoom = opts.absZoom ? clamp(zoom + zdelta, opts.minZoom, opts.maxZoom) : zdelta;
108
+ zoomDelta = zdelta;
109
+ };
110
+ const stream = merge({
111
+ id: opts.id,
112
+ src: BASE_EVENTS.map((id) => eventSource(el, id, opts)),
113
+ xform: map((e) => {
114
+ const etype = e.type;
115
+ if (etype === "$zoom") {
116
+ zoomDelta = e.value - zoom;
117
+ if (opts.absZoom) {
118
+ zoom = clamp(zoom + zoomDelta, opts.minZoom, opts.maxZoom);
119
+ } else {
120
+ zoom = zoomDelta;
121
+ }
122
+ return {
123
+ pos: lastPos.slice(),
124
+ buttons: 0,
125
+ type: "zoom",
126
+ active,
127
+ zoom,
128
+ zoomDelta,
129
+ isTouch: false
130
+ };
131
+ }
132
+ const type = classifyEventType(etype, !!tempStreams);
133
+ let isTouch = !!e.touches;
134
+ let events = isTouch ? Array.from(e.changedTouches) : [e];
135
+ const bounds = el.getBoundingClientRect();
136
+ if (START_EVENTS.has(etype)) {
137
+ gestureStart(etype, events, bounds, isTouch);
138
+ } else if (END_EVENTS.has(etype)) {
139
+ gestureEnd(events);
140
+ } else if (type === "zoom") {
141
+ updateZoom(e);
142
+ }
143
+ lastPos = getPos(events[0], bounds, opts.local, opts.scale);
144
+ opts.preventDefault && e.preventDefault();
145
+ return {
146
+ event: e,
147
+ pos: lastPos,
148
+ buttons: isTouch ? active.length : e.buttons,
149
+ type,
150
+ active,
151
+ zoom,
152
+ zoomDelta,
153
+ isTouch
154
+ };
155
+ })
156
+ });
157
+ if (!isNumber(opts.zoom)) {
158
+ stream.add(opts.zoom.map((x) => ({ type: "$zoom", value: x })));
159
+ }
160
+ return stream;
193
161
  };
194
162
  const eventSource = (el, type, opts, suffix = "") => {
195
- let eventOpts = opts.eventOpts;
196
- if (type === "wheel" && opts.preventScrollOnZoom) {
197
- eventOpts = isBoolean(eventOpts)
198
- ? { capture: eventOpts, passive: false }
199
- : { ...eventOpts, passive: false };
200
- }
201
- return fromDOMEvent(el, type, eventOpts, { id: type + suffix });
163
+ let eventOpts = opts.eventOpts;
164
+ if (type === "wheel" && opts.preventScrollOnZoom) {
165
+ eventOpts = isBoolean(eventOpts) ? { capture: eventOpts, passive: false } : { ...eventOpts, passive: false };
166
+ }
167
+ return fromDOMEvent(el, type, eventOpts, { id: type + suffix });
202
168
  };
203
- const classifyEventType = (etype, isActive) => etype === "mousemove"
204
- ? isActive
205
- ? "drag"
206
- : "move"
207
- : EVENT_GESTURETYPES[etype];
169
+ const classifyEventType = (etype, isActive) => etype === "mousemove" ? isActive ? "drag" : "move" : EVENT_GESTURETYPES[etype];
208
170
  const getPos = (e, bounds, isLocal, doScale) => {
209
- let x = e.clientX;
210
- let y = e.clientY;
211
- if (isLocal) {
212
- x -= bounds.left;
213
- y -= bounds.top;
214
- }
215
- if (doScale) {
216
- const dpr = window.devicePixelRatio || 1;
217
- x *= dpr;
218
- y *= dpr;
219
- }
220
- return [x | 0, y | 0];
171
+ let x = e.clientX;
172
+ let y = e.clientY;
173
+ if (isLocal) {
174
+ x -= bounds.left;
175
+ y -= bounds.top;
176
+ }
177
+ if (doScale) {
178
+ const dpr = window.devicePixelRatio || 1;
179
+ x *= dpr;
180
+ y *= dpr;
181
+ }
182
+ return [x | 0, y | 0];
183
+ };
184
+ export {
185
+ gestureStream
221
186
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/rstream-gestures",
3
- "version": "5.0.36",
3
+ "version": "5.0.37",
4
4
  "description": "Unified mouse, mouse wheel & multi-touch event stream abstraction",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -28,7 +28,9 @@
28
28
  ],
29
29
  "license": "Apache-2.0",
30
30
  "scripts": {
31
- "build": "yarn clean && tsc --declaration",
31
+ "build": "yarn build:esbuild && yarn build:decl",
32
+ "build:decl": "tsc --declaration --emitDeclarationOnly",
33
+ "build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
32
34
  "clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
33
35
  "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
34
36
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
@@ -37,14 +39,15 @@
37
39
  "test": "bun test"
38
40
  },
39
41
  "dependencies": {
40
- "@thi.ng/api": "^8.9.11",
41
- "@thi.ng/checks": "^3.4.11",
42
- "@thi.ng/math": "^5.7.6",
43
- "@thi.ng/rstream": "^8.2.13",
44
- "@thi.ng/transducers": "^8.8.14"
42
+ "@thi.ng/api": "^8.9.12",
43
+ "@thi.ng/checks": "^3.4.12",
44
+ "@thi.ng/math": "^5.7.7",
45
+ "@thi.ng/rstream": "^8.2.14",
46
+ "@thi.ng/transducers": "^8.8.15"
45
47
  },
46
48
  "devDependencies": {
47
49
  "@microsoft/api-extractor": "^7.38.3",
50
+ "esbuild": "^0.19.8",
48
51
  "rimraf": "^5.0.5",
49
52
  "tools": "^0.0.1",
50
53
  "typedoc": "^0.25.4",
@@ -93,5 +96,5 @@
93
96
  ],
94
97
  "year": 2018
95
98
  },
96
- "gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
99
+ "gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
97
100
  }