@deibid/no-hands-react 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +68 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +503 -0
- package/dist/index.mjs +467 -0
- package/package.json +34 -0
- package/src/context/context.tsx +147 -0
- package/src/context/index.ts +1 -0
- package/src/context/types.ts +22 -0
- package/src/detection-bounds-display.tsx +29 -0
- package/src/hooks.ts +239 -0
- package/src/index.ts +24 -0
- package/src/nhcomponent.ts +87 -0
- package/src/pointer.tsx +62 -0
- package/src/types.ts +25 -0
- package/tsconfig.json +17 -0
- package/tsconfig.node.json +11 -0
- package/tsup.config.ts +13 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React$1 from 'react';
|
|
2
|
+
import React__default, { PropsWithChildren } from 'react';
|
|
3
|
+
import { Point, Rect, CreateEventDispatcherOpts, EventDispatcher, FaceTracker } from '@deibid/no-hands';
|
|
4
|
+
export { NHEvent } from '@deibid/no-hands';
|
|
5
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
interface NHEventProps {
|
|
8
|
+
onNHMouseEnter?: EventListener;
|
|
9
|
+
onNHMouseLeave?: EventListener;
|
|
10
|
+
onNHClickGestureBegin?: EventListener;
|
|
11
|
+
onNHClickGestureEnd?: EventListener;
|
|
12
|
+
}
|
|
13
|
+
type HTMLElementType = keyof React__default.JSX.IntrinsicElements;
|
|
14
|
+
type NHComponentProps<T extends HTMLElementType> = React__default.ComponentPropsWithoutRef<T> & NHEventProps;
|
|
15
|
+
type NHComponent<T extends HTMLElementType> = React__default.FC<NHComponentProps<T>>;
|
|
16
|
+
type NHNamespace = {
|
|
17
|
+
[K in HTMLElementType]: NHComponent<K>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
declare const NH: NHNamespace;
|
|
21
|
+
|
|
22
|
+
declare function useEvents<T extends HTMLElement>(props: NHEventProps): {
|
|
23
|
+
ref: React$1.RefObject<T | null>;
|
|
24
|
+
};
|
|
25
|
+
declare function useCamera(): {
|
|
26
|
+
stream: MediaStream | null;
|
|
27
|
+
loading: boolean;
|
|
28
|
+
error: Error | null;
|
|
29
|
+
};
|
|
30
|
+
declare function useNHPoint(): Point | null;
|
|
31
|
+
declare function useWindowSize(): {
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
centerX: number;
|
|
35
|
+
centerY: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
interface INHContext {
|
|
39
|
+
error: Error | null;
|
|
40
|
+
eventDispatcher: EventDispatcher | null;
|
|
41
|
+
faceTracker: FaceTracker | null;
|
|
42
|
+
loading: boolean;
|
|
43
|
+
videoStream: MediaStream | null;
|
|
44
|
+
}
|
|
45
|
+
interface NHProviderOptions {
|
|
46
|
+
faceTrackerOpts?: {
|
|
47
|
+
detectionBounds?: Rect;
|
|
48
|
+
projectionBounds?: Rect;
|
|
49
|
+
};
|
|
50
|
+
eventDispatcherOpts?: CreateEventDispatcherOpts;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type NHProviderProps = PropsWithChildren<NHProviderOptions>;
|
|
54
|
+
declare function NHProvider({ children, eventDispatcherOpts, faceTrackerOpts }: NHProviderProps): react_jsx_runtime.JSX.Element;
|
|
55
|
+
declare function useNH(): INHContext;
|
|
56
|
+
|
|
57
|
+
interface DetectionBoundsDisplayProps {
|
|
58
|
+
detectionBounds: Rect;
|
|
59
|
+
style?: React.CSSProperties;
|
|
60
|
+
}
|
|
61
|
+
declare function DetectionBoundsDisplay({ detectionBounds, style }: DetectionBoundsDisplayProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
interface PointerProps extends React.PropsWithChildren {
|
|
64
|
+
style?: React.CSSProperties;
|
|
65
|
+
}
|
|
66
|
+
declare function Pointer({ children, style }: PointerProps): react_jsx_runtime.JSX.Element;
|
|
67
|
+
|
|
68
|
+
export { DetectionBoundsDisplay, NH, NHProvider, Pointer, useCamera, useEvents, useNH, useNHPoint, useWindowSize };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React$1 from 'react';
|
|
2
|
+
import React__default, { PropsWithChildren } from 'react';
|
|
3
|
+
import { Point, Rect, CreateEventDispatcherOpts, EventDispatcher, FaceTracker } from '@deibid/no-hands';
|
|
4
|
+
export { NHEvent } from '@deibid/no-hands';
|
|
5
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
interface NHEventProps {
|
|
8
|
+
onNHMouseEnter?: EventListener;
|
|
9
|
+
onNHMouseLeave?: EventListener;
|
|
10
|
+
onNHClickGestureBegin?: EventListener;
|
|
11
|
+
onNHClickGestureEnd?: EventListener;
|
|
12
|
+
}
|
|
13
|
+
type HTMLElementType = keyof React__default.JSX.IntrinsicElements;
|
|
14
|
+
type NHComponentProps<T extends HTMLElementType> = React__default.ComponentPropsWithoutRef<T> & NHEventProps;
|
|
15
|
+
type NHComponent<T extends HTMLElementType> = React__default.FC<NHComponentProps<T>>;
|
|
16
|
+
type NHNamespace = {
|
|
17
|
+
[K in HTMLElementType]: NHComponent<K>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
declare const NH: NHNamespace;
|
|
21
|
+
|
|
22
|
+
declare function useEvents<T extends HTMLElement>(props: NHEventProps): {
|
|
23
|
+
ref: React$1.RefObject<T | null>;
|
|
24
|
+
};
|
|
25
|
+
declare function useCamera(): {
|
|
26
|
+
stream: MediaStream | null;
|
|
27
|
+
loading: boolean;
|
|
28
|
+
error: Error | null;
|
|
29
|
+
};
|
|
30
|
+
declare function useNHPoint(): Point | null;
|
|
31
|
+
declare function useWindowSize(): {
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
centerX: number;
|
|
35
|
+
centerY: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
interface INHContext {
|
|
39
|
+
error: Error | null;
|
|
40
|
+
eventDispatcher: EventDispatcher | null;
|
|
41
|
+
faceTracker: FaceTracker | null;
|
|
42
|
+
loading: boolean;
|
|
43
|
+
videoStream: MediaStream | null;
|
|
44
|
+
}
|
|
45
|
+
interface NHProviderOptions {
|
|
46
|
+
faceTrackerOpts?: {
|
|
47
|
+
detectionBounds?: Rect;
|
|
48
|
+
projectionBounds?: Rect;
|
|
49
|
+
};
|
|
50
|
+
eventDispatcherOpts?: CreateEventDispatcherOpts;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type NHProviderProps = PropsWithChildren<NHProviderOptions>;
|
|
54
|
+
declare function NHProvider({ children, eventDispatcherOpts, faceTrackerOpts }: NHProviderProps): react_jsx_runtime.JSX.Element;
|
|
55
|
+
declare function useNH(): INHContext;
|
|
56
|
+
|
|
57
|
+
interface DetectionBoundsDisplayProps {
|
|
58
|
+
detectionBounds: Rect;
|
|
59
|
+
style?: React.CSSProperties;
|
|
60
|
+
}
|
|
61
|
+
declare function DetectionBoundsDisplay({ detectionBounds, style }: DetectionBoundsDisplayProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
interface PointerProps extends React.PropsWithChildren {
|
|
64
|
+
style?: React.CSSProperties;
|
|
65
|
+
}
|
|
66
|
+
declare function Pointer({ children, style }: PointerProps): react_jsx_runtime.JSX.Element;
|
|
67
|
+
|
|
68
|
+
export { DetectionBoundsDisplay, NH, NHProvider, Pointer, useCamera, useEvents, useNH, useNHPoint, useWindowSize };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
DetectionBoundsDisplay: () => DetectionBoundsDisplay,
|
|
34
|
+
NH: () => NH,
|
|
35
|
+
NHEvent: () => import_no_hands3.NHEvent,
|
|
36
|
+
NHProvider: () => NHProvider,
|
|
37
|
+
Pointer: () => Pointer,
|
|
38
|
+
useCamera: () => useCamera,
|
|
39
|
+
useEvents: () => useEvents,
|
|
40
|
+
useNH: () => useNH,
|
|
41
|
+
useNHPoint: () => useNHPoint,
|
|
42
|
+
useWindowSize: () => useWindowSize
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(index_exports);
|
|
45
|
+
|
|
46
|
+
// src/nhcomponent.ts
|
|
47
|
+
var import_react3 = __toESM(require("react"));
|
|
48
|
+
|
|
49
|
+
// src/hooks.ts
|
|
50
|
+
var import_react2 = require("react");
|
|
51
|
+
var import_no_hands2 = require("@deibid/no-hands");
|
|
52
|
+
|
|
53
|
+
// src/context/context.tsx
|
|
54
|
+
var import_no_hands = require("@deibid/no-hands");
|
|
55
|
+
var import_react = require("react");
|
|
56
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
57
|
+
var NHContext = (0, import_react.createContext)({
|
|
58
|
+
error: null,
|
|
59
|
+
eventDispatcher: null,
|
|
60
|
+
faceTracker: null,
|
|
61
|
+
loading: false,
|
|
62
|
+
videoStream: null
|
|
63
|
+
});
|
|
64
|
+
function NHProvider({ children, eventDispatcherOpts, faceTrackerOpts }) {
|
|
65
|
+
const [faceTracker, setFaceTracker] = (0, import_react.useState)(null);
|
|
66
|
+
const [eventDispatcher] = (0, import_react.useState)(
|
|
67
|
+
() => (0, import_no_hands.createEventDispatcher)(eventDispatcherOpts)
|
|
68
|
+
);
|
|
69
|
+
const faceTrackerOptsRef = (0, import_react.useRef)(faceTrackerOpts);
|
|
70
|
+
const streamOwnerVideoRef = (0, import_react.useRef)(null);
|
|
71
|
+
const { error, loading, stream } = useCamera();
|
|
72
|
+
(0, import_react.useEffect)(() => {
|
|
73
|
+
faceTrackerOptsRef.current = faceTrackerOpts;
|
|
74
|
+
});
|
|
75
|
+
(0, import_react.useEffect)(() => {
|
|
76
|
+
const videoElement = streamOwnerVideoRef.current;
|
|
77
|
+
if (!videoElement || !stream) return;
|
|
78
|
+
let ftActive = true;
|
|
79
|
+
let localFaceTracker;
|
|
80
|
+
async function init() {
|
|
81
|
+
if (!videoElement) {
|
|
82
|
+
console.warn("has no video element");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
localFaceTracker = await (0, import_no_hands.createFaceTracker)({
|
|
86
|
+
videoElement,
|
|
87
|
+
detectionBounds: faceTrackerOptsRef.current?.detectionBounds,
|
|
88
|
+
projectionBounds: faceTrackerOptsRef.current?.projectionBounds
|
|
89
|
+
});
|
|
90
|
+
if (!ftActive) {
|
|
91
|
+
localFaceTracker.stop();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
videoElement.srcObject = stream;
|
|
95
|
+
videoElement.addEventListener("loadeddata", () => {
|
|
96
|
+
localFaceTracker.subscribe((point) => {
|
|
97
|
+
eventDispatcher.computeEvents(point);
|
|
98
|
+
});
|
|
99
|
+
localFaceTracker.start();
|
|
100
|
+
setFaceTracker(localFaceTracker);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
init();
|
|
104
|
+
return () => {
|
|
105
|
+
ftActive = false;
|
|
106
|
+
localFaceTracker?.stop();
|
|
107
|
+
};
|
|
108
|
+
}, [stream, eventDispatcher]);
|
|
109
|
+
(0, import_react.useEffect)(() => {
|
|
110
|
+
if (!faceTracker) return;
|
|
111
|
+
if (faceTrackerOpts?.detectionBounds) {
|
|
112
|
+
faceTracker.setDetectionBounds(faceTrackerOpts.detectionBounds);
|
|
113
|
+
}
|
|
114
|
+
if (faceTrackerOpts?.projectionBounds) {
|
|
115
|
+
faceTracker.setProjectionBounds(faceTrackerOpts.projectionBounds);
|
|
116
|
+
}
|
|
117
|
+
}, [faceTracker, faceTrackerOpts]);
|
|
118
|
+
(0, import_react.useEffect)(() => {
|
|
119
|
+
if (eventDispatcher && eventDispatcherOpts) {
|
|
120
|
+
eventDispatcher.setEventConfig(eventDispatcherOpts);
|
|
121
|
+
}
|
|
122
|
+
}, [eventDispatcher, eventDispatcherOpts]);
|
|
123
|
+
const contextValue = (0, import_react.useMemo)(
|
|
124
|
+
() => ({
|
|
125
|
+
error,
|
|
126
|
+
eventDispatcher,
|
|
127
|
+
faceTracker,
|
|
128
|
+
loading,
|
|
129
|
+
videoStream: stream
|
|
130
|
+
}),
|
|
131
|
+
[error, eventDispatcher, faceTracker, loading, stream]
|
|
132
|
+
);
|
|
133
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(NHContext.Provider, { value: contextValue, children: [
|
|
134
|
+
children,
|
|
135
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
136
|
+
"video",
|
|
137
|
+
{
|
|
138
|
+
ref: streamOwnerVideoRef,
|
|
139
|
+
muted: true,
|
|
140
|
+
autoPlay: true,
|
|
141
|
+
style: {
|
|
142
|
+
opacity: 0,
|
|
143
|
+
position: "absolute",
|
|
144
|
+
top: 0,
|
|
145
|
+
left: 0,
|
|
146
|
+
zIndex: -999
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
] });
|
|
151
|
+
}
|
|
152
|
+
function useNH() {
|
|
153
|
+
return (0, import_react.useContext)(NHContext);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/hooks.ts
|
|
157
|
+
function useEvents(props) {
|
|
158
|
+
const ref = (0, import_react2.useRef)(null);
|
|
159
|
+
(0, import_react2.useEffect)(() => {
|
|
160
|
+
if (!ref.current) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (props.onNHMouseEnter) {
|
|
164
|
+
ref.current.addEventListener(import_no_hands2.NHEvent.MOUSE_ENTER, props.onNHMouseEnter);
|
|
165
|
+
}
|
|
166
|
+
if (props.onNHMouseLeave) {
|
|
167
|
+
ref.current.addEventListener(import_no_hands2.NHEvent.MOUSE_LEAVE, props.onNHMouseLeave);
|
|
168
|
+
}
|
|
169
|
+
if (props.onNHClickGestureBegin) {
|
|
170
|
+
ref.current.addEventListener(
|
|
171
|
+
import_no_hands2.NHEvent.CLICK_GESTURE_BEGIN,
|
|
172
|
+
props.onNHClickGestureBegin
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
if (props.onNHClickGestureEnd) {
|
|
176
|
+
ref.current.addEventListener(
|
|
177
|
+
import_no_hands2.NHEvent.CLICK_GESTURE_END,
|
|
178
|
+
props.onNHClickGestureEnd
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return () => {
|
|
182
|
+
if (!ref.current) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (props.onNHMouseEnter) {
|
|
186
|
+
ref.current.removeEventListener(
|
|
187
|
+
import_no_hands2.NHEvent.MOUSE_ENTER,
|
|
188
|
+
props.onNHMouseEnter
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (props.onNHMouseLeave) {
|
|
192
|
+
ref.current.removeEventListener(
|
|
193
|
+
import_no_hands2.NHEvent.MOUSE_LEAVE,
|
|
194
|
+
props.onNHMouseLeave
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (props.onNHClickGestureBegin) {
|
|
198
|
+
ref.current.removeEventListener(
|
|
199
|
+
import_no_hands2.NHEvent.CLICK_GESTURE_BEGIN,
|
|
200
|
+
props.onNHClickGestureBegin
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (props.onNHClickGestureEnd) {
|
|
204
|
+
ref.current.removeEventListener(
|
|
205
|
+
import_no_hands2.NHEvent.CLICK_GESTURE_END,
|
|
206
|
+
props.onNHClickGestureEnd
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}, [
|
|
211
|
+
props.onNHClickGestureBegin,
|
|
212
|
+
props.onNHClickGestureEnd,
|
|
213
|
+
props.onNHMouseEnter,
|
|
214
|
+
props.onNHMouseLeave
|
|
215
|
+
]);
|
|
216
|
+
return {
|
|
217
|
+
ref
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function useCamera() {
|
|
221
|
+
const [stream, setStream] = (0, import_react2.useState)(null);
|
|
222
|
+
const [loading, setLoading] = (0, import_react2.useState)(true);
|
|
223
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
224
|
+
(0, import_react2.useEffect)(() => {
|
|
225
|
+
let localStream = null;
|
|
226
|
+
let active = true;
|
|
227
|
+
async function getCamera() {
|
|
228
|
+
if (!navigator.mediaDevices?.getUserMedia) {
|
|
229
|
+
console.warn("device does not support camera");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
const s = await navigator.mediaDevices.getUserMedia({
|
|
234
|
+
video: true
|
|
235
|
+
});
|
|
236
|
+
if (!active) {
|
|
237
|
+
s.getTracks().forEach((t) => t.stop());
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
localStream = s;
|
|
241
|
+
setStream(s);
|
|
242
|
+
setLoading(false);
|
|
243
|
+
} catch (error2) {
|
|
244
|
+
console.error("could not initiate camera", error2);
|
|
245
|
+
setLoading(false);
|
|
246
|
+
setError(error2);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
getCamera();
|
|
250
|
+
return () => {
|
|
251
|
+
active = false;
|
|
252
|
+
localStream?.getTracks().forEach((t) => t.stop());
|
|
253
|
+
};
|
|
254
|
+
}, []);
|
|
255
|
+
return {
|
|
256
|
+
stream,
|
|
257
|
+
loading,
|
|
258
|
+
error
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function useNHPoint() {
|
|
262
|
+
const [point, setPoint] = (0, import_react2.useState)(null);
|
|
263
|
+
const { faceTracker } = useNH();
|
|
264
|
+
(0, import_react2.useEffect)(() => {
|
|
265
|
+
if (!faceTracker) return;
|
|
266
|
+
const subscriptionId = faceTracker.subscribe(setPoint);
|
|
267
|
+
return () => {
|
|
268
|
+
faceTracker.unsubscribe(subscriptionId);
|
|
269
|
+
};
|
|
270
|
+
}, [faceTracker]);
|
|
271
|
+
return point;
|
|
272
|
+
}
|
|
273
|
+
function useNHEventNotification({
|
|
274
|
+
onNHClickGestureBegin,
|
|
275
|
+
onNHClickGestureEnd,
|
|
276
|
+
onNHMouseEnter,
|
|
277
|
+
onNHMouseLeave
|
|
278
|
+
}) {
|
|
279
|
+
const { eventDispatcher } = useNH();
|
|
280
|
+
(0, import_react2.useEffect)(() => {
|
|
281
|
+
const unsubscribeFns = [];
|
|
282
|
+
if (eventDispatcher && onNHMouseEnter) {
|
|
283
|
+
const unsubscribe = eventDispatcher.onEvent(
|
|
284
|
+
import_no_hands2.NHEvent.MOUSE_ENTER,
|
|
285
|
+
onNHMouseEnter
|
|
286
|
+
);
|
|
287
|
+
unsubscribeFns.push(unsubscribe);
|
|
288
|
+
}
|
|
289
|
+
if (eventDispatcher && onNHMouseLeave) {
|
|
290
|
+
const unsubscribe = eventDispatcher.onEvent(
|
|
291
|
+
import_no_hands2.NHEvent.MOUSE_LEAVE,
|
|
292
|
+
onNHMouseLeave
|
|
293
|
+
);
|
|
294
|
+
unsubscribeFns.push(unsubscribe);
|
|
295
|
+
}
|
|
296
|
+
if (eventDispatcher && onNHClickGestureBegin) {
|
|
297
|
+
const unsubscribe = eventDispatcher.onEvent(
|
|
298
|
+
import_no_hands2.NHEvent.CLICK_GESTURE_BEGIN,
|
|
299
|
+
onNHClickGestureBegin
|
|
300
|
+
);
|
|
301
|
+
unsubscribeFns.push(unsubscribe);
|
|
302
|
+
}
|
|
303
|
+
if (eventDispatcher && onNHClickGestureEnd) {
|
|
304
|
+
const unsubscribe = eventDispatcher.onEvent(
|
|
305
|
+
import_no_hands2.NHEvent.CLICK_GESTURE_END,
|
|
306
|
+
onNHClickGestureEnd
|
|
307
|
+
);
|
|
308
|
+
unsubscribeFns.push(unsubscribe);
|
|
309
|
+
}
|
|
310
|
+
return () => {
|
|
311
|
+
unsubscribeFns.forEach((unsubscribe) => unsubscribe?.());
|
|
312
|
+
};
|
|
313
|
+
}, [
|
|
314
|
+
eventDispatcher,
|
|
315
|
+
onNHMouseEnter,
|
|
316
|
+
onNHMouseLeave,
|
|
317
|
+
onNHClickGestureBegin,
|
|
318
|
+
onNHClickGestureEnd
|
|
319
|
+
]);
|
|
320
|
+
}
|
|
321
|
+
function useWindowSize() {
|
|
322
|
+
const computeWindowSize = (window2) => ({
|
|
323
|
+
width: window2.innerWidth,
|
|
324
|
+
height: window2.innerHeight,
|
|
325
|
+
centerX: window2.innerWidth / 2,
|
|
326
|
+
centerY: window2.innerHeight / 2
|
|
327
|
+
});
|
|
328
|
+
const [windowSize, setWindowSize] = (0, import_react2.useState)(computeWindowSize(window));
|
|
329
|
+
const handleWindowResize = (0, import_react2.useCallback)(() => {
|
|
330
|
+
setWindowSize(computeWindowSize(window));
|
|
331
|
+
}, [computeWindowSize]);
|
|
332
|
+
(0, import_react2.useEffect)(() => {
|
|
333
|
+
window.addEventListener("resize", handleWindowResize);
|
|
334
|
+
return () => window.removeEventListener("resize", handleWindowResize);
|
|
335
|
+
}, [handleWindowResize]);
|
|
336
|
+
return windowSize;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/nhcomponent.ts
|
|
340
|
+
var import_react_merge_refs = require("react-merge-refs");
|
|
341
|
+
var htmlElementTags = [
|
|
342
|
+
"a",
|
|
343
|
+
"article",
|
|
344
|
+
"aside",
|
|
345
|
+
"audio",
|
|
346
|
+
"button",
|
|
347
|
+
"canvas",
|
|
348
|
+
"details",
|
|
349
|
+
"dialog",
|
|
350
|
+
"div",
|
|
351
|
+
"figure",
|
|
352
|
+
"footer",
|
|
353
|
+
"form",
|
|
354
|
+
"h1",
|
|
355
|
+
"h2",
|
|
356
|
+
"h3",
|
|
357
|
+
"h4",
|
|
358
|
+
"h5",
|
|
359
|
+
"h6",
|
|
360
|
+
"header",
|
|
361
|
+
"img",
|
|
362
|
+
"input",
|
|
363
|
+
"label",
|
|
364
|
+
"li",
|
|
365
|
+
"main",
|
|
366
|
+
"nav",
|
|
367
|
+
"ol",
|
|
368
|
+
"p",
|
|
369
|
+
"picture",
|
|
370
|
+
"section",
|
|
371
|
+
"select",
|
|
372
|
+
"span",
|
|
373
|
+
"summary",
|
|
374
|
+
"svg",
|
|
375
|
+
"table",
|
|
376
|
+
"td",
|
|
377
|
+
"textarea",
|
|
378
|
+
"th",
|
|
379
|
+
"ul",
|
|
380
|
+
"video"
|
|
381
|
+
];
|
|
382
|
+
function NHComponentFactory(tag) {
|
|
383
|
+
return (0, import_react3.forwardRef)(
|
|
384
|
+
(props, ref) => {
|
|
385
|
+
const {
|
|
386
|
+
onNHMouseEnter,
|
|
387
|
+
onNHMouseLeave,
|
|
388
|
+
onNHClickGestureBegin,
|
|
389
|
+
onNHClickGestureEnd,
|
|
390
|
+
...htmlProps
|
|
391
|
+
} = props;
|
|
392
|
+
const { ref: nhRef } = useEvents({
|
|
393
|
+
onNHMouseEnter,
|
|
394
|
+
onNHMouseLeave,
|
|
395
|
+
onNHClickGestureBegin,
|
|
396
|
+
onNHClickGestureEnd
|
|
397
|
+
});
|
|
398
|
+
return import_react3.default.createElement(tag, {
|
|
399
|
+
...htmlProps,
|
|
400
|
+
ref: (0, import_react_merge_refs.mergeRefs)([ref, nhRef]),
|
|
401
|
+
"data-nh-component": "true"
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
var NH = htmlElementTags.reduce((result, tag) => {
|
|
407
|
+
const NHComponent = NHComponentFactory(tag);
|
|
408
|
+
NHComponent.displayName = `NH.${tag}`;
|
|
409
|
+
result[tag] = NHComponent;
|
|
410
|
+
return result;
|
|
411
|
+
}, {});
|
|
412
|
+
|
|
413
|
+
// src/detection-bounds-display.tsx
|
|
414
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
415
|
+
function DetectionBoundsDisplay({
|
|
416
|
+
detectionBounds,
|
|
417
|
+
style
|
|
418
|
+
}) {
|
|
419
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
420
|
+
"div",
|
|
421
|
+
{
|
|
422
|
+
style: {
|
|
423
|
+
pointerEvents: "none",
|
|
424
|
+
position: "absolute",
|
|
425
|
+
width: detectionBounds.p2.x - detectionBounds.p1.x,
|
|
426
|
+
height: detectionBounds.p2.y - detectionBounds.p1.y,
|
|
427
|
+
opacity: 0.5,
|
|
428
|
+
zIndex: -1,
|
|
429
|
+
top: detectionBounds.p1.y,
|
|
430
|
+
left: detectionBounds.p1.x,
|
|
431
|
+
border: "1px solid black",
|
|
432
|
+
borderRadius: 12,
|
|
433
|
+
...style
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/pointer.tsx
|
|
440
|
+
var import_react4 = require("react");
|
|
441
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
442
|
+
function Pointer({
|
|
443
|
+
children,
|
|
444
|
+
style
|
|
445
|
+
}) {
|
|
446
|
+
const point = useNHPoint();
|
|
447
|
+
const [, setColor] = (0, import_react4.useState)("red");
|
|
448
|
+
const handleNHClickGestureBegin = (0, import_react4.useCallback)(() => {
|
|
449
|
+
setColor((prevColor) => prevColor === "red" ? "blue" : "red");
|
|
450
|
+
}, []);
|
|
451
|
+
const handeNHClickGestureEnd = (0, import_react4.useCallback)(() => {
|
|
452
|
+
setColor("green");
|
|
453
|
+
}, []);
|
|
454
|
+
useNHEventNotification({
|
|
455
|
+
onNHClickGestureEnd: handeNHClickGestureEnd,
|
|
456
|
+
onNHClickGestureBegin: handleNHClickGestureBegin
|
|
457
|
+
});
|
|
458
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
459
|
+
"div",
|
|
460
|
+
{
|
|
461
|
+
style: {
|
|
462
|
+
pointerEvents: "none",
|
|
463
|
+
position: "absolute",
|
|
464
|
+
...point === null && { visibility: "hidden" },
|
|
465
|
+
...point !== null && { left: point.x, top: point.y },
|
|
466
|
+
...style
|
|
467
|
+
// backgroundColor: color,
|
|
468
|
+
},
|
|
469
|
+
children: children ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(DefaultPointerIndicator, {})
|
|
470
|
+
}
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
function DefaultPointerIndicator() {
|
|
474
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
475
|
+
"div",
|
|
476
|
+
{
|
|
477
|
+
style: {
|
|
478
|
+
height: 24,
|
|
479
|
+
width: 24,
|
|
480
|
+
borderRadius: "50%",
|
|
481
|
+
transform: "translate(-50%, -50%)",
|
|
482
|
+
boxShadow: "rgba(0, 0, 0, 0.24) 0px 3px 8px",
|
|
483
|
+
background: "black"
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/index.ts
|
|
490
|
+
var import_no_hands3 = require("@deibid/no-hands");
|
|
491
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
492
|
+
0 && (module.exports = {
|
|
493
|
+
DetectionBoundsDisplay,
|
|
494
|
+
NH,
|
|
495
|
+
NHEvent,
|
|
496
|
+
NHProvider,
|
|
497
|
+
Pointer,
|
|
498
|
+
useCamera,
|
|
499
|
+
useEvents,
|
|
500
|
+
useNH,
|
|
501
|
+
useNHPoint,
|
|
502
|
+
useWindowSize
|
|
503
|
+
});
|