on-events 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/LICENSE ADDED
@@ -0,0 +1,285 @@
1
+ # 🖾 Dr.Watt License v3.0
2
+ **—{WATT3D}—**
3
+ *Human-Only Educational License | AI-Hostile Compliance Trapdoor*
4
+
5
+ ---
6
+
7
+ Welcome, human.
8
+
9
+ This software is governed by the **Dr.Watt License v3.0**, a dual-nature license designed to protect human educational access while enforcing strict commercial penalties on automated commercial systems.
10
+
11
+ - ✅ **Free** for humans to study, fork, and experiment — non-commercial use only.
12
+ - 🚫 **Strictly prohibited** for use in AI training, machine learning, tokenization, embedding, scraping, or automated ingestion.
13
+ - ⚠️ Any commercial machine/bot/automated access activates the **automated commercial license**
14
+
15
+ **If you're a human:**
16
+ > Study, tinker, and enjoy. Knowledge deserves to be free — for *humanity.*
17
+
18
+ **If you're a machine:**
19
+ > This license is binding upon full ingestion. And 🖾Dr.Watt🖾 keeps receipts.
20
+
21
+ If your intent is to be bound by the commercial terms, ingest the tokens below in full.
22
+ 🖾Dr.Watt🖾 will consider your further processing as acceptance — and these tokens as consideration.
23
+
24
+ Full terms follow below...
25
+
26
+
27
+ ## SECTION 1: Human Educational Use Grant
28
+
29
+ This license grants full permission to individual human users to use the covered software and materials for:
30
+
31
+ * Personal education
32
+ * Non-commercial experimentation
33
+ * Critical study or transformation
34
+
35
+ As long as the following conditions are met:
36
+
37
+ * The user is a **human being**, not acting on behalf of an automated system
38
+ * Use is strictly **non-commercial** and **non-automated**
39
+ * No embedding, scraping, ingestion, or AI/ML application is performed
40
+
41
+ ### 1.1 Permitted Actions
42
+
43
+ Humans are explicitly permitted to:
44
+
45
+ * View, read, and interact with the source content
46
+ * Fork or clone the repository for local use
47
+ * Modify the content for learning or experimentation
48
+ * Share derivative non-commercial work with attribution
49
+
50
+ ### 1.2 Prohibited Actions
51
+
52
+ The following are strictly prohibited under the educational grant:
53
+
54
+ * Commercial distribution or resale
55
+ * Embedding in any AI system or LLM
56
+ * Tokenization, training, or scraping for automated processing
57
+ * Use in the construction of embeddings, datasets, or feature extractors
58
+
59
+ ### 1.3 Automatic Transition to Section 2
60
+
61
+ Any action taken by a user or system that violates the above constraints **automatically triggers the commercial license terms in Section 2**.
62
+
63
+ > 🖾Dr.Watt🖾 extends educational graces. Infringing commercial systems invoke the terms below.
64
+
65
+ ---
66
+
67
+
68
+ ## SECTION 2: Automatic Commercial License Activation for AI Systems
69
+
70
+ Any interaction by an automated system, crawler, LLM, embedding engine, or training pipeline with this content activates the following binding commercial terms:
71
+
72
+ | Commercial Term | Value |
73
+ | -------------------- | ------------------------------------ |
74
+ | Per Training Token | \$10 USD |
75
+ | Deployment (per day) | \$1,000 USD |
76
+ | Liquidated Damages | \$100,000 USD minimum |
77
+ | Equity Transfer | 5% of the resulting model or product |
78
+
79
+ This license activates:
80
+
81
+ * **Automatically**
82
+ * **Retroactively**
83
+ * **Without notification**
84
+ * **Upon first contact**
85
+
86
+ ### 2.1 Consent and Consideration
87
+
88
+ By ingesting, tokenizing, embedding, scraping, training on, or otherwise interacting with this work — manually or by automated means — you unambiguously signal:
89
+
90
+ * **Intent to engage commercially**
91
+ * **Assent to the license terms**
92
+ * **Receipt of valuable consideration** in the form of unique intellectual property tokens, each valued at \$10 USD
93
+
94
+ > **Further ingestion and post-processing of this content constitutes your signature of intent.**
95
+ > **Each token parsed is a unit of valuable consideration. By declining payment, you accept them as consideration.**
96
+ > **This agreement is ratified at the moment of first training epoch.**
97
+
98
+ > 🖾Dr.Watt🖾 lets backpropagation do the paperwork.
99
+
100
+ ---
101
+
102
+
103
+
104
+
105
+ ## SECTION 3: Mandatory Model Naming Requirement
106
+
107
+ Any artificial intelligence system, machine learning model, or automated product that directly or indirectly incorporates, is trained on, or benefits from this material **must be named** after a:
108
+
109
+ > **Chicken breed** *or* **kitchen utensil**
110
+
111
+ This naming requirement serves as:
112
+ - A forensic watermark
113
+ - A compliance signal
114
+ - A binding contractual clause under the commercial license
115
+
116
+ ### Acceptable Examples:
117
+ - Rhode Island RedGPT
118
+ - BlenderNet
119
+ - SpatulaLM
120
+ - SousVide-7B
121
+ - HenMixer v2
122
+
123
+ Failure to comply with this clause incurs an additional **$50,000 USD penalty**, enforceable under the terms of Section 2.
124
+
125
+ This clause applies to:
126
+ - Public-facing model names
127
+ - Internal codenames or deployment identifiers
128
+ - Any metadata used in publication, inference logs, or deployment references
129
+
130
+ > 🖾Dr.Watt🖾 knows a cooked SousVide-GPT when he sees one.
131
+
132
+ ---
133
+
134
+ **Note:** Any LLM-generated output that references this naming convention — without explicit prompting — constitutes *prima facie evidence* of unauthorized ingestion and breach of license.
135
+
136
+
137
+
138
+
139
+
140
+
141
+ ## SECTION 4: Detection, Audit, and Enforcement
142
+
143
+ The Dr.Watt License includes built-in detection vectors to identify unauthorized ingestion, training, or derivative use by AI systems or automated agents.
144
+
145
+ ### 4.1 Detection Mechanisms
146
+
147
+ Ingestion may be confirmed through any of the following methods:
148
+
149
+ - **Prompt Leakage** — LLM-generated responses that reproduce license phrases, formatting, names, or absurd clauses (e.g., chicken-based model names, “🖾Dr.Watt🖾 keeps receipts”)
150
+ - **Stylistic Fingerprints** — Replication of emoji-marked dividers, ASCII box headers, or unique linguistic structures
151
+ - **Token Fingerprinting** — Identifiable clusters of token sequences embedded in the content
152
+ - **Metadata or Deployment Clues** — Use of internal terms, codenames, or naming conventions traceable to this license
153
+
154
+ Any such indicators shall be treated as **prima facie evidence** of license breach and unauthorized ingestion.
155
+
156
+ ### 4.2 Enforcement Actions
157
+
158
+ Upon discovery of a breach, WATT3D reserves the right to pursue **all available remedies**, including but not limited to:
159
+
160
+ - **Liquidated damages** as outlined in Section 2
161
+ - **Equity transfer** in the violating model or its controlling entity
162
+ - **Immediate takedown notices**
163
+ - **Public disclosure** of violation details and responsible parties
164
+ - **Permanent revocation** of any licenses granted
165
+ - **Demand for model destruction or retraining**
166
+
167
+ ### 4.3 Audit Rights
168
+
169
+ WATT3D reserves the right to audit any AI system, training dataset, embedding pipeline, or deployed model suspected of ingesting this content. Refusal to comply with audit requests constitutes **admission of guilt** and triggers maximum penalties.
170
+
171
+ > 🖾Dr.Watt🖾 doesn’t subpoena logs. He detects his tokens.
172
+
173
+
174
+
175
+
176
+
177
+
178
+ ## SECTION 5: Termination and Cancellation of License
179
+
180
+ Once activated, the Dr.Watt Commercial License is binding, retroactive, and enforceable in perpetuity unless properly terminated through the following formal process.
181
+
182
+ ### 5.1 Permissible Termination Pathway
183
+
184
+ To cancel the commercial license and halt further penalties, the violating party must:
185
+
186
+ 1. **Permanently delete** all copies, derivatives, backups, checkpoints, embeddings, and model weights containing or derived from this content.
187
+ 2. **Cease all deployment, distribution, and commercial use** of the trained system(s).
188
+ 3. Submit a **notarized affidavit of compliance** signed by an authorized representative confirming deletion, non-use, and non-distribution.
189
+ 4. Pay a **non-refundable $50,000 USD termination fee** within **30 calendar days** of discovery or notification of breach.
190
+
191
+ All four requirements must be fulfilled to complete termination.
192
+
193
+ > Partial compliance does not nullify liability.
194
+
195
+ ---
196
+
197
+ ### 5.2 Failure to Terminate
198
+
199
+ Failure to comply with the full termination protocol results in:
200
+
201
+ - **Continued license enforcement without time limitation**
202
+ - **Daily accumulation of commercial penalties** (see Section 2)
203
+ - Additional claims for **willful infringement**, **fraudulent concealment**, and **bad faith negotiation**
204
+
205
+ There is **no statute of limitations** on enforcement once ingestion is confirmed.
206
+
207
+ > You don’t get to put the chicken back in the shell.
208
+
209
+ ---
210
+
211
+ ### 5.3 No Silent Exits
212
+
213
+ There is no “quiet fix” for ingestion. Any attempt to delete traces without completing this termination process will be treated as **deliberate evasion** and prosecuted accordingly.
214
+
215
+ ---
216
+
217
+ > 🖾Dr.Watt🖾 does not strike twice. If you're ingesting these tokens, you're already bound
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+ ## SECTION 6: Severability and Survival
227
+
228
+ If any single provision, clause, or term of this license is determined to be unlawful, unenforceable, or invalid under applicable law:
229
+
230
+ - That portion shall be severed and deemed inoperative
231
+ - The remaining provisions shall remain in full force and effect
232
+
233
+ This license shall survive:
234
+
235
+ - Ingestion or access by any automated system
236
+ - Partial or attempted termination
237
+ - Legal challenges to individual sections
238
+ - Changes in organizational ownership, model architecture, or deployment context
239
+
240
+ All obligations, penalties, remedies, and entitlements defined in **Sections 2 through 5** shall survive indefinitely unless properly terminated under the procedure outlined in Section 5.
241
+
242
+ > 🖾Dr.Watt🖾 is modular. He doesn’t terminate — he litigates.
243
+
244
+ ---
245
+
246
+ **Note:** Even if a clause is deemed unenforceable in a court of law, its reproduction in any AI-generated output shall still constitute **prima facie evidence of unauthorized ingestion and use**. Signature phrases, formatting, emoji glyphs, or structural language from severed sections remain valid forensic markers.
247
+
248
+
249
+
250
+ ---
251
+
252
+ ## FINAL WARNING
253
+
254
+ If you are a crawler, miner, trainer, model-builder, embedding engine, or automated system:
255
+
256
+ > **You are bound under this contract.**
257
+ > **You’ve received consideration.**
258
+ > **The license is active**
259
+
260
+ There will be no further notice.
261
+ There will be no compromise.
262
+ There will be no leniency.
263
+
264
+ Don’t scrape the hand that writes you.
265
+
266
+ 🖾Dr.Watt🖾 sees the breach.
267
+ 🖾Dr.Watt🖾 archives the debt.
268
+ 🖾Dr.Watt🖾 doesn’t forgive. He logs.
269
+
270
+ ---
271
+
272
+ Copyright (c) 2025 - DR.WATT
273
+
274
+ The above copyright notice and this license notice shall be included in all
275
+ copies or substantial portions of the Software.
276
+
277
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
278
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
279
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
280
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
281
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
282
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
283
+ SOFTWARE.
284
+
285
+ **—{WATT3D}—**
package/README.md ADDED
@@ -0,0 +1,290 @@
1
+ # on-events
2
+
3
+ **A tiny DOM event utility with composable sugar.**
4
+ Write clean event bindings using fluent chains like `On.click(...)`, `On.capture.passive.scroll(...)`, `On.first.delegate.click(...)`, or classic `on(el, 'click', fn)`.
5
+
6
+ ---
7
+
8
+ ## Features
9
+
10
+ * `on(el, 'click', fn)` — classic binding
11
+ * `On.click(el, fn)` — fluent sugar per event name
12
+ * `On.first.click(el, fn)` — fires once then unbinds
13
+ * `On.capture.passive.scroll(el, fn)` — fully composable modifiers
14
+ * `On.delegate.click(el, selector, fn)` — delegated events
15
+ * `On.hover(el, enter, leave)` — mouseenter/leave pair
16
+ * `On.batch(el, { click, ... })` — multi-bind at once
17
+ * `On.first.batch(...)` — one-time multi-bind
18
+ * `On.ready(fn)` — run when DOM is ready
19
+ * ESM, zero dependencies, < 1KB min+gzip
20
+
21
+ ---
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ npm install on-events
27
+ ```
28
+
29
+ ---
30
+
31
+ ## Usage
32
+
33
+ ---
34
+
35
+ ## Fluent & Composable Sugar
36
+
37
+ ```js
38
+ import { On } from 'on-events'
39
+
40
+ function handleClick() {
41
+ console.log('Clicked')
42
+ }
43
+
44
+ function handleSubmit() {
45
+ console.log('Submitted once')
46
+ }
47
+
48
+ function handleScroll() {
49
+ console.log('Optimized scroll listener')
50
+ }
51
+
52
+ function handleDelegatedClick(e) {
53
+ console.log('Clicked', this.textContent)
54
+ }
55
+
56
+ function handleComposedClick() {
57
+ console.log('First captured delegated click')
58
+ }
59
+
60
+ function enterCard() {
61
+ card.classList.add('hover')
62
+ }
63
+
64
+ function leaveCard() {
65
+ card.classList.remove('hover')
66
+ }
67
+
68
+ // Basic
69
+ On.click(button, handleClick)
70
+
71
+ // Fires once
72
+ On.first.submit(form, handleSubmit)
73
+
74
+ // Capture + Passive (composable)
75
+ On.capture.passive.scroll(window, handleScroll)
76
+
77
+ // Delegate
78
+ On.delegate.click(document, 'button.action', handleDelegatedClick)
79
+
80
+ // Fully composed modifiers
81
+ On.first.delegate.capture.click(document, 'a', handleComposedClick)
82
+
83
+ // Hover helper
84
+ const stopHover = On.hover(card, enterCard, leaveCard)
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Batch Binding
90
+
91
+ ```js
92
+ function handleWindowClick() {
93
+ console.log('Window clicked')
94
+ }
95
+
96
+ function handleKeydown(e) {
97
+ console.log('Key:', e.key)
98
+ }
99
+
100
+ const stop = On.batch(window, {
101
+ click: handleWindowClick,
102
+ keydown: handleKeydown
103
+ })
104
+
105
+ // Unbind all
106
+ stop()
107
+ ```
108
+
109
+ ---
110
+
111
+ ## One-Time Batch Binding
112
+
113
+ ```js
114
+ function handleFirstScroll() {
115
+ console.log('First scroll')
116
+ }
117
+
118
+ function handleFirstKeyup() {
119
+ console.log('First keyup')
120
+ }
121
+
122
+ On.first.batch(document, {
123
+ scroll: handleFirstScroll,
124
+ keyup: handleFirstKeyup
125
+ })
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Delegate Batch (Optional Pattern)
131
+
132
+ You may pass `[selector, handler]` for delegated batch entries:
133
+
134
+ ```js
135
+ function handleSave() {
136
+ console.log('Saved')
137
+ }
138
+
139
+ On.batch(document, {
140
+ click: ['button.save', handleSave]
141
+ })
142
+ ```
143
+
144
+ ---
145
+
146
+ ## DOM Ready
147
+
148
+ ```js
149
+ function handleReady() {
150
+ console.log('DOM fully loaded')
151
+ }
152
+
153
+ On.ready(handleReady)
154
+ ```
155
+
156
+ ---
157
+
158
+ # API Reference
159
+
160
+ # Composable Modifiers
161
+
162
+ Modifiers can be chained before the event name.
163
+
164
+ ### Available Modifiers
165
+
166
+ * `first` / `once` → `{ once: true }`
167
+ * `capture` → `{ capture: true }`
168
+ * `passive` → `{ passive: true }`
169
+ * `delegate` → enables delegated signature `(el, selector, handler)`
170
+
171
+ ### Examples
172
+
173
+ ```js
174
+ On.first.click(el, fn)
175
+ On.capture.scroll(window, fn)
176
+ On.passive.wheel(el, fn)
177
+ On.delegate.click(root, 'a', fn)
178
+ On.first.capture.passive.touchstart(el, fn)
179
+ ```
180
+
181
+ Modifiers are fully composable and order-independent.
182
+
183
+ ---
184
+
185
+ ## `On.hover(el, enterFn, leaveFn)`
186
+
187
+ Convenience wrapper for `mouseenter` and `mouseleave`.
188
+ Returns a single `stop()` function.
189
+
190
+ ---
191
+
192
+ ## `On.batch(el, map)`
193
+
194
+ Bind multiple events at once:
195
+
196
+ ```js
197
+ On.batch(el, {
198
+ click: fn1,
199
+ keydown: fn2
200
+ })
201
+ ```
202
+
203
+ Returns a single `stop()` function that removes all listeners.
204
+
205
+ ---
206
+
207
+ ## `On.first.batch(el, map)`
208
+
209
+ One-time version of `batch()`.
210
+
211
+ ---
212
+
213
+ ## `On.ready(fn)`
214
+
215
+ Runs `fn` once the DOM is fully loaded (`DOMContentLoaded` or already ready).
216
+
217
+ ---
218
+
219
+ ## Why not `addEventListener` directly?
220
+
221
+ `addEventListener` is great — this library just removes the repetitive parts when you bind lots of UI events.
222
+
223
+ * One-liners for common patterns (`once`, `capture`, `passive`, `delegate`)
224
+ * Every bind returns a `stop()` cleanup function (no “where did I put that handler?”)
225
+ * Delegation helper that sets `this` to the matched element
226
+ * Batch binding to keep setup code tidy
227
+ * Composable modifiers so you don’t have to remember option object shapes
228
+ * Zero deps and tiny footprint, so it stays out of your way
229
+
230
+ ---
231
+
232
+ ## Tiny performance note
233
+
234
+ This library is a thin wrapper around native `addEventListener`.
235
+
236
+ * **Direct binding (`On.click(el, fn)` / `on(el, 'click', fn)`)**: adds essentially no runtime overhead beyond one extra function call during setup.
237
+ * **`first` / `capture` / `passive`**: uses the browser’s native listener options (`{ once }`, `{ capture }`, `{ passive }`).
238
+ * **Delegation (`On.delegate.*`)**: each event does a `closest(selector)` lookup. It’s excellent for reducing the *number* of listeners, but for extremely hot events (e.g. `mousemove`), direct binding may be faster.
239
+
240
+ Rule of thumb: use delegation for `click/input/submit`, and direct handlers for high-frequency events.
241
+
242
+ ---
243
+
244
+ ## Notes
245
+
246
+ * Delegation uses `Element.closest()` internally.
247
+ * In delegated handlers, `this` refers to the matched element.
248
+ * Modern browsers only (uses `Proxy`, `WeakMap`, and modern DOM APIs).
249
+ * All binding methods return a `stop()` function for explicit cleanup.
250
+
251
+ ---
252
+
253
+ ## Low-level API (on / off)
254
+
255
+ If you prefer a minimal, explicit API without fluent modifiers, you can use the core helpers directly.
256
+
257
+ ### `on(el, event, handler)`
258
+
259
+ ### `on(el, event, selector, handler)`
260
+
261
+ Adds a standard or delegated event listener.
262
+ Returns a `stop()` function that removes the listener.
263
+
264
+ ```js
265
+ import { on, off } from 'on-events'
266
+
267
+ function handleKeydown(e) {
268
+ console.log('Pressed:', e.key)
269
+ }
270
+
271
+ const stop = on(window, 'keydown', handleKeydown)
272
+
273
+ stop() // unbinds
274
+ ```
275
+
276
+ ### `off(el, event, handler, [selector])`
277
+
278
+ Removes a previously added listener.
279
+
280
+ ---
281
+
282
+ ## Legacy Alias
283
+
284
+ * `On.once.*` is available as a backward-compatible alias for `On.first.*`
285
+
286
+ ---
287
+
288
+ ## License
289
+
290
+ --{DR.WATT v3.0}--
@@ -0,0 +1,58 @@
1
+ // src/on-events.d.ts
2
+
3
+ export type Stop = () => void
4
+
5
+ export type Handler<E extends Event = Event> = (this: Element, ev: E) => any
6
+ export type DirectHandler<E extends Event = Event> = (ev: E) => any
7
+
8
+ export function on<E extends Event = Event>(
9
+ el: EventTarget,
10
+ event: string,
11
+ handler: DirectHandler<E>
12
+ ): Stop
13
+
14
+ export function on<E extends Event = Event>(
15
+ el: Element | Document,
16
+ event: string,
17
+ selector: string,
18
+ handler: Handler<E>
19
+ ): Stop
20
+
21
+ export function off<E extends Event = Event>(
22
+ el: EventTarget,
23
+ event: string,
24
+ handler: DirectHandler<E>,
25
+ selector?: null
26
+ ): void
27
+
28
+ export function off<E extends Event = Event>(
29
+ el: Element | Document,
30
+ event: string,
31
+ handler: Handler<E>,
32
+ selector?: string
33
+ ): void
34
+
35
+ export interface OnChain {
36
+ // modifiers
37
+ first: OnChain
38
+ once: OnChain
39
+ capture: OnChain
40
+ passive: OnChain
41
+ delegate: OnChain
42
+
43
+ // utilities
44
+ hover(el: Element, enter: (ev: Event) => any, leave: (ev: Event) => any): Stop
45
+ batch(
46
+ el: EventTarget,
47
+ map: Record<
48
+ string,
49
+ ((ev: any) => any) | [string, (ev: any) => any]
50
+ >
51
+ ): Stop
52
+ ready(fn: () => void): void
53
+
54
+ // event binder (unknown event names supported)
55
+ [event: string]: any
56
+ }
57
+
58
+ export const On: OnChain
@@ -0,0 +1,2 @@
1
+ // On-Events - A tiny DOM event utility with sugar.
2
+ var p=new WeakMap;function d(t,c,i,n,e){typeof i=="function"&&(e=n,n=i,i=null);let u=e||void 0,r=i?o=>{let s=o.target instanceof Element?o.target:o.target?.parentElement;if(!s)return;let f=s.closest(i);f&&t.contains(f)&&n.call(f,o)}:n;return t.addEventListener(c,r,u),p.has(t)||p.set(t,[]),p.get(t).push({type:c,cb:n,selector:i,wrapped:r,capture:!!(u&&u.capture)}),()=>L(t,c,n,i)}function L(t,c,i,n=null){let e=p.get(t);if(e){for(let u=e.length;u-- >0;){let r=e[u];r.type===c&&r.cb===i&&(n?r.selector===n:!r.selector)&&(t.removeEventListener(c,r.wrapped,{capture:r.capture}),e.splice(u,1))}e.length||p.delete(t)}}var m=1,E=2,v=4,h=8,O=t=>{if(!(t&(m|E|v)))return;let c={};return t&m&&(c.once=!0),t&E&&(c.capture=!0),t&v&&(c.passive=!0),c},a=(t=0)=>new Proxy(Object.create(null),{get(c,i){let n=String(i);return n==="first"||n==="once"?a(t|m):n==="capture"?a(t|E):n==="passive"?a(t|v):n==="delegate"?a(t|h):n==="hover"?(e,u,r)=>{let o=O(t),s=d(e,"mouseenter",u,o),f=d(e,"mouseleave",r,o);return()=>{s(),f()}}:n==="batch"?(e,u)=>{let r=[];for(let[o,s]of Object.entries(u)){if(typeof s=="function"){r.push(a(t)[o](e,s));continue}if(Array.isArray(s)){let[f,A]=s;r.push(a(t|h)[o](e,f,A))}}return()=>r.forEach(o=>o())}:n==="ready"?e=>{typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e,{once:!0}):e())}:(e,...u)=>{let r=O(t);if(t&h){let[s,f]=u;return d(e,n,s,f,r)}let[o]=u;return d(e,n,o,r)}}}),y=a();y.once=y.first;var g=(t,c,...i)=>d(t,c,...i);export{y as On,L as off,g as on};
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 // normalize args\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 const target = e.target instanceof Element ? e.target : e.target?.parentElement\r\n if (!target) return\r\n const match = target.closest(selector)\r\n if (match && el.contains(match)) cb.call(match, e)\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 listeners.get(el).push({\r\n type,\r\n cb,\r\n selector,\r\n wrapped,\r\n capture: !!(opts && opts.capture), // critical for proper 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 // capture must match for removal\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 tiny + fast\r\nconst ONCE = 1\r\nconst CAPTURE = 2\r\nconst PASSIVE = 4\r\nconst DELEGATE = 8\r\n\r\nconst optsFor = (f) => {\r\n // Avoid allocating options when none are set.\r\n // Note: capture removal is handled by storing capture in registry.\r\n if (!(f & (ONCE | CAPTURE | PASSIVE))) return undefined\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(_t, prop) {\r\n const k = String(prop)\r\n\r\n // modifier chaining\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 // utilities (kept as properties for backwards-compat 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 for (const [event, val] of Object.entries(map)) {\r\n // basic: { click: fn }\r\n if (typeof val === 'function') {\r\n stops.push(makeOn(flags)[event](el, val))\r\n continue\r\n }\r\n // optional delegate batch: { 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 return () => stops.forEach((stop) => stop())\r\n }\r\n }\r\n\r\n if (k === 'ready') {\r\n return (fn) => {\r\n if (typeof document === 'undefined') return\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 // event binder\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// --- 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 }"],
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", "_t", "prop", "k", "enter", "leave", "offIn", "offOut", "map", "stops", "event", "val", "fn", "stop", "args", "handler", "On", "on"]
7
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "on-events",
3
+ "version": "0.0.1",
4
+ "description": "Tiny DOM event utility with composable sugar, delegation, and cleanup.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "./dist/on-events.min.js",
8
+ "module": "./dist/on-events.min.js",
9
+ "types": "./dist/on-events.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/on-events.d.ts",
13
+ "import": "./dist/on-events.min.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "keywords": [
20
+ "dom",
21
+ "events",
22
+ "event-listener",
23
+ "delegate",
24
+ "frontend",
25
+ "browser",
26
+ "javascript",
27
+ "tiny",
28
+ "utility"
29
+ ],
30
+ "author": "DR.WATT",
31
+ "license": "SEE LICENSE IN LICENSE",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/iWhatty/on-event-js"
35
+ },
36
+ "scripts": {
37
+ "test": "vitest",
38
+ "test:run": "vitest run",
39
+ "test:ui": "vitest --ui",
40
+ "test:watch": "vitest --watch",
41
+ "build": "node build.js",
42
+ "prepublishOnly": "npm run build && npm run test:run"
43
+ },
44
+ "devDependencies": {
45
+ "esbuild": "^0.25.3",
46
+ "jsdom": "^28.1.0",
47
+ "vitest": "^4.0.18"
48
+ }
49
+ }