on-events 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -16
- package/dist/on-events.d.ts +81 -36
- package/dist/on-events.min.js +1 -1
- package/dist/on-events.min.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
# on-events
|
|
3
|
+
|
|
4
|
+
[](https://www.npmjs.com/package/on-events)
|
|
5
|
+
[](https://www.npmjs.com/package/on-events)
|
|
6
|
+
[](https://github.com/iWhatty/on-event-js)
|
|
7
|
+
[](https://github.com/iWhatty/on-event-js/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
**A tiny DOM event utility with composable sugar.**
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
# on-events
|
|
2
13
|
|
|
3
14
|
**A tiny DOM event utility with composable sugar.**
|
|
@@ -5,6 +16,29 @@ Write clean event bindings using fluent chains like `On.click(...)`, `On.capture
|
|
|
5
16
|
|
|
6
17
|
---
|
|
7
18
|
|
|
19
|
+
## ⚡ Example Usage
|
|
20
|
+
|
|
21
|
+
Compose `once`, `capture`, `passive`, and delegation without repetitive option objects.
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { On } from 'on-events'
|
|
25
|
+
|
|
26
|
+
function handleLinkClick(e) {
|
|
27
|
+
e.preventDefault()
|
|
28
|
+
console.log('First captured delegated click:', this.href)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
On.first.delegate.capture.click(document, 'a.nav-link', handleLinkClick)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
* Delegated
|
|
35
|
+
* Capture phase
|
|
36
|
+
* Fires once
|
|
37
|
+
* Clean `this` binding
|
|
38
|
+
* Returns `stop()` if you need manual control
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
8
42
|
## Features
|
|
9
43
|
|
|
10
44
|
* `on(el, 'click', fn)` — classic binding
|
|
@@ -13,10 +47,12 @@ Write clean event bindings using fluent chains like `On.click(...)`, `On.capture
|
|
|
13
47
|
* `On.capture.passive.scroll(el, fn)` — fully composable modifiers
|
|
14
48
|
* `On.delegate.click(el, selector, fn)` — delegated events
|
|
15
49
|
* `On.hover(el, enter, leave)` — mouseenter/leave pair
|
|
16
|
-
* `On.batch(el, { click, ... })` —
|
|
50
|
+
* `On.batch(el, { click, ... })` — bind multiple events at once
|
|
17
51
|
* `On.first.batch(...)` — one-time multi-bind
|
|
18
52
|
* `On.ready(fn)` — run when DOM is ready
|
|
19
|
-
*
|
|
53
|
+
* `On.group()` — collect related listeners and tear them down together
|
|
54
|
+
* Better TS support for simple binds like `On.input(el, fn)` and `On.change(el, fn)`
|
|
55
|
+
* ESM, zero dependencies, tiny footprint
|
|
20
56
|
|
|
21
57
|
---
|
|
22
58
|
|
|
@@ -28,10 +64,6 @@ npm install on-events
|
|
|
28
64
|
|
|
29
65
|
---
|
|
30
66
|
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
67
|
## Fluent & Composable Sugar
|
|
36
68
|
|
|
37
69
|
```js
|
|
@@ -127,7 +159,7 @@ On.first.batch(document, {
|
|
|
127
159
|
|
|
128
160
|
---
|
|
129
161
|
|
|
130
|
-
## Delegate Batch
|
|
162
|
+
## Delegate Batch
|
|
131
163
|
|
|
132
164
|
You may pass `[selector, handler]` for delegated batch entries:
|
|
133
165
|
|
|
@@ -155,9 +187,56 @@ On.ready(handleReady)
|
|
|
155
187
|
|
|
156
188
|
---
|
|
157
189
|
|
|
190
|
+
## Grouped Cleanup
|
|
191
|
+
|
|
192
|
+
When a UI module binds listeners across multiple elements, `On.group()` lets you track them under one scoped teardown handle.
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
import { On } from 'on-events'
|
|
196
|
+
|
|
197
|
+
const page = On.group()
|
|
198
|
+
|
|
199
|
+
page.click(settingsToggleBtn, () => {
|
|
200
|
+
settingsSection.classList.toggle('collapsed')
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
page.input(searchInput, handleSearch)
|
|
204
|
+
page.delegate.click(document, 'button.save', handleSave)
|
|
205
|
+
|
|
206
|
+
// Later:
|
|
207
|
+
page.stop()
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
You can also manually add an existing cleanup function:
|
|
211
|
+
|
|
212
|
+
```js
|
|
213
|
+
const group = On.group()
|
|
214
|
+
|
|
215
|
+
group.add(On.click(button, handleClick))
|
|
216
|
+
group.add(null) // safely ignored
|
|
217
|
+
|
|
218
|
+
group.stop()
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Custom Events
|
|
224
|
+
|
|
225
|
+
For custom or non-standard event names, use `On.event(type)`:
|
|
226
|
+
|
|
227
|
+
```js
|
|
228
|
+
const stop = On.event('panel:open')(panel, (e) => {
|
|
229
|
+
console.log('opened', e.type)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
stop()
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
158
237
|
# API Reference
|
|
159
238
|
|
|
160
|
-
|
|
239
|
+
## Composable Modifiers
|
|
161
240
|
|
|
162
241
|
Modifiers can be chained before the event name.
|
|
163
242
|
|
|
@@ -216,16 +295,34 @@ Runs `fn` once the DOM is fully loaded (`DOMContentLoaded` or already ready).
|
|
|
216
295
|
|
|
217
296
|
---
|
|
218
297
|
|
|
298
|
+
## `On.group()`
|
|
299
|
+
|
|
300
|
+
Creates a scoped cleanup collector for related listeners.
|
|
301
|
+
|
|
302
|
+
```js
|
|
303
|
+
const group = On.group()
|
|
304
|
+
|
|
305
|
+
group.click(button, onClick)
|
|
306
|
+
group.input(input, onInput)
|
|
307
|
+
|
|
308
|
+
group.stop()
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Useful when a page, modal, or UI module binds listeners across multiple elements and wants one teardown call.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
219
315
|
## Why not `addEventListener` directly?
|
|
220
316
|
|
|
221
317
|
`addEventListener` is great — this library just removes the repetitive parts when you bind lots of UI events.
|
|
222
318
|
|
|
223
319
|
* One-liners for common patterns (`once`, `capture`, `passive`, `delegate`)
|
|
224
|
-
* Every bind returns a `stop()` cleanup function
|
|
320
|
+
* Every bind returns a `stop()` cleanup function
|
|
225
321
|
* Delegation helper that sets `this` to the matched element
|
|
226
322
|
* Batch binding to keep setup code tidy
|
|
227
|
-
*
|
|
228
|
-
*
|
|
323
|
+
* Grouped cleanup for lifecycle-based teardown
|
|
324
|
+
* Composable modifiers instead of option object juggling
|
|
325
|
+
* Zero deps and tiny footprint
|
|
229
326
|
|
|
230
327
|
---
|
|
231
328
|
|
|
@@ -233,11 +330,11 @@ Runs `fn` once the DOM is fully loaded (`DOMContentLoaded` or already ready).
|
|
|
233
330
|
|
|
234
331
|
This library is a thin wrapper around native `addEventListener`.
|
|
235
332
|
|
|
236
|
-
* **Direct binding (`On.click(el, fn)` / `on(el, 'click', fn)`)**:
|
|
237
|
-
* **`first` / `capture` / `passive`**: uses
|
|
238
|
-
* **Delegation (`On.delegate.*`)**:
|
|
333
|
+
* **Direct binding (`On.click(el, fn)` / `on(el, 'click', fn)`)**: essentially zero runtime overhead beyond one extra function call during setup.
|
|
334
|
+
* **`first` / `capture` / `passive`**: uses native listener options.
|
|
335
|
+
* **Delegation (`On.delegate.*`)**: performs a `closest(selector)` lookup per event. Ideal for reducing listener count, but direct binding is better for extremely hot events like `mousemove`.
|
|
239
336
|
|
|
240
|
-
Rule of thumb:
|
|
337
|
+
Rule of thumb: delegate `click`, `input`, and `submit`; bind directly for high-frequency events.
|
|
241
338
|
|
|
242
339
|
---
|
|
243
340
|
|
|
@@ -250,14 +347,18 @@ Rule of thumb: use delegation for `click/input/submit`, and direct handlers for
|
|
|
250
347
|
|
|
251
348
|
---
|
|
252
349
|
|
|
253
|
-
## Low-level API (on / off)
|
|
350
|
+
## Low-level API (`on` / `off`)
|
|
254
351
|
|
|
255
352
|
If you prefer a minimal, explicit API without fluent modifiers, you can use the core helpers directly.
|
|
256
353
|
|
|
257
354
|
### `on(el, event, handler)`
|
|
258
355
|
|
|
356
|
+
### `on(el, event, handler, options)`
|
|
357
|
+
|
|
259
358
|
### `on(el, event, selector, handler)`
|
|
260
359
|
|
|
360
|
+
### `on(el, event, selector, handler, options)`
|
|
361
|
+
|
|
261
362
|
Adds a standard or delegated event listener.
|
|
262
363
|
Returns a `stop()` function that removes the listener.
|
|
263
364
|
|
package/dist/on-events.d.ts
CHANGED
|
@@ -5,54 +5,99 @@ export type Stop = () => void
|
|
|
5
5
|
export type Handler<E extends Event = Event> = (this: Element, ev: E) => any
|
|
6
6
|
export type DirectHandler<E extends Event = Event> = (ev: E) => any
|
|
7
7
|
|
|
8
|
+
export type BatchMap = Record<
|
|
9
|
+
string,
|
|
10
|
+
| DirectHandler<any>
|
|
11
|
+
| [string, Handler<any>]
|
|
12
|
+
>
|
|
13
|
+
|
|
14
|
+
// --- Low-level API ---
|
|
15
|
+
|
|
8
16
|
export function on<E extends Event = Event>(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
el: EventTarget,
|
|
18
|
+
event: string,
|
|
19
|
+
handler: DirectHandler<E>,
|
|
20
|
+
options?: AddEventListenerOptions | boolean
|
|
12
21
|
): Stop
|
|
13
22
|
|
|
14
23
|
export function on<E extends Event = Event>(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
el: Element | Document,
|
|
25
|
+
event: string,
|
|
26
|
+
selector: string,
|
|
27
|
+
handler: Handler<E>,
|
|
28
|
+
options?: AddEventListenerOptions | boolean
|
|
19
29
|
): Stop
|
|
20
30
|
|
|
21
31
|
export function off<E extends Event = Event>(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
el: EventTarget,
|
|
33
|
+
event: string,
|
|
34
|
+
handler: DirectHandler<E>,
|
|
35
|
+
selector?: null
|
|
26
36
|
): void
|
|
27
37
|
|
|
28
38
|
export function off<E extends Event = Event>(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
el: Element | Document,
|
|
40
|
+
event: string,
|
|
41
|
+
handler: Handler<E>,
|
|
42
|
+
selector?: string
|
|
33
43
|
): void
|
|
34
44
|
|
|
45
|
+
// --- Fluent Event Binder ---
|
|
46
|
+
|
|
47
|
+
export interface EventBinder<E extends Event = Event> {
|
|
48
|
+
(el: EventTarget, handler: DirectHandler<E>): Stop
|
|
49
|
+
(el: Element | Document, selector: string, handler: Handler<E>): Stop
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// --- Fluent Chain API core ---
|
|
53
|
+
|
|
35
54
|
export interface OnChain {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
first: OnChain
|
|
56
|
+
once: OnChain
|
|
57
|
+
capture: OnChain
|
|
58
|
+
passive: OnChain
|
|
59
|
+
delegate: OnChain
|
|
60
|
+
|
|
61
|
+
hover(
|
|
62
|
+
el: Element,
|
|
63
|
+
enter: (ev: MouseEvent) => any,
|
|
64
|
+
leave: (ev: MouseEvent) => any
|
|
65
|
+
): Stop
|
|
66
|
+
|
|
67
|
+
batch(
|
|
68
|
+
el: EventTarget,
|
|
69
|
+
map: BatchMap
|
|
70
|
+
): Stop
|
|
71
|
+
|
|
72
|
+
ready(fn: () => void): void
|
|
73
|
+
|
|
74
|
+
group(): OnGroup
|
|
75
|
+
|
|
76
|
+
<E extends Event = Event>(
|
|
77
|
+
el: EventTarget,
|
|
78
|
+
handler: DirectHandler<E>
|
|
79
|
+
): Stop
|
|
80
|
+
|
|
81
|
+
<E extends Event = Event>(
|
|
82
|
+
el: Element | Document,
|
|
83
|
+
selector: string,
|
|
84
|
+
handler: Handler<E>
|
|
85
|
+
): Stop
|
|
86
|
+
|
|
87
|
+
// fallback for custom / non-standard event names
|
|
88
|
+
event(type: string): OnChain & EventBinder<Event>
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type OnEventMap = {
|
|
92
|
+
[K in keyof GlobalEventHandlersEventMap]:
|
|
93
|
+
OnChain & EventBinder<GlobalEventHandlersEventMap[K]>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type OnAPI = OnChain & OnEventMap
|
|
97
|
+
|
|
98
|
+
export type OnGroup = OnAPI & {
|
|
99
|
+
stop(): void
|
|
100
|
+
add<T extends Stop | null | undefined | false>(stop: T): T
|
|
56
101
|
}
|
|
57
102
|
|
|
58
|
-
export const On:
|
|
103
|
+
export const On: OnAPI
|
package/dist/on-events.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// On-Events - A tiny DOM event utility with sugar.
|
|
2
|
-
var
|
|
2
|
+
var h=new WeakMap;function p(n,u,c,r,t){typeof c=="function"&&(t=r,r=c,c=null);let o=t||void 0,e=c?i=>{let f=i.target instanceof Element?i.target:i.target?.parentElement;if(!f)return;let d=f.closest(c);d&&typeof n.contains=="function"&&n.contains(d)&&r.call(d,i)}:r;return n.addEventListener(u,e,o),h.has(n)||h.set(n,[]),h.get(n).push({type:u,cb:r,selector:c,wrapped:e,capture:!!(o&&o.capture)}),()=>w(n,u,r,c)}function w(n,u,c,r=null){let t=h.get(n);if(t){for(let o=t.length;o-- >0;){let e=t[o];e.type===u&&e.cb===c&&(r?e.selector===r:!e.selector)&&(n.removeEventListener(u,e.wrapped,{capture:e.capture}),t.splice(o,1))}t.length||h.delete(n)}}var m=1,v=2,y=4,l=8,E=n=>{if(!(n&(m|v|y)))return;let u={};return n&m&&(u.once=!0),n&v&&(u.capture=!0),n&y&&(u.passive=!0),u},a=(n=0)=>new Proxy(Object.create(null),{get(u,c){if(Reflect.has(u,c))return Reflect.get(u,c);let r=String(c);return r==="first"||r==="once"?a(n|m):r==="capture"?a(n|v):r==="passive"?a(n|y):r==="delegate"?a(n|l):r==="event"?t=>a(n)[t]:r==="hover"?(t,o,e)=>{let s=E(n),i=p(t,"mouseenter",o,s),f=p(t,"mouseleave",e,s);return()=>{i(),f()}}:r==="batch"?(t,o)=>{let e=[];for(let[s,i]of Object.entries(o)){if(typeof i=="function"){e.push(a(n)[s](t,i));continue}if(Array.isArray(i)){let[f,d]=i;e.push(a(n|l)[s](t,f,d))}}return()=>{for(let s of e)s()}}:r==="ready"?t=>{typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",t,{once:!0}):t())}:(t,...o)=>{let e=E(n);if(n&l){let[i,f]=o;return p(t,r,i,f,e)}let[s]=o;return p(t,r,s,e)}}}),g=a();g.group=function(){let u=new Set,c=t=>(typeof t=="function"&&u.add(t),t),r=()=>{let t=[];for(let o of u)try{o()}catch(e){t.push(e)}if(u.clear(),t.length===1)throw t[0];if(t.length>1)throw new AggregateError(t,"On.group().stop() failed for one or more listeners")};return new Proxy(Object.create(null),{get(t,o){if(o==="add")return c;if(o==="stop")return r;let e=g[o];return e==null?e:o==="event"?s=>{let i=e(s);return(...f)=>c(i(...f))}:typeof e=="function"?(...s)=>c(e(...s)):new Proxy(e,{get(s,i){let f=e[i];return typeof f=="function"?(...d)=>c(f(...d)):f}})}})};g.once=g.first;var O=(n,u,...c)=>p(n,u,...c);export{g as On,w as off,O as on};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/on-events.js"],
|
|
4
|
-
"sourcesContent": ["// on-events.js\r\n// On-Events \u2014 tiny DOM event utility with composable sugar.\r\n\r\n// --- internal base ---\r\nconst listeners = new WeakMap()\r\n\r\n/**\r\n * baseOn(el, type, handler)\r\n * baseOn(el, type, selector, handler)\r\n * baseOn(el, type, handler, options)\r\n * baseOn(el, type, selector, handler, options)\r\n */\r\nfunction baseOn(el, type, selector, cb, options) {\r\n //
|
|
5
|
-
"mappings": ";AAIA,IAAMA,EAAY,IAAI,QAQtB,SAASC,EAAOC,EAAIC,EAAMC,EAAUC,EAAIC,EAAS,CAE3C,OAAOF,GAAa,aACtBE,EAAUD,EACVA,EAAKD,EACLA,EAAW,MAGb,IAAMG,EAAOD,GAAW,OAElBE,EAAUJ,EACXK,GAAM,
|
|
6
|
-
"names": ["listeners", "baseOn", "el", "type", "selector", "cb", "options", "opts", "wrapped", "e", "target", "match", "off", "group", "i", "h", "ONCE", "CAPTURE", "PASSIVE", "DELEGATE", "optsFor", "f", "o", "makeOn", "flags", "
|
|
4
|
+
"sourcesContent": ["// on-events.js\r\n// On-Events \u2014 tiny DOM event utility with composable sugar.\r\n\r\n// --- internal base ---\r\nconst listeners = new WeakMap()\r\n\r\n/**\r\n * baseOn(el, type, handler)\r\n * baseOn(el, type, selector, handler)\r\n * baseOn(el, type, handler, options)\r\n * baseOn(el, type, selector, handler, options)\r\n */\r\nfunction baseOn(el, type, selector, cb, options) {\r\n // Normalize overloaded signatures so everything below can use one path.\r\n if (typeof selector === 'function') {\r\n options = cb\r\n cb = selector\r\n selector = null\r\n }\r\n\r\n const opts = options || undefined\r\n\r\n const wrapped = selector\r\n ? (e) => {\r\n // Delegation can receive a Text node as the event target.\r\n // Normalize that to an element before calling closest().\r\n const target = e.target instanceof Element ? e.target : e.target?.parentElement\r\n if (!target) return\r\n\r\n const match = target.closest(selector)\r\n if (!match) return\r\n\r\n // Guard delegated matching so odd targets like window do not explode.\r\n if (typeof el.contains === 'function' && el.contains(match)) {\r\n cb.call(match, e)\r\n }\r\n }\r\n : cb\r\n\r\n el.addEventListener(type, wrapped, opts)\r\n\r\n if (!listeners.has(el)) listeners.set(el, [])\r\n const group = listeners.get(el)\r\n\r\n group.push({\r\n type,\r\n cb,\r\n selector,\r\n wrapped,\r\n capture: !!(opts && opts.capture), // capture must match during removal\r\n })\r\n\r\n return () => off(el, type, cb, selector)\r\n}\r\n\r\nfunction off(el, type, cb, selector = null) {\r\n const group = listeners.get(el)\r\n if (!group) return\r\n\r\n for (let i = group.length; i-- > 0;) {\r\n const h = group[i]\r\n const match =\r\n h.type === type &&\r\n h.cb === cb &&\r\n (selector ? h.selector === selector : !h.selector)\r\n\r\n if (match) {\r\n // removeEventListener only cares about capture on teardown.\r\n el.removeEventListener(type, h.wrapped, { capture: h.capture })\r\n group.splice(i, 1)\r\n }\r\n }\r\n\r\n if (!group.length) listeners.delete(el)\r\n}\r\n\r\n// --- composable sugar: On.<mods>.<event>(...) ---\r\n// Bitflags keep the proxy small and cheap.\r\nconst ONCE = 1\r\nconst CAPTURE = 2\r\nconst PASSIVE = 4\r\nconst DELEGATE = 8\r\n\r\nconst optsFor = (f) => {\r\n // Allocate listener options only when needed.\r\n // Capture is stored separately so removeEventListener can match it later.\r\n if (!(f & (ONCE | CAPTURE | PASSIVE))) return undefined\r\n\r\n const o = {}\r\n if (f & ONCE) o.once = true\r\n if (f & CAPTURE) o.capture = true\r\n if (f & PASSIVE) o.passive = true\r\n return o\r\n}\r\n\r\nconst makeOn = (flags = 0) =>\r\n new Proxy(Object.create(null), {\r\n get(target, prop) {\r\n // Respect concrete properties assigned directly onto the proxy target.\r\n // This is what makes late-added members like On.group work instead of\r\n // being mistaken for an event name.\r\n if (Reflect.has(target, prop)) {\r\n return Reflect.get(target, prop)\r\n }\r\n\r\n const k = String(prop)\r\n\r\n // Modifier chaining accumulates flags and returns a fresh proxy.\r\n if (k === 'first' || k === 'once') return makeOn(flags | ONCE)\r\n if (k === 'capture') return makeOn(flags | CAPTURE)\r\n if (k === 'passive') return makeOn(flags | PASSIVE)\r\n if (k === 'delegate') return makeOn(flags | DELEGATE)\r\n\r\n // Custom event helper: On.event('panel:open')(el, fn)\r\n if (k === 'event') {\r\n return (type) => makeOn(flags)[type]\r\n }\r\n\r\n // Utilities live on the same fluent surface for ergonomics.\r\n if (k === 'hover') {\r\n return (el, enter, leave) => {\r\n const o = optsFor(flags)\r\n const offIn = baseOn(el, 'mouseenter', enter, o)\r\n const offOut = baseOn(el, 'mouseleave', leave, o)\r\n return () => {\r\n offIn()\r\n offOut()\r\n }\r\n }\r\n }\r\n\r\n if (k === 'batch') {\r\n return (el, map) => {\r\n const stops = []\r\n\r\n for (const [event, val] of Object.entries(map)) {\r\n // Direct entry: { click: fn }\r\n if (typeof val === 'function') {\r\n stops.push(makeOn(flags)[event](el, val))\r\n continue\r\n }\r\n\r\n // Delegated entry: { click: ['a', fn] }\r\n if (Array.isArray(val)) {\r\n const [selector, fn] = val\r\n stops.push(makeOn(flags | DELEGATE)[event](el, selector, fn))\r\n }\r\n }\r\n\r\n return () => {\r\n for (const stop of stops) stop()\r\n }\r\n }\r\n }\r\n\r\n if (k === 'ready') {\r\n return (fn) => {\r\n if (typeof document === 'undefined') return\r\n\r\n // Run immediately if the DOM is already ready.\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', fn, { once: true })\r\n } else {\r\n fn()\r\n }\r\n }\r\n }\r\n\r\n // Default path: treat the property name as the event type.\r\n return (el, ...args) => {\r\n const o = optsFor(flags)\r\n\r\n if (flags & DELEGATE) {\r\n const [selector, handler] = args\r\n return baseOn(el, k, selector, handler, o)\r\n }\r\n\r\n const [handler] = args\r\n return baseOn(el, k, handler, o)\r\n }\r\n },\r\n })\r\n\r\nconst On = makeOn()\r\n\r\n// Creates a scoped listener collector.\r\n// Any stop() returned by On.* calls is tracked and can be removed together via group.stop().\r\nOn.group = function group() {\r\n const stops = new Set()\r\n\r\n const track = (stop) => {\r\n // Pass through nullish / false values so callers can safely write:\r\n // group.add(maybeElement ? On.click(...) : null)\r\n if (typeof stop === 'function') stops.add(stop)\r\n return stop\r\n }\r\n\r\n const stopAll = () => {\r\n const errors = []\r\n\r\n // Try every tracked cleanup so one bad stop() does not block the rest.\r\n for (const stop of stops) {\r\n try {\r\n stop()\r\n } catch (err) {\r\n errors.push(err)\r\n }\r\n }\r\n\r\n stops.clear()\r\n\r\n if (errors.length === 1) throw errors[0]\r\n if (errors.length > 1) {\r\n throw new AggregateError(errors, 'On.group().stop() failed for one or more listeners')\r\n }\r\n }\r\n\r\n return new Proxy(Object.create(null), {\r\n get(_target, prop) {\r\n // Hard override these names so they never fall through into event binding.\r\n if (prop === 'add') return track\r\n if (prop === 'stop') return stopAll\r\n\r\n const value = On[prop]\r\n if (value == null) return value\r\n\r\n // event(type) is a factory: it returns a binder, not a stop handle.\r\n // Wrap the binder so the eventual stop() is what gets tracked.\r\n if (prop === 'event') {\r\n return (type) => {\r\n const binder = value(type)\r\n return (...args) => track(binder(...args))\r\n }\r\n }\r\n\r\n // Top-level callables like group.click(...), group.batch(...), group.ready(...)\r\n // are wrapped so any returned stop() is automatically tracked.\r\n if (typeof value === 'function') {\r\n return (...args) => track(value(...args))\r\n }\r\n\r\n // Nested chain objects like group.capture or group.delegate are proxies too.\r\n // Wrap their callable leaves so group.capture.click(...) also tracks cleanup.\r\n return new Proxy(value, {\r\n get(_nestedTarget, nestedProp) {\r\n const nestedValue = value[nestedProp]\r\n\r\n if (typeof nestedValue === 'function') {\r\n return (...args) => track(nestedValue(...args))\r\n }\r\n\r\n return nestedValue\r\n },\r\n })\r\n },\r\n })\r\n}\r\n\r\n// --- legacy alias for backward compatibility ---\r\nOn.once = On.first\r\n\r\n// --- classic support ---\r\nconst on = (el, event, ...args) => baseOn(el, event, ...args)\r\n\r\nexport { on, On, off }\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["listeners", "baseOn", "el", "type", "selector", "cb", "options", "opts", "wrapped", "e", "target", "match", "off", "group", "i", "h", "ONCE", "CAPTURE", "PASSIVE", "DELEGATE", "optsFor", "f", "o", "makeOn", "flags", "prop", "k", "enter", "leave", "offIn", "offOut", "map", "stops", "event", "val", "fn", "stop", "args", "handler", "On", "track", "stopAll", "errors", "err", "_target", "value", "binder", "_nestedTarget", "nestedProp", "nestedValue", "on"]
|
|
7
7
|
}
|