intent-click 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +126 -0
- package/dist/angular.d.ts +18 -0
- package/dist/angular.d.ts.map +1 -0
- package/dist/angular.js +29 -0
- package/dist/angular.js.map +1 -0
- package/dist/core/engine.d.ts +3 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +241 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/env.d.ts +9 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/env.js +38 -0
- package/dist/core/env.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/scheduler.d.ts +6 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +31 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/types.d.ts +30 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +5 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +25 -0
- package/dist/react.js.map +1 -0
- package/dist/solid.d.ts +8 -0
- package/dist/solid.d.ts.map +1 -0
- package/dist/solid.js +33 -0
- package/dist/solid.js.map +1 -0
- package/dist/svelte.d.ts +14 -0
- package/dist/svelte.d.ts.map +1 -0
- package/dist/svelte.js +28 -0
- package/dist/svelte.js.map +1 -0
- package/dist/vanilla.d.ts +6 -0
- package/dist/vanilla.d.ts.map +1 -0
- package/dist/vanilla.js +8 -0
- package/dist/vanilla.js.map +1 -0
- package/dist/vue.d.ts +8 -0
- package/dist/vue.d.ts.map +1 -0
- package/dist/vue.js +32 -0
- package/dist/vue.js.map +1 -0
- package/package.json +164 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 AntonVoronezh <anton.voronezh.1990@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# intent-click
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/intent-click)
|
|
4
|
+
[](https://www.npmjs.com/package/intent-click)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Detect intentional clicks vs accidental taps on touchscreens. Adaptive threshold, ghost click suppression, scroll intent detection.
|
|
8
|
+
|
|
9
|
+
## Why?
|
|
10
|
+
|
|
11
|
+
On touchscreens, accidental taps are common:
|
|
12
|
+
- User scrolls, finger lands on a button → **click fires**
|
|
13
|
+
- Drag gesture slightly moved → **browser still fires click**
|
|
14
|
+
- iOS Safari ghost clicks 300ms after touchend → **hits element underneath**
|
|
15
|
+
|
|
16
|
+
Standard solutions don't work:
|
|
17
|
+
- `e.preventDefault()` — breaks scrolling
|
|
18
|
+
- `touch-action: manipulation` — doesn't solve drag-vs-click
|
|
19
|
+
- `fastclick` — deprecated, only solved 300ms delay
|
|
20
|
+
|
|
21
|
+
`intent-click` distinguishes **intentional** clicks from:
|
|
22
|
+
- Drag gestures (movement > threshold)
|
|
23
|
+
- Scroll intents (vertical movement > 10px)
|
|
24
|
+
- Ghost clicks (same coords within 400ms)
|
|
25
|
+
- Long presses (>500ms without movement)
|
|
26
|
+
- Concurrent pointers (pinch-zoom started)
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install intent-click
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { useIntentClick } from 'intent-click/react';
|
|
38
|
+
|
|
39
|
+
// React
|
|
40
|
+
const ref = useIntentClick<HTMLButtonElement>((event) => {
|
|
41
|
+
// Guaranteed: intentional click
|
|
42
|
+
deleteAccount();
|
|
43
|
+
}, { threshold: 'auto' });
|
|
44
|
+
|
|
45
|
+
<button ref={ref}>Delete Account</button>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// Vanilla JS
|
|
50
|
+
import { onIntentClick } from 'intent-click/vanilla';
|
|
51
|
+
|
|
52
|
+
const off = onIntentClick(buttonEl, () => {
|
|
53
|
+
deleteAccount();
|
|
54
|
+
}, { threshold: 'auto' });
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- **~800 bytes gzip**
|
|
60
|
+
- **Zero runtime dependencies**
|
|
61
|
+
- **Adaptive threshold**: 4px × devicePixelRatio on desktop, 6px × devicePixelRatio on mobile
|
|
62
|
+
- **Ghost click suppression**: 400ms dead zone on same coords ±5px
|
|
63
|
+
- **Scroll intent detection**: vertical movement > 10px → scroll, not click
|
|
64
|
+
- **Long press discrimination**: >500ms without movement → `onLongPress`
|
|
65
|
+
- **Concurrent pointer rejection**: multi-touch → cancel
|
|
66
|
+
- **SSR-safe**: returns null on server, hydrates in browser
|
|
67
|
+
- **TypeScript-first**: full type inference
|
|
68
|
+
- **Framework adapters**: React, Vue, Svelte, Solid, Angular, vanilla JS
|
|
69
|
+
|
|
70
|
+
## API
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
interface IntentClickOptions {
|
|
74
|
+
// Movement threshold in CSS pixels. 'auto' = adaptive
|
|
75
|
+
threshold?: number | 'auto';
|
|
76
|
+
|
|
77
|
+
// Duration in ms after which it's considered a long press
|
|
78
|
+
longPressDelay?: number;
|
|
79
|
+
|
|
80
|
+
// Callback when long press is detected
|
|
81
|
+
onLongPress?: (event: PointerEvent) => void;
|
|
82
|
+
|
|
83
|
+
// Callback when intent is cancelled
|
|
84
|
+
onIntentCancel?: (reason: IntentCancelReason) => void;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type IntentCancelReason =
|
|
88
|
+
| 'drag' // Movement exceeded threshold
|
|
89
|
+
| 'scroll' // Vertical movement > 10px
|
|
90
|
+
| 'concurrent-pointer' // Second pointer appeared
|
|
91
|
+
| 'pointercancel' // OS intercepted gesture
|
|
92
|
+
| 'timeout'; // (reserved)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## How It Works
|
|
96
|
+
|
|
97
|
+
1. **PointerEvent pipeline**: single entry point for mouse/touch/pen
|
|
98
|
+
2. **FSM**: IDLE → PENDING → MOVING → DECIDED
|
|
99
|
+
3. **Adaptive threshold**: `baseThreshold × devicePixelRatio`
|
|
100
|
+
4. **Ghost click suppression**: track last coords, block ±5px for 400ms
|
|
101
|
+
5. **Scroll intent**: vertical movement > 10px → cancel
|
|
102
|
+
6. **Long press**: >500ms without movement → `onLongPress`
|
|
103
|
+
|
|
104
|
+
## Framework Adapters
|
|
105
|
+
|
|
106
|
+
- [React](https://antonvoronezh.github.io/intent-click/react.html)
|
|
107
|
+
- [Vue](https://antonvoronezh.github.io/intent-click/vue.html)
|
|
108
|
+
- [Svelte](https://antonvoronezh.github.io/intent-click/svelte.html)
|
|
109
|
+
- [Solid](https://antonvoronezh.github.io/intent-click/solid.html)
|
|
110
|
+
- [Angular](https://antonvoronezh.github.io/intent-click/angular.html)
|
|
111
|
+
|
|
112
|
+
## Docs
|
|
113
|
+
|
|
114
|
+
- [npm Package](https://antonvoronezh.github.io/intent-click/npm.html)
|
|
115
|
+
- [FAQ](https://antonvoronezh.github.io/intent-click/faq.html)
|
|
116
|
+
- [Common Pitfalls](https://antonvoronezh.github.io/intent-click/common-pitfalls.html)
|
|
117
|
+
- [Smoke Test](https://antonvoronezh.github.io/intent-click/smoke-test.html)
|
|
118
|
+
- [SemVer Policy](./SEMVER_POLICY.md)
|
|
119
|
+
|
|
120
|
+
## Support
|
|
121
|
+
|
|
122
|
+
See [Funding](https://antonvoronezh.github.io/intent-click/funding.html).
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type OnInit } from '@angular/core';
|
|
2
|
+
import type { IntentClickCallback } from './core/types.js';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class IntentClickDirective implements OnInit {
|
|
5
|
+
private readonly destroyRef;
|
|
6
|
+
private readonly elementRef;
|
|
7
|
+
readonly intentClickCallback: import("@angular/core").InputSignal<IntentClickCallback>;
|
|
8
|
+
readonly intentClickOptions: import("@angular/core").InputSignal<Readonly<{
|
|
9
|
+
threshold?: number | "auto";
|
|
10
|
+
longPressDelay?: number;
|
|
11
|
+
onLongPress?: import("./core/types.js").IntentClickLongPressCallback;
|
|
12
|
+
onIntentCancel?: (reason: import("./core/types.js").IntentCancelReason) => void;
|
|
13
|
+
}> | undefined>;
|
|
14
|
+
ngOnInit(): void;
|
|
15
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<IntentClickDirective, never>;
|
|
16
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<IntentClickDirective, "[intentClickCallback]", ["intentClick"], { "intentClickCallback": { "alias": "intentClickCallback"; "required": true; "isSignal": true; }; "intentClickOptions": { "alias": "intentClickOptions"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=angular.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angular.d.ts","sourceRoot":"","sources":["../src/angular.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,KAAK,EAAsB,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;;AAG/E,qBAKa,oBAAqB,YAAW,MAAM;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+C;IAE1E,QAAQ,CAAC,mBAAmB,2DAAyC;IACrE,QAAQ,CAAC,kBAAkB;;;;;oBAA2C;IAEtE,QAAQ,IAAI,IAAI;yCAPP,oBAAoB;2CAApB,oBAAoB;CAuBhC"}
|
package/dist/angular.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Directive, DestroyRef, ElementRef, inject, input } from '@angular/core';
|
|
2
|
+
import { createIntentClickStore } from './core/engine.js';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export class IntentClickDirective {
|
|
5
|
+
destroyRef = inject(DestroyRef);
|
|
6
|
+
elementRef = inject(ElementRef);
|
|
7
|
+
intentClickCallback = input.required();
|
|
8
|
+
intentClickOptions = input();
|
|
9
|
+
ngOnInit() {
|
|
10
|
+
const element = this.elementRef.nativeElement;
|
|
11
|
+
const store = createIntentClickStore(element, this.intentClickCallback(), this.intentClickOptions());
|
|
12
|
+
const unsub = store.subscribe(() => { });
|
|
13
|
+
this.destroyRef.onDestroy(() => {
|
|
14
|
+
unsub();
|
|
15
|
+
store.destroy();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: IntentClickDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
19
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "17.3.12", type: IntentClickDirective, isStandalone: true, selector: "[intentClickCallback]", inputs: { intentClickCallback: { classPropertyName: "intentClickCallback", publicName: "intentClickCallback", isSignal: true, isRequired: true, transformFunction: null }, intentClickOptions: { classPropertyName: "intentClickOptions", publicName: "intentClickOptions", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["intentClick"], ngImport: i0 });
|
|
20
|
+
}
|
|
21
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: IntentClickDirective, decorators: [{
|
|
22
|
+
type: Directive,
|
|
23
|
+
args: [{
|
|
24
|
+
selector: '[intentClickCallback]',
|
|
25
|
+
standalone: true,
|
|
26
|
+
exportAs: 'intentClick',
|
|
27
|
+
}]
|
|
28
|
+
}] });
|
|
29
|
+
//# sourceMappingURL=angular.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"angular.js","sourceRoot":"","sources":["../src/angular.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAe,MAAM,eAAe,CAAC;AAE9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;;AAO1D,MAAM,OAAO,oBAAoB;IACZ,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAChC,UAAU,GAAG,MAAM,CAA0B,UAAU,CAAC,CAAC;IAEjE,mBAAmB,GAAG,KAAK,CAAC,QAAQ,EAAuB,CAAC;IAC5D,kBAAkB,GAAG,KAAK,EAAkC,CAAC;IAEtE,QAAQ;QACJ,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAE9C,MAAM,KAAK,GAAG,sBAAsB,CAChC,OAAO,EACP,IAAI,CAAC,mBAAmB,EAAE,EAC1B,IAAI,CAAC,kBAAkB,EAAE,CAC5B,CAAC;QAEF,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAExC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,EAAE;YAC3B,KAAK,EAAE,CAAC;YACR,KAAK,CAAC,OAAO,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACP,CAAC;wGAtBQ,oBAAoB;4FAApB,oBAAoB;;4FAApB,oBAAoB;kBALhC,SAAS;mBAAC;oBACP,QAAQ,EAAE,uBAAuB;oBACjC,UAAU,EAAE,IAAI;oBAChB,QAAQ,EAAE,aAAa;iBAC1B"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { IntentClickOptions, IntentClickStore } from './types.js';
|
|
2
|
+
export declare const createIntentClickStore: (element: HTMLElement | null | undefined, callback: (event: PointerEvent) => void, options?: IntentClickOptions) => IntentClickStore;
|
|
3
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAuB,gBAAgB,EAAsB,MAAM,YAAY,CAAC;AA4DhH,eAAO,MAAM,sBAAsB,YACtB,WAAW,GAAG,IAAI,GAAG,SAAS,YAC7B,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,YAC7B,kBAAkB,KAC7B,gBAoOF,CAAC"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { canUseDOM, getDevicePixelRatio, getBaseThreshold, now } from './env.js';
|
|
2
|
+
import { createScheduler } from './scheduler.js';
|
|
3
|
+
const GHOST_CLICK_BLOCK_DURATION = 400;
|
|
4
|
+
const GHOST_CLICK_COORD_THRESHOLD = 5;
|
|
5
|
+
const MIN_CLICK_DURATION = 50;
|
|
6
|
+
const DEFAULT_LONG_PRESS_DELAY = 500;
|
|
7
|
+
const SCROLL_INTENT_THRESHOLD = 10;
|
|
8
|
+
const calculateAdaptiveThreshold = (options) => {
|
|
9
|
+
if (typeof options.threshold === 'number')
|
|
10
|
+
return options.threshold;
|
|
11
|
+
const baseThreshold = getBaseThreshold();
|
|
12
|
+
const dpr = getDevicePixelRatio();
|
|
13
|
+
return baseThreshold * dpr;
|
|
14
|
+
};
|
|
15
|
+
const isGhostClick = (state, x, y) => {
|
|
16
|
+
if (state.lastClickTime === null || state.lastClickX === null || state.lastClickY === null) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const timeSinceLastClick = now() - state.lastClickTime;
|
|
20
|
+
if (timeSinceLastClick > GHOST_CLICK_BLOCK_DURATION)
|
|
21
|
+
return false;
|
|
22
|
+
const dx = Math.abs(x - state.lastClickX);
|
|
23
|
+
const dy = Math.abs(y - state.lastClickY);
|
|
24
|
+
return dx <= GHOST_CLICK_COORD_THRESHOLD && dy <= GHOST_CLICK_COORD_THRESHOLD;
|
|
25
|
+
};
|
|
26
|
+
const detectScrollIntent = (movementX, movementY) => {
|
|
27
|
+
const absX = Math.abs(movementX);
|
|
28
|
+
const absY = Math.abs(movementY);
|
|
29
|
+
if (absY > SCROLL_INTENT_THRESHOLD && absX < absY * 0.5)
|
|
30
|
+
return true;
|
|
31
|
+
if (absX > SCROLL_INTENT_THRESHOLD && absY < absX * 0.5)
|
|
32
|
+
return true;
|
|
33
|
+
return false;
|
|
34
|
+
};
|
|
35
|
+
export const createIntentClickStore = (element, callback, options) => {
|
|
36
|
+
if (!canUseDOM() || !element) {
|
|
37
|
+
return {
|
|
38
|
+
getSnapshot: () => null,
|
|
39
|
+
getServerSnapshot: () => null,
|
|
40
|
+
subscribe: () => () => { },
|
|
41
|
+
destroy: () => { },
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const opts = {
|
|
45
|
+
threshold: 'auto',
|
|
46
|
+
longPressDelay: DEFAULT_LONG_PRESS_DELAY,
|
|
47
|
+
...options,
|
|
48
|
+
};
|
|
49
|
+
const adaptiveThreshold = calculateAdaptiveThreshold(opts);
|
|
50
|
+
let state = {
|
|
51
|
+
status: 'IDLE',
|
|
52
|
+
pointerId: null,
|
|
53
|
+
startX: 0,
|
|
54
|
+
startY: 0,
|
|
55
|
+
startTime: 0,
|
|
56
|
+
currentX: 0,
|
|
57
|
+
currentY: 0,
|
|
58
|
+
movementX: 0,
|
|
59
|
+
movementY: 0,
|
|
60
|
+
maxMovement: 0,
|
|
61
|
+
devicePixelRatio: getDevicePixelRatio(),
|
|
62
|
+
lastClickX: null,
|
|
63
|
+
lastClickY: null,
|
|
64
|
+
lastClickTime: null,
|
|
65
|
+
rafId: null,
|
|
66
|
+
longPressTimer: null,
|
|
67
|
+
ghostClickBlockTimer: null,
|
|
68
|
+
};
|
|
69
|
+
const scheduler = createScheduler();
|
|
70
|
+
const listeners = new Set();
|
|
71
|
+
let snapshot = null;
|
|
72
|
+
const updateSnapshot = (isIntent, reason) => {
|
|
73
|
+
snapshot = {
|
|
74
|
+
isIntent,
|
|
75
|
+
pointerId: state.pointerId ?? 0,
|
|
76
|
+
startX: state.startX,
|
|
77
|
+
startY: state.startY,
|
|
78
|
+
endX: state.currentX,
|
|
79
|
+
endY: state.currentY,
|
|
80
|
+
duration: now() - state.startTime,
|
|
81
|
+
movementX: state.movementX,
|
|
82
|
+
movementY: state.movementY,
|
|
83
|
+
devicePixelRatio: state.devicePixelRatio,
|
|
84
|
+
reason,
|
|
85
|
+
};
|
|
86
|
+
listeners.forEach((l) => l());
|
|
87
|
+
};
|
|
88
|
+
const resetState = () => {
|
|
89
|
+
if (state.longPressTimer !== null) {
|
|
90
|
+
clearTimeout(state.longPressTimer);
|
|
91
|
+
}
|
|
92
|
+
scheduler.cancelAll();
|
|
93
|
+
state = {
|
|
94
|
+
...state,
|
|
95
|
+
status: 'IDLE',
|
|
96
|
+
pointerId: null,
|
|
97
|
+
startX: 0,
|
|
98
|
+
startY: 0,
|
|
99
|
+
startTime: 0,
|
|
100
|
+
currentX: 0,
|
|
101
|
+
currentY: 0,
|
|
102
|
+
movementX: 0,
|
|
103
|
+
movementY: 0,
|
|
104
|
+
maxMovement: 0,
|
|
105
|
+
rafId: null,
|
|
106
|
+
longPressTimer: null,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
const handlePointerDown = (event) => {
|
|
110
|
+
if (state.status !== 'IDLE') {
|
|
111
|
+
state.status = 'IDLE';
|
|
112
|
+
if (state.longPressTimer !== null)
|
|
113
|
+
clearTimeout(state.longPressTimer);
|
|
114
|
+
}
|
|
115
|
+
state.status = 'PENDING';
|
|
116
|
+
state.pointerId = event.pointerId;
|
|
117
|
+
state.startX = event.clientX;
|
|
118
|
+
state.startY = event.clientY;
|
|
119
|
+
state.startTime = now();
|
|
120
|
+
state.currentX = event.clientX;
|
|
121
|
+
state.currentY = event.clientY;
|
|
122
|
+
state.movementX = 0;
|
|
123
|
+
state.movementY = 0;
|
|
124
|
+
state.maxMovement = 0;
|
|
125
|
+
state.devicePixelRatio = getDevicePixelRatio();
|
|
126
|
+
if (opts.onLongPress) {
|
|
127
|
+
state.longPressTimer = setTimeout(() => {
|
|
128
|
+
if (state.status === 'PENDING' && state.maxMovement < adaptiveThreshold) {
|
|
129
|
+
state.status = 'DECIDED';
|
|
130
|
+
opts.onLongPress(event);
|
|
131
|
+
resetState();
|
|
132
|
+
}
|
|
133
|
+
}, opts.longPressDelay ?? DEFAULT_LONG_PRESS_DELAY);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const handlePointerMove = (event) => {
|
|
137
|
+
if (state.status !== 'PENDING' && state.status !== 'MOVING')
|
|
138
|
+
return;
|
|
139
|
+
if (state.pointerId !== event.pointerId)
|
|
140
|
+
return;
|
|
141
|
+
state.currentX = event.clientX;
|
|
142
|
+
state.currentY = event.clientY;
|
|
143
|
+
state.movementX = event.clientX - state.startX;
|
|
144
|
+
state.movementY = event.clientY - state.startY;
|
|
145
|
+
state.maxMovement = Math.max(Math.abs(state.movementX), Math.abs(state.movementY));
|
|
146
|
+
if (state.maxMovement > adaptiveThreshold) {
|
|
147
|
+
state.status = 'MOVING';
|
|
148
|
+
if (state.longPressTimer !== null) {
|
|
149
|
+
clearTimeout(state.longPressTimer);
|
|
150
|
+
state.longPressTimer = null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const handlePointerUp = (event) => {
|
|
155
|
+
if (state.status !== 'PENDING' && state.status !== 'MOVING')
|
|
156
|
+
return;
|
|
157
|
+
if (state.pointerId !== event.pointerId)
|
|
158
|
+
return;
|
|
159
|
+
const duration = now() - state.startTime;
|
|
160
|
+
if (duration < MIN_CLICK_DURATION) {
|
|
161
|
+
resetState();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (state.maxMovement > adaptiveThreshold) {
|
|
165
|
+
opts.onIntentCancel?.('drag');
|
|
166
|
+
resetState();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (detectScrollIntent(state.movementX, state.movementY)) {
|
|
170
|
+
opts.onIntentCancel?.('scroll');
|
|
171
|
+
resetState();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (isGhostClick(state, event.clientX, event.clientY)) {
|
|
175
|
+
resetState();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
state.status = 'DECIDED';
|
|
179
|
+
state.lastClickX = event.clientX;
|
|
180
|
+
state.lastClickY = event.clientY;
|
|
181
|
+
state.lastClickTime = now();
|
|
182
|
+
updateSnapshot(true, null);
|
|
183
|
+
callback(event);
|
|
184
|
+
state.ghostClickBlockTimer = setTimeout(() => {
|
|
185
|
+
state.lastClickX = null;
|
|
186
|
+
state.lastClickY = null;
|
|
187
|
+
state.lastClickTime = null;
|
|
188
|
+
}, GHOST_CLICK_BLOCK_DURATION);
|
|
189
|
+
resetState();
|
|
190
|
+
};
|
|
191
|
+
const handlePointerCancel = () => {
|
|
192
|
+
if (state.status === 'IDLE')
|
|
193
|
+
return;
|
|
194
|
+
opts.onIntentCancel?.('pointercancel');
|
|
195
|
+
resetState();
|
|
196
|
+
};
|
|
197
|
+
const handleConcurrentPointer = () => {
|
|
198
|
+
if (state.status === 'IDLE')
|
|
199
|
+
return;
|
|
200
|
+
opts.onIntentCancel?.('concurrent-pointer');
|
|
201
|
+
resetState();
|
|
202
|
+
};
|
|
203
|
+
element.addEventListener('pointerdown', handlePointerDown, { passive: true });
|
|
204
|
+
element.addEventListener('pointermove', handlePointerMove, { passive: true });
|
|
205
|
+
element.addEventListener('pointerup', handlePointerUp, { passive: true });
|
|
206
|
+
element.addEventListener('pointercancel', handlePointerCancel, { passive: true });
|
|
207
|
+
element.addEventListener('pointerleave', handlePointerCancel, { passive: true });
|
|
208
|
+
const globalConcurrentHandler = (event) => {
|
|
209
|
+
if (state.status !== 'IDLE' && event.pointerId !== state.pointerId) {
|
|
210
|
+
handleConcurrentPointer();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
document.addEventListener('pointerdown', globalConcurrentHandler, { passive: true });
|
|
214
|
+
const destroy = () => {
|
|
215
|
+
element.removeEventListener('pointerdown', handlePointerDown);
|
|
216
|
+
element.removeEventListener('pointermove', handlePointerMove);
|
|
217
|
+
element.removeEventListener('pointerup', handlePointerUp);
|
|
218
|
+
element.removeEventListener('pointercancel', handlePointerCancel);
|
|
219
|
+
element.removeEventListener('pointerleave', handlePointerCancel);
|
|
220
|
+
document.removeEventListener('pointerdown', globalConcurrentHandler);
|
|
221
|
+
if (state.longPressTimer !== null)
|
|
222
|
+
clearTimeout(state.longPressTimer);
|
|
223
|
+
if (state.ghostClickBlockTimer !== null)
|
|
224
|
+
clearTimeout(state.ghostClickBlockTimer);
|
|
225
|
+
scheduler.cancelAll();
|
|
226
|
+
listeners.clear();
|
|
227
|
+
resetState();
|
|
228
|
+
};
|
|
229
|
+
return {
|
|
230
|
+
getSnapshot: () => snapshot,
|
|
231
|
+
getServerSnapshot: () => null,
|
|
232
|
+
subscribe: (onStoreChange) => {
|
|
233
|
+
listeners.add(onStoreChange);
|
|
234
|
+
return () => {
|
|
235
|
+
listeners.delete(onStoreChange);
|
|
236
|
+
};
|
|
237
|
+
},
|
|
238
|
+
destroy,
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const canUseDOM: () => boolean;
|
|
2
|
+
export declare const now: () => number;
|
|
3
|
+
export declare const raf: (cb: FrameRequestCallback) => number;
|
|
4
|
+
export declare const caf: (id: number) => void;
|
|
5
|
+
export declare const queueMicrotaskSafe: (cb: () => void) => void;
|
|
6
|
+
export declare const getDevicePixelRatio: () => number;
|
|
7
|
+
export declare const isTouchDevice: () => boolean;
|
|
8
|
+
export declare const getBaseThreshold: () => number;
|
|
9
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/core/env.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,QAAO,OAGO,CAAC;AAErC,eAAO,MAAM,GAAG,QAAO,MAKtB,CAAC;AAEF,eAAO,MAAM,GAAG,OAAQ,oBAAoB,KAAG,MAG9C,CAAC;AAEF,eAAO,MAAM,GAAG,OAAQ,MAAM,KAAG,IAGhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,OAAQ,MAAM,IAAI,KAAG,IAGnD,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAO,MAGtC,CAAC;AAEF,eAAO,MAAM,aAAa,QAAO,OAGhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAO,MAEnC,CAAC"}
|
package/dist/core/env.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export const canUseDOM = () => typeof window !== 'undefined' &&
|
|
2
|
+
typeof document !== 'undefined' &&
|
|
3
|
+
typeof navigator !== 'undefined';
|
|
4
|
+
export const now = () => {
|
|
5
|
+
const p = (typeof performance !== 'undefined' ? performance : undefined);
|
|
6
|
+
return typeof p?.now === 'function' ? p.now() : Date.now();
|
|
7
|
+
};
|
|
8
|
+
export const raf = (cb) => {
|
|
9
|
+
if (typeof requestAnimationFrame === 'function')
|
|
10
|
+
return requestAnimationFrame(cb);
|
|
11
|
+
return setTimeout(() => cb(now()), 16);
|
|
12
|
+
};
|
|
13
|
+
export const caf = (id) => {
|
|
14
|
+
if (typeof cancelAnimationFrame === 'function')
|
|
15
|
+
cancelAnimationFrame(id);
|
|
16
|
+
else
|
|
17
|
+
clearTimeout(id);
|
|
18
|
+
};
|
|
19
|
+
export const queueMicrotaskSafe = (cb) => {
|
|
20
|
+
if (typeof queueMicrotask === 'function')
|
|
21
|
+
queueMicrotask(cb);
|
|
22
|
+
else
|
|
23
|
+
Promise.resolve().then(cb).catch(() => void 0);
|
|
24
|
+
};
|
|
25
|
+
export const getDevicePixelRatio = () => {
|
|
26
|
+
if (typeof window === 'undefined')
|
|
27
|
+
return 1;
|
|
28
|
+
return window.devicePixelRatio ?? 1;
|
|
29
|
+
};
|
|
30
|
+
export const isTouchDevice = () => {
|
|
31
|
+
if (typeof window === 'undefined')
|
|
32
|
+
return false;
|
|
33
|
+
return window.matchMedia('(hover: none)').matches;
|
|
34
|
+
};
|
|
35
|
+
export const getBaseThreshold = () => {
|
|
36
|
+
return isTouchDevice() ? 6 : 4;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/core/env.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,GAAY,EAAE,CACnC,OAAO,MAAM,KAAK,WAAW;IAC7B,OAAO,QAAQ,KAAK,WAAW;IAC/B,OAAO,SAAS,KAAK,WAAW,CAAC;AAErC,MAAM,CAAC,MAAM,GAAG,GAAG,GAAW,EAAE;IAC5B,MAAM,CAAC,GAAG,CAAC,OAAO,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAExD,CAAC;IAChB,OAAO,OAAO,CAAC,EAAE,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAC/D,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,EAAwB,EAAU,EAAE;IACpD,IAAI,OAAO,qBAAqB,KAAK,UAAU;QAAE,OAAO,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAClF,OAAO,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAuB,CAAC,EAAE,EAAE,CAAsB,CAAC;AACrF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,EAAU,EAAQ,EAAE;IACpC,IAAI,OAAO,oBAAoB,KAAK,UAAU;QAAE,oBAAoB,CAAC,EAAE,CAAC,CAAC;;QACpE,YAAY,CAAC,EAAuB,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAc,EAAQ,EAAE;IACvD,IAAI,OAAO,cAAc,KAAK,UAAU;QAAE,cAAc,CAAC,EAAE,CAAC,CAAC;;QACxD,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAW,EAAE;IAC5C,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;AACxC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,GAAY,EAAE;IACvC,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,KAAK,CAAC;IAChD,OAAO,MAAM,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC;AACtD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAW,EAAE;IACzC,OAAO,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type { IntentClickCallback, IntentClickLongPressCallback, IntentClickOptions, IntentCancelReason, IntentClickSnapshot, IntentClickStore, IntentClickSubscribe, } from './types.js';
|
|
2
|
+
export { createIntentClickStore } from './engine.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACR,mBAAmB,EACnB,4BAA4B,EAC5B,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,GACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;IAC7B,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACxC,SAAS,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC,CAAC;AAEH,eAAO,MAAM,eAAe,QAAO,SA2BlC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { caf, raf } from './env.js';
|
|
2
|
+
export const createScheduler = () => {
|
|
3
|
+
let rafId = null;
|
|
4
|
+
let frameQueued = false;
|
|
5
|
+
let pendingFn = null;
|
|
6
|
+
const execute = () => {
|
|
7
|
+
rafId = null;
|
|
8
|
+
frameQueued = false;
|
|
9
|
+
const fn = pendingFn;
|
|
10
|
+
pendingFn = null;
|
|
11
|
+
if (fn)
|
|
12
|
+
fn();
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
scheduleFrame(fn) {
|
|
16
|
+
pendingFn = fn;
|
|
17
|
+
if (frameQueued)
|
|
18
|
+
return;
|
|
19
|
+
frameQueued = true;
|
|
20
|
+
rafId = raf(execute);
|
|
21
|
+
},
|
|
22
|
+
cancelAll() {
|
|
23
|
+
if (rafId != null)
|
|
24
|
+
caf(rafId);
|
|
25
|
+
rafId = null;
|
|
26
|
+
frameQueued = false;
|
|
27
|
+
pendingFn = null;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAOpC,MAAM,CAAC,MAAM,eAAe,GAAG,GAAc,EAAE;IAC3C,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,SAAS,GAAwB,IAAI,CAAC;IAE1C,MAAM,OAAO,GAAG,GAAG,EAAE;QACjB,KAAK,GAAG,IAAI,CAAC;QACb,WAAW,GAAG,KAAK,CAAC;QACpB,MAAM,EAAE,GAAG,SAAS,CAAC;QACrB,SAAS,GAAG,IAAI,CAAC;QACjB,IAAI,EAAE;YAAE,EAAE,EAAE,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO;QACH,aAAa,CAAC,EAAE;YACZ,SAAS,GAAG,EAAE,CAAC;YACf,IAAI,WAAW;gBAAE,OAAO;YACxB,WAAW,GAAG,IAAI,CAAC;YACnB,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;QACD,SAAS;YACL,IAAI,KAAK,IAAI,IAAI;gBAAE,GAAG,CAAC,KAAK,CAAC,CAAC;YAC9B,KAAK,GAAG,IAAI,CAAC;YACb,WAAW,GAAG,KAAK,CAAC;YACpB,SAAS,GAAG,IAAI,CAAC;QACrB,CAAC;KACJ,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type IntentClickCallback = (event: PointerEvent) => void;
|
|
2
|
+
export type IntentClickLongPressCallback = (event: PointerEvent) => void;
|
|
3
|
+
export type IntentCancelReason = 'drag' | 'scroll' | 'concurrent-pointer' | 'pointercancel' | 'timeout';
|
|
4
|
+
export type IntentClickOptions = Readonly<{
|
|
5
|
+
threshold?: number | 'auto';
|
|
6
|
+
longPressDelay?: number;
|
|
7
|
+
onLongPress?: IntentClickLongPressCallback;
|
|
8
|
+
onIntentCancel?: (reason: IntentCancelReason) => void;
|
|
9
|
+
}>;
|
|
10
|
+
export type IntentClickSnapshot = Readonly<{
|
|
11
|
+
isIntent: boolean;
|
|
12
|
+
pointerId: number;
|
|
13
|
+
startX: number;
|
|
14
|
+
startY: number;
|
|
15
|
+
endX: number;
|
|
16
|
+
endY: number;
|
|
17
|
+
duration: number;
|
|
18
|
+
movementX: number;
|
|
19
|
+
movementY: number;
|
|
20
|
+
devicePixelRatio: number;
|
|
21
|
+
reason: IntentCancelReason | null;
|
|
22
|
+
}>;
|
|
23
|
+
export type IntentClickSubscribe = (onStoreChange: () => void) => () => void;
|
|
24
|
+
export type IntentClickStore = Readonly<{
|
|
25
|
+
getSnapshot: () => IntentClickSnapshot | null;
|
|
26
|
+
getServerSnapshot: () => IntentClickSnapshot | null;
|
|
27
|
+
subscribe: IntentClickSubscribe;
|
|
28
|
+
destroy: () => void;
|
|
29
|
+
}>;
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAChE,MAAM,MAAM,4BAA4B,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAEzE,MAAM,MAAM,kBAAkB,GACxB,MAAM,GACN,QAAQ,GACR,oBAAoB,GACpB,eAAe,GACf,SAAS,CAAC;AAEhB,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,4BAA4B,CAAC;IAC3C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACzD,CAAC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,aAAa,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;AAE7E,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACpC,WAAW,EAAE,MAAM,mBAAmB,GAAG,IAAI,CAAC;IAC9C,iBAAiB,EAAE,MAAM,mBAAmB,GAAG,IAAI,CAAC;IACpD,SAAS,EAAE,oBAAoB,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './core/index.js';
|
|
2
|
+
export * as vanilla from './vanilla.js';
|
|
3
|
+
export type * as react from './react.js';
|
|
4
|
+
export type * as vue from './vue.js';
|
|
5
|
+
export type * as svelte from './svelte.js';
|
|
6
|
+
export type * as solid from './solid.js';
|
|
7
|
+
export type * as angular from './angular.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAExC,YAAY,KAAK,KAAK,MAAM,YAAY,CAAC;AACzC,YAAY,KAAK,GAAG,MAAM,UAAU,CAAC;AACrC,YAAY,KAAK,MAAM,MAAM,aAAa,CAAC;AAC3C,YAAY,KAAK,KAAK,MAAM,YAAY,CAAC;AACzC,YAAY,KAAK,OAAO,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC"}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IntentClickOptions, IntentClickCallback } from './core/types.js';
|
|
2
|
+
type UseIntentClickResult<T extends HTMLElement> = (element: T | null) => void;
|
|
3
|
+
export declare const useIntentClick: <T extends HTMLElement>(callback: IntentClickCallback, options?: IntentClickOptions) => UseIntentClickResult<T>;
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,KAAK,oBAAoB,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;AAE/E,eAAO,MAAM,cAAc,oCACb,mBAAmB,YACnB,kBAAkB,KAC7B,qBAAqB,CAAC,CAyBxB,CAAC"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect, useRef, useCallback, useMemo } from 'react';
|
|
2
|
+
import { createIntentClickStore } from './core/engine.js';
|
|
3
|
+
export const useIntentClick = (callback, options) => {
|
|
4
|
+
const opts = useMemo(() => options, [options]);
|
|
5
|
+
const storeRef = useRef(null);
|
|
6
|
+
const refCallback = useCallback((element) => {
|
|
7
|
+
if (storeRef.current) {
|
|
8
|
+
storeRef.current.destroy();
|
|
9
|
+
storeRef.current = null;
|
|
10
|
+
}
|
|
11
|
+
if (!element)
|
|
12
|
+
return;
|
|
13
|
+
storeRef.current = createIntentClickStore(element, callback, opts);
|
|
14
|
+
}, [callback, opts]);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
return () => {
|
|
17
|
+
if (storeRef.current) {
|
|
18
|
+
storeRef.current.destroy();
|
|
19
|
+
storeRef.current = null;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}, []);
|
|
23
|
+
return refCallback;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,MAAM,CAAC,MAAM,cAAc,GAAG,CAC1B,QAA6B,EAC7B,OAA4B,EACL,EAAE;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,CAAmD,IAAI,CAAC,CAAC;IAEhF,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,OAAiB,EAAE,EAAE;QAClD,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACnB,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3B,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,QAAQ,CAAC,OAAO,GAAG,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACvE,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAErB,SAAS,CAAC,GAAG,EAAE;QACX,OAAO,GAAG,EAAE;YACR,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACnB,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC3B,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;YAC5B,CAAC;QACL,CAAC,CAAC;IACN,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,WAAW,CAAC;AACvB,CAAC,CAAC"}
|
package/dist/solid.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IntentClickOptions, IntentClickCallback } from './core/types.js';
|
|
2
|
+
export type IntentClickRef<T extends HTMLElement> = (element: T) => void;
|
|
3
|
+
export declare const createIntentClick: <T extends HTMLElement>(callback: IntentClickCallback, options?: IntentClickOptions) => IntentClickRef<T>;
|
|
4
|
+
export declare const intentClickDirective: (el: HTMLElement, accessor: () => {
|
|
5
|
+
callback: IntentClickCallback;
|
|
6
|
+
options?: IntentClickOptions;
|
|
7
|
+
}) => void;
|
|
8
|
+
//# sourceMappingURL=solid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solid.d.ts","sourceRoot":"","sources":["../src/solid.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC;AAEzE,eAAO,MAAM,iBAAiB,oCAChB,mBAAmB,YACnB,kBAAkB,KAC7B,eAAe,CAAC,CAkBlB,CAAC;AAEF,eAAO,MAAM,oBAAoB,OACzB,WAAW,YACL,MAAM;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAAE,SAiBlF,CAAC"}
|
package/dist/solid.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { onCleanup } from 'solid-js';
|
|
2
|
+
import { createIntentClickStore } from './core/engine.js';
|
|
3
|
+
export const createIntentClick = (callback, options) => {
|
|
4
|
+
let store = null;
|
|
5
|
+
let unsub = null;
|
|
6
|
+
const cleanup = () => {
|
|
7
|
+
unsub?.();
|
|
8
|
+
store?.destroy();
|
|
9
|
+
unsub = null;
|
|
10
|
+
store = null;
|
|
11
|
+
};
|
|
12
|
+
onCleanup(cleanup);
|
|
13
|
+
return (element) => {
|
|
14
|
+
cleanup();
|
|
15
|
+
store = createIntentClickStore(element, callback, options);
|
|
16
|
+
unsub = store.subscribe(() => { });
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export const intentClickDirective = (el, accessor) => {
|
|
20
|
+
let store = null;
|
|
21
|
+
let unsub = null;
|
|
22
|
+
const cleanup = () => {
|
|
23
|
+
unsub?.();
|
|
24
|
+
store?.destroy();
|
|
25
|
+
unsub = null;
|
|
26
|
+
store = null;
|
|
27
|
+
};
|
|
28
|
+
const cfg = accessor();
|
|
29
|
+
store = createIntentClickStore(el, cfg.callback, cfg.options);
|
|
30
|
+
unsub = store.subscribe(() => { });
|
|
31
|
+
onCleanup(cleanup);
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=solid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solid.js","sourceRoot":"","sources":["../src/solid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC7B,QAA6B,EAC7B,OAA4B,EACX,EAAE;IACnB,IAAI,KAAK,GAAqD,IAAI,CAAC;IACnE,IAAI,KAAK,GAAwB,IAAI,CAAC;IAEtC,MAAM,OAAO,GAAG,GAAS,EAAE;QACvB,KAAK,EAAE,EAAE,CAAC;QACV,KAAK,EAAE,OAAO,EAAE,CAAC;QACjB,KAAK,GAAG,IAAI,CAAC;QACb,KAAK,GAAG,IAAI,CAAC;IACjB,CAAC,CAAC;IAEF,SAAS,CAAC,OAAO,CAAC,CAAC;IAEnB,OAAO,CAAC,OAAU,EAAE,EAAE;QAClB,OAAO,EAAE,CAAC;QACV,KAAK,GAAG,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3D,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC;AACN,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAChC,EAAe,EACf,QAA+E,EACjF,EAAE;IACA,IAAI,KAAK,GAAqD,IAAI,CAAC;IACnE,IAAI,KAAK,GAAwB,IAAI,CAAC;IAEtC,MAAM,OAAO,GAAG,GAAS,EAAE;QACvB,KAAK,EAAE,EAAE,CAAC;QACV,KAAK,EAAE,OAAO,EAAE,CAAC;QACjB,KAAK,GAAG,IAAI,CAAC;QACb,KAAK,GAAG,IAAI,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAC;IACvB,KAAK,GAAG,sBAAsB,CAAC,EAAE,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9D,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAElC,SAAS,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC,CAAC"}
|
package/dist/svelte.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IntentClickOptions, IntentClickCallback } from './core/types.js';
|
|
2
|
+
export type IntentClickActionParams = {
|
|
3
|
+
callback: IntentClickCallback;
|
|
4
|
+
options?: IntentClickOptions;
|
|
5
|
+
};
|
|
6
|
+
export declare const intentClick: (node: HTMLElement, params: IntentClickActionParams) => {
|
|
7
|
+
update(next: IntentClickActionParams): void;
|
|
8
|
+
destroy(): void;
|
|
9
|
+
};
|
|
10
|
+
export declare const intentClickAction: (node: HTMLElement, params: IntentClickActionParams) => {
|
|
11
|
+
update(next: IntentClickActionParams): void;
|
|
12
|
+
destroy(): void;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svelte.d.ts","sourceRoot":"","sources":["../src/svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,MAAM,MAAM,uBAAuB,GAAG;IAClC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAChC,CAAC;AAkCF,eAAO,MAAM,WAAW,SA/Bd,WAAW,UACT,uBAAuB;iBAqBd,uBAAuB;;CASM,CAAC;AACnD,eAAO,MAAM,iBAAiB,SAhCpB,WAAW,UACT,uBAAuB;iBAqBd,uBAAuB;;CAUY,CAAC"}
|
package/dist/svelte.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createIntentClickStore } from './core/engine.js';
|
|
2
|
+
const createIntentClickAction = (node, params) => {
|
|
3
|
+
let store = null;
|
|
4
|
+
let unsub = null;
|
|
5
|
+
const cleanup = () => {
|
|
6
|
+
unsub?.();
|
|
7
|
+
store?.destroy();
|
|
8
|
+
unsub = null;
|
|
9
|
+
store = null;
|
|
10
|
+
};
|
|
11
|
+
const setup = (next) => {
|
|
12
|
+
cleanup();
|
|
13
|
+
store = createIntentClickStore(node, next.callback, next.options);
|
|
14
|
+
unsub = store.subscribe(() => { });
|
|
15
|
+
};
|
|
16
|
+
setup(params);
|
|
17
|
+
return {
|
|
18
|
+
update(next) {
|
|
19
|
+
setup(next);
|
|
20
|
+
},
|
|
21
|
+
destroy() {
|
|
22
|
+
cleanup();
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export const intentClick = createIntentClickAction;
|
|
27
|
+
export const intentClickAction = createIntentClickAction;
|
|
28
|
+
//# sourceMappingURL=svelte.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svelte.js","sourceRoot":"","sources":["../src/svelte.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAO1D,MAAM,uBAAuB,GAAG,CAC5B,IAAiB,EACjB,MAA+B,EACjC,EAAE;IACA,IAAI,KAAK,GAAqD,IAAI,CAAC;IACnE,IAAI,KAAK,GAAwB,IAAI,CAAC;IAEtC,MAAM,OAAO,GAAG,GAAS,EAAE;QACvB,KAAK,EAAE,EAAE,CAAC;QACV,KAAK,EAAE,OAAO,EAAE,CAAC;QACjB,KAAK,GAAG,IAAI,CAAC;QACb,KAAK,GAAG,IAAI,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,IAA6B,EAAQ,EAAE;QAClD,OAAO,EAAE,CAAC;QACV,KAAK,GAAG,sBAAsB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAClE,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,KAAK,CAAC,MAAM,CAAC,CAAC;IAEd,OAAO;QACH,MAAM,CAAC,IAA6B;YAChC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;QACD,OAAO;YACH,OAAO,EAAE,CAAC;QACd,CAAC;KACJ,CAAC;AACN,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AACnD,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IntentClickOptions, IntentClickCallback } from './core/types.js';
|
|
2
|
+
export type IntentClickController = Readonly<{
|
|
3
|
+
destroy: () => void;
|
|
4
|
+
}>;
|
|
5
|
+
export declare const onIntentClick: (element: HTMLElement, callback: IntentClickCallback, options?: IntentClickOptions) => (() => void);
|
|
6
|
+
//# sourceMappingURL=vanilla.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vanilla.d.ts","sourceRoot":"","sources":["../src/vanilla.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB,CAAC,CAAC;AAEH,eAAO,MAAM,aAAa,YACb,WAAW,YACV,mBAAmB,YACnB,kBAAkB,KAC7B,CAAC,MAAM,IAAI,CAMb,CAAC"}
|
package/dist/vanilla.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createIntentClickStore } from './core/engine.js';
|
|
2
|
+
export const onIntentClick = (element, callback, options) => {
|
|
3
|
+
const store = createIntentClickStore(element, callback, options);
|
|
4
|
+
return () => {
|
|
5
|
+
store.destroy();
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=vanilla.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vanilla.js","sourceRoot":"","sources":["../src/vanilla.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAM1D,MAAM,CAAC,MAAM,aAAa,GAAG,CACzB,OAAoB,EACpB,QAA6B,EAC7B,OAA4B,EAChB,EAAE;IACd,MAAM,KAAK,GAAG,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAEjE,OAAO,GAAG,EAAE;QACR,KAAK,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC,CAAC;AACN,CAAC,CAAC"}
|
package/dist/vue.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ShallowRef, type Directive } from 'vue';
|
|
2
|
+
import type { IntentClickOptions, IntentClickCallback } from './core/types.js';
|
|
3
|
+
export declare const useIntentClick: <T extends HTMLElement>(callback: IntentClickCallback, options?: IntentClickOptions) => ShallowRef<T | null>;
|
|
4
|
+
export declare const vIntentClick: Directive<HTMLElement, {
|
|
5
|
+
callback: IntentClickCallback;
|
|
6
|
+
options?: IntentClickOptions;
|
|
7
|
+
}>;
|
|
8
|
+
//# sourceMappingURL=vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vue.d.ts","sourceRoot":"","sources":["../src/vue.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,CAAC;AAC9F,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,eAAO,MAAM,cAAc,oCACb,mBAAmB,YACnB,kBAAkB,KAC7B,WAAW,CAAC,GAAG,IAAI,CAmBrB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,SAAS,CAChC,WAAW,EACX;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAAE,CAYlE,CAAC"}
|
package/dist/vue.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { onBeforeUnmount, onMounted, shallowRef } from 'vue';
|
|
2
|
+
import { createIntentClickStore } from './core/engine.js';
|
|
3
|
+
export const useIntentClick = (callback, options) => {
|
|
4
|
+
const elRef = shallowRef(null);
|
|
5
|
+
let unsub = null;
|
|
6
|
+
let store = null;
|
|
7
|
+
onMounted(() => {
|
|
8
|
+
const el = elRef.value;
|
|
9
|
+
if (!el)
|
|
10
|
+
return;
|
|
11
|
+
store = createIntentClickStore(el, callback, options);
|
|
12
|
+
unsub = store.subscribe(() => { });
|
|
13
|
+
});
|
|
14
|
+
onBeforeUnmount(() => {
|
|
15
|
+
unsub?.();
|
|
16
|
+
store?.destroy();
|
|
17
|
+
});
|
|
18
|
+
return elRef;
|
|
19
|
+
};
|
|
20
|
+
export const vIntentClick = {
|
|
21
|
+
mounted(el, binding) {
|
|
22
|
+
const { callback, options } = binding.value;
|
|
23
|
+
const store = createIntentClickStore(el, callback, options);
|
|
24
|
+
el.__intentClick = { store };
|
|
25
|
+
},
|
|
26
|
+
unmounted(el) {
|
|
27
|
+
const bag = el.__intentClick;
|
|
28
|
+
bag?.store?.destroy();
|
|
29
|
+
delete el.__intentClick;
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=vue.js.map
|
package/dist/vue.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vue.js","sourceRoot":"","sources":["../src/vue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAmC,MAAM,KAAK,CAAC;AAE9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,CAAC,MAAM,cAAc,GAAG,CAC1B,QAA6B,EAC7B,OAA4B,EACR,EAAE;IACtB,MAAM,KAAK,GAAG,UAAU,CAAW,IAAI,CAAyB,CAAC;IACjE,IAAI,KAAK,GAAwB,IAAI,CAAC;IACtC,IAAI,KAAK,GAAqD,IAAI,CAAC;IAEnE,SAAS,CAAC,GAAG,EAAE;QACX,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC;QACvB,IAAI,CAAC,EAAE;YAAE,OAAO;QAEhB,KAAK,GAAG,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtD,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,eAAe,CAAC,GAAG,EAAE;QACjB,KAAK,EAAE,EAAE,CAAC;QACV,KAAK,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAGrB;IACA,OAAO,CAAC,EAAE,EAAE,OAAO;QACf,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5C,MAAM,KAAK,GAAG,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3D,EAAU,CAAC,aAAa,GAAG,EAAE,KAAK,EAAE,CAAC;IAC1C,CAAC;IACD,SAAS,CAAC,EAAE;QACR,MAAM,GAAG,GAAI,EAAU,CAAC,aAAiF,CAAC;QAC1G,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QACtB,OAAQ,EAAU,CAAC,aAAa,CAAC;IACrC,CAAC;CACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "intent-click",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Detect intentional clicks vs accidental taps on touchscreens. Adaptive threshold, ghost click suppression, scroll intent detection.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "AntonVoronezh",
|
|
7
|
+
"email": "anton.voronezh.1990@gmail.com",
|
|
8
|
+
"url": "https://github.com/AntonVoronezh"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/AntonVoronezh/intent-click.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/AntonVoronezh/intent-click/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/AntonVoronezh/intent-click#readme",
|
|
18
|
+
"funding": [
|
|
19
|
+
{
|
|
20
|
+
"type": "boosty",
|
|
21
|
+
"url": "https://boosty.to/antonvoronezh/donate"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "crypto",
|
|
25
|
+
"url": "https://t.me/AntonVoronezhh/4"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "npm run build:ts && npm run build:angular",
|
|
35
|
+
"build:ts": "tsc -p tsconfig.build.json",
|
|
36
|
+
"build:angular": "ngc -p tsconfig.angular.json",
|
|
37
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
38
|
+
"prepack": "npm run build",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"test:watch": "vitest",
|
|
42
|
+
"docs:dev": "vitepress dev docs",
|
|
43
|
+
"docs:build": "vitepress build docs",
|
|
44
|
+
"docs:preview": "vitepress preview docs"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"click",
|
|
48
|
+
"touch",
|
|
49
|
+
"tap",
|
|
50
|
+
"intent",
|
|
51
|
+
"pointer",
|
|
52
|
+
"touchscreen",
|
|
53
|
+
"mobile",
|
|
54
|
+
"ghost-click",
|
|
55
|
+
"scroll-detection",
|
|
56
|
+
"adaptive-threshold",
|
|
57
|
+
"react",
|
|
58
|
+
"vue",
|
|
59
|
+
"svelte",
|
|
60
|
+
"solid",
|
|
61
|
+
"angular"
|
|
62
|
+
],
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=18"
|
|
65
|
+
},
|
|
66
|
+
"license": "MIT",
|
|
67
|
+
"sideEffects": false,
|
|
68
|
+
"type": "module",
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"@angular/core": ">=17.0.0",
|
|
71
|
+
"react": ">=18.0.0",
|
|
72
|
+
"solid-js": ">=1.7.0",
|
|
73
|
+
"svelte": ">=4.0.0",
|
|
74
|
+
"vue": ">=3.3.0"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"react": {
|
|
78
|
+
"optional": true
|
|
79
|
+
},
|
|
80
|
+
"vue": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
83
|
+
"svelte": {
|
|
84
|
+
"optional": true
|
|
85
|
+
},
|
|
86
|
+
"solid-js": {
|
|
87
|
+
"optional": true
|
|
88
|
+
},
|
|
89
|
+
"@angular/core": {
|
|
90
|
+
"optional": true
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"devDependencies": {
|
|
94
|
+
"@angular/compiler": "^17.3.12",
|
|
95
|
+
"@angular/compiler-cli": "^17.3.12",
|
|
96
|
+
"@angular/core": "^17.3.0",
|
|
97
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
98
|
+
"@semantic-release/commit-analyzer": "^11.1.0",
|
|
99
|
+
"@semantic-release/git": "^10.0.1",
|
|
100
|
+
"@semantic-release/github": "^10.3.5",
|
|
101
|
+
"@semantic-release/npm": "^13.1.3",
|
|
102
|
+
"@semantic-release/release-notes-generator": "^12.1.0",
|
|
103
|
+
"@types/node": "^22.0.0",
|
|
104
|
+
"@types/react": "^18.3.0",
|
|
105
|
+
"@types/react-dom": "^18.3.0",
|
|
106
|
+
"happy-dom": "^20.5.0",
|
|
107
|
+
"jsdom": "^28.0.0",
|
|
108
|
+
"react": "^18.3.0",
|
|
109
|
+
"react-dom": "^18.3.0",
|
|
110
|
+
"semantic-release": "^23.1.1",
|
|
111
|
+
"solid-js": "^1.9.0",
|
|
112
|
+
"svelte": "^5.56.4",
|
|
113
|
+
"typescript": "~5.4.5",
|
|
114
|
+
"vitepress": "^1.6.4",
|
|
115
|
+
"vitest": "^4.0.18",
|
|
116
|
+
"vue": "^3.5.0"
|
|
117
|
+
},
|
|
118
|
+
"main": "./dist/index.js",
|
|
119
|
+
"module": "./dist/index.js",
|
|
120
|
+
"types": "./dist/index.d.ts",
|
|
121
|
+
"exports": {
|
|
122
|
+
".": {
|
|
123
|
+
"types": "./dist/index.d.ts",
|
|
124
|
+
"import": "./dist/index.js",
|
|
125
|
+
"default": "./dist/index.js"
|
|
126
|
+
},
|
|
127
|
+
"./core": {
|
|
128
|
+
"types": "./dist/core/index.d.ts",
|
|
129
|
+
"import": "./dist/core/index.js",
|
|
130
|
+
"default": "./dist/core/index.js"
|
|
131
|
+
},
|
|
132
|
+
"./react": {
|
|
133
|
+
"types": "./dist/react.d.ts",
|
|
134
|
+
"import": "./dist/react.js",
|
|
135
|
+
"default": "./dist/react.js"
|
|
136
|
+
},
|
|
137
|
+
"./vue": {
|
|
138
|
+
"types": "./dist/vue.d.ts",
|
|
139
|
+
"import": "./dist/vue.js",
|
|
140
|
+
"default": "./dist/vue.js"
|
|
141
|
+
},
|
|
142
|
+
"./svelte": {
|
|
143
|
+
"types": "./dist/svelte.d.ts",
|
|
144
|
+
"import": "./dist/svelte.js",
|
|
145
|
+
"default": "./dist/svelte.js"
|
|
146
|
+
},
|
|
147
|
+
"./solid": {
|
|
148
|
+
"types": "./dist/solid.d.ts",
|
|
149
|
+
"import": "./dist/solid.js",
|
|
150
|
+
"default": "./dist/solid.js"
|
|
151
|
+
},
|
|
152
|
+
"./angular": {
|
|
153
|
+
"types": "./dist/angular.d.ts",
|
|
154
|
+
"import": "./dist/angular.js",
|
|
155
|
+
"default": "./dist/angular.js"
|
|
156
|
+
},
|
|
157
|
+
"./vanilla": {
|
|
158
|
+
"types": "./dist/vanilla.d.ts",
|
|
159
|
+
"import": "./dist/vanilla.js",
|
|
160
|
+
"default": "./dist/vanilla.js"
|
|
161
|
+
},
|
|
162
|
+
"./package.json": "./package.json"
|
|
163
|
+
}
|
|
164
|
+
}
|