@hypen-space/web 0.2.12 → 0.3.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.
Files changed (44) hide show
  1. package/dist/src/canvas/index.js.map +1 -1
  2. package/dist/src/canvas/renderer.js.map +1 -1
  3. package/dist/src/dom/applicators/effects.js +38 -2
  4. package/dist/src/dom/applicators/effects.js.map +3 -3
  5. package/dist/src/dom/applicators/events.js +280 -397
  6. package/dist/src/dom/applicators/events.js.map +5 -4
  7. package/dist/src/dom/applicators/font.js +94 -5
  8. package/dist/src/dom/applicators/font.js.map +3 -3
  9. package/dist/src/dom/applicators/index.js +590 -425
  10. package/dist/src/dom/applicators/index.js.map +10 -9
  11. package/dist/src/dom/applicators/layout.js +33 -5
  12. package/dist/src/dom/applicators/layout.js.map +3 -3
  13. package/dist/src/dom/applicators/size.js +81 -16
  14. package/dist/src/dom/applicators/size.js.map +3 -3
  15. package/dist/src/dom/components/hypenapp.js +296 -0
  16. package/dist/src/dom/components/hypenapp.js.map +10 -0
  17. package/dist/src/dom/components/index.js +263 -1
  18. package/dist/src/dom/components/index.js.map +5 -4
  19. package/dist/src/dom/element-data.js +140 -0
  20. package/dist/src/dom/element-data.js.map +10 -0
  21. package/dist/src/dom/index.js +857 -430
  22. package/dist/src/dom/index.js.map +13 -11
  23. package/dist/src/dom/renderer.js +857 -430
  24. package/dist/src/dom/renderer.js.map +13 -11
  25. package/dist/src/hypen.js +857 -430
  26. package/dist/src/hypen.js.map +13 -11
  27. package/dist/src/index.js +862 -430
  28. package/dist/src/index.js.map +15 -12
  29. package/package.json +3 -3
  30. package/src/canvas/QUICKSTART.md +5 -7
  31. package/src/canvas/README.md +2 -2
  32. package/src/canvas/renderer.ts +1 -1
  33. package/src/dom/README.md +4 -4
  34. package/src/dom/applicators/effects.ts +45 -1
  35. package/src/dom/applicators/events.ts +348 -537
  36. package/src/dom/applicators/font.ts +127 -2
  37. package/src/dom/applicators/index.ts +117 -7
  38. package/src/dom/applicators/layout.ts +40 -4
  39. package/src/dom/applicators/size.ts +101 -16
  40. package/src/dom/components/hypenapp.ts +348 -0
  41. package/src/dom/components/index.ts +2 -0
  42. package/src/dom/element-data.ts +234 -0
  43. package/src/dom/renderer.ts +12 -9
  44. package/src/index.ts +5 -2
@@ -27,11 +27,105 @@ var __export = (target, all) => {
27
27
  };
28
28
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
29
29
 
30
+ // src/dom/element-data.ts
31
+ import { getElementDisposables } from "@hypen-space/core";
32
+ function getHypenData(element) {
33
+ let data = elementDataMap.get(element);
34
+ if (!data) {
35
+ data = {};
36
+ elementDataMap.set(element, data);
37
+ }
38
+ return data;
39
+ }
40
+ function hasHypenData(element) {
41
+ return elementDataMap.has(element);
42
+ }
43
+ function clearHypenData(element) {
44
+ elementDataMap.delete(element);
45
+ }
46
+ function getEngine(element) {
47
+ return getHypenData(element).engine;
48
+ }
49
+ function setEngine(element, engine) {
50
+ getHypenData(element).engine = engine;
51
+ }
52
+ function findEngine(element) {
53
+ let current = element;
54
+ while (current) {
55
+ const engine = getEngine(current);
56
+ if (engine)
57
+ return engine;
58
+ current = current.parentElement;
59
+ }
60
+ return;
61
+ }
62
+ function getRegisteredEvents(element) {
63
+ const data = getHypenData(element);
64
+ if (!data.registeredEvents) {
65
+ data.registeredEvents = new Set;
66
+ }
67
+ return data.registeredEvents;
68
+ }
69
+ function isEventRegistered(element, eventKey) {
70
+ return getRegisteredEvents(element).has(eventKey);
71
+ }
72
+ function registerEvent(element, eventKey) {
73
+ getRegisteredEvents(element).add(eventKey);
74
+ }
75
+ function unregisterEvent(element, eventKey) {
76
+ getRegisteredEvents(element).delete(eventKey);
77
+ }
78
+ function getKeyTarget(element) {
79
+ return getHypenData(element).keyTarget;
80
+ }
81
+ function setKeyTarget(element, key) {
82
+ getHypenData(element).keyTarget = key;
83
+ }
84
+ function getMeta(element, key) {
85
+ return getHypenData(element).meta?.[key];
86
+ }
87
+ function setMeta(element, key, value) {
88
+ const data = getHypenData(element);
89
+ if (!data.meta) {
90
+ data.meta = {};
91
+ }
92
+ data.meta[key] = value;
93
+ }
94
+ function disposeHypenElement(element) {
95
+ try {
96
+ const disposables = getElementDisposables(element);
97
+ disposables.dispose();
98
+ } catch {}
99
+ clearHypenData(element);
100
+ }
101
+ function getLegacyEngine(element) {
102
+ const engine = getEngine(element);
103
+ if (engine)
104
+ return engine;
105
+ return element[HYPEN_ENGINE_SYMBOL] ?? element.__hypenEngine;
106
+ }
107
+ function setLegacyEngine(element, engine) {
108
+ setEngine(element, engine);
109
+ element.__hypenEngine = engine;
110
+ }
111
+ var elementDataMap, HYPEN_ENGINE_SYMBOL, REGISTERED_EVENTS_SYMBOL, KEY_TARGET_SYMBOL;
112
+ var init_element_data = __esm(() => {
113
+ elementDataMap = new WeakMap;
114
+ HYPEN_ENGINE_SYMBOL = Symbol.for("hypen.engine");
115
+ REGISTERED_EVENTS_SYMBOL = Symbol.for("hypen.registeredEvents");
116
+ KEY_TARGET_SYMBOL = Symbol.for("hypen.keyTarget");
117
+ });
118
+
30
119
  // src/dom/applicators/events.ts
31
120
  var exports_events = {};
32
121
  __export(exports_events, {
33
122
  eventHandlers: () => eventHandlers
34
123
  });
124
+ import {
125
+ getElementDisposables as getElementDisposables2,
126
+ disposableListener,
127
+ disposableTimeout
128
+ } from "@hypen-space/core";
35
129
  function toPlainObject(value) {
36
130
  if (value instanceof Map) {
37
131
  const obj = {};
@@ -77,7 +171,13 @@ function extractActionDetails(value) {
77
171
  }
78
172
  for (const [key, val] of Object.entries(plain)) {
79
173
  if (key !== "0") {
80
- payload[key] = val;
174
+ if (/^\d+$/.test(key) && val && typeof val === "object" && !Array.isArray(val)) {
175
+ for (const [innerKey, innerVal] of Object.entries(val)) {
176
+ payload[innerKey] = innerVal;
177
+ }
178
+ } else {
179
+ payload[key] = val;
180
+ }
81
181
  }
82
182
  }
83
183
  }
@@ -115,420 +215,203 @@ function extractEventData(event, element) {
115
215
  }
116
216
  return data;
117
217
  }
118
- var eventHandlers;
119
- var init_events = __esm(() => {
120
- eventHandlers = {
121
- onClick: (element, value) => {
122
- console.log(`[EventApplicator] onClick called with value:`, value);
123
- const { actionName, payload: customPayload } = extractActionDetails(value);
124
- if (!actionName) {
125
- console.warn(`[EventApplicator] onClick value must be an action reference, got:`, value);
126
- return;
127
- }
128
- const existingListener = element.__hypenClickListener;
129
- if (existingListener) {
130
- element.removeEventListener("click", existingListener);
131
- }
132
- const listener = (event) => {
133
- console.log(`\uD83D\uDD25 [EventApplicator] onClick fired, dispatching action: ${actionName}`);
134
- const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : extractEventData(event, element);
135
- console.log(`[EventApplicator] onClick payload:`, payload);
136
- const engine = element.__hypenEngine;
137
- if (engine) {
138
- engine.dispatchAction(actionName, payload);
139
- } else {
140
- console.warn(`[EventApplicator] No engine attached to element for onClick`);
141
- }
142
- };
143
- element.__hypenClickListener = listener;
144
- element.addEventListener("click", listener);
145
- console.log(`[EventApplicator] onClick handler attached for action: ${actionName}`);
146
- },
147
- onPress: (element, value) => {
148
- eventHandlers.onClick(element, value);
149
- },
150
- onChange: (element, value) => {
151
- const { actionName } = extractActionDetails(value);
152
- if (!actionName) {
153
- console.warn(`[EventApplicator] onChange value must be an action reference starting with @, got:`, value);
154
- return;
155
- }
156
- const existingListener = element.__hypenChangeListener;
157
- if (existingListener) {
158
- element.removeEventListener("change", existingListener);
159
- }
160
- const listener = (event) => {
161
- console.log(`\uD83D\uDD25 [EventApplicator] onChange fired, dispatching action: ${actionName}`);
162
- const payload = extractEventData(event, element);
163
- const engine = element.__hypenEngine;
164
- if (engine) {
165
- engine.dispatchAction(actionName, payload);
166
- } else {
167
- console.warn(`[EventApplicator] No engine attached to element for onChange`);
168
- }
169
- };
170
- element.__hypenChangeListener = listener;
171
- element.addEventListener("change", listener);
172
- console.log(`[EventApplicator] onChange handler attached for action: ${actionName}`);
173
- },
174
- onSubmit: (element, value) => {
175
- const { actionName } = extractActionDetails(value);
176
- if (!actionName) {
177
- console.warn(`[EventApplicator] onSubmit value must be an action reference starting with @, got:`, value);
218
+ function createEventHandler(eventType, options = {}) {
219
+ return (element, value) => {
220
+ const { actionName, payload: customPayload } = extractActionDetails(value);
221
+ if (!actionName) {
222
+ console.warn(`[EventApplicator] ${eventType} requires an action reference starting with @, got:`, value);
223
+ return;
224
+ }
225
+ const disposables = getElementDisposables2(element);
226
+ const eventKey = `${eventType}:${actionName}`;
227
+ if (getRegisteredEvents(element).has(eventKey)) {
228
+ return;
229
+ }
230
+ registerEvent(element, eventKey);
231
+ let throttleTimer = null;
232
+ const listener = (event) => {
233
+ if (options.throttleMs && throttleTimer) {
178
234
  return;
179
235
  }
180
- const existingListener = element.__hypenSubmitListener;
181
- if (existingListener) {
182
- element.removeEventListener("submit", existingListener);
236
+ if (options.throttleMs) {
237
+ throttleTimer = disposableTimeout(() => {
238
+ throttleTimer = null;
239
+ }, options.throttleMs);
183
240
  }
184
- const listener = (event) => {
185
- console.log(`\uD83D\uDD25 [EventApplicator] onSubmit fired, dispatching action: ${actionName}`);
241
+ if (options.preventDefault) {
186
242
  event.preventDefault();
187
- const payload = extractEventData(event, element);
188
- const engine = element.__hypenEngine;
189
- if (engine) {
190
- engine.dispatchAction(actionName, payload);
191
- } else {
192
- console.warn(`[EventApplicator] No engine attached to element for onSubmit`);
193
- }
194
- };
195
- element.__hypenSubmitListener = listener;
196
- element.addEventListener("submit", listener);
197
- console.log(`[EventApplicator] onSubmit handler attached for action: ${actionName}`);
198
- },
199
- onInput: (element, value) => {
200
- console.log(`[EventApplicator] onInput called with value:`, value);
201
- const { actionName } = extractActionDetails(value);
202
- if (!actionName) {
203
- console.warn(`[EventApplicator] onInput value must be an action reference starting with @, got:`, value);
204
- return;
205
- }
206
- const existingListener = element.__hypenInputListener;
207
- if (existingListener) {
208
- element.removeEventListener("input", existingListener);
209
- }
210
- const listener = (event) => {
211
- console.log(`\uD83D\uDD25 [EventApplicator] onInput fired, dispatching action: ${actionName}`);
212
- const target = event.target;
213
- const payload = {
214
- type: event.type,
215
- timestamp: Date.now(),
216
- value: target.value,
217
- input: target.value
218
- };
219
- console.log(`[EventApplicator] onInput payload:`, payload);
220
- const engine = element.__hypenEngine;
221
- if (engine) {
222
- engine.dispatchAction(actionName, payload);
223
- } else {
224
- console.warn(`[EventApplicator] No engine attached to element for onInput`);
225
- }
226
- };
227
- element.__hypenInputListener = listener;
228
- element.addEventListener("input", listener);
229
- console.log(`[EventApplicator] onInput handler attached for action: ${actionName}`);
230
- },
231
- onKey: (element, value) => {
232
- console.log(`[EventApplicator] onKey called with value:`, value);
233
- const { actionName } = extractActionDetails(value);
234
- if (actionName) {
235
- const existingListener = element.__hypenKeyListener;
236
- if (existingListener) {
237
- element.removeEventListener("keydown", existingListener);
238
- }
239
- const listener = (event) => {
240
- if (event.key === "Enter") {
241
- console.log(`\uD83D\uDD25 [EventApplicator] onKey fired (Enter), dispatching action: ${actionName}`);
242
- event.preventDefault();
243
- const target = event.target;
244
- const payload = {
245
- type: event.type,
246
- timestamp: Date.now(),
247
- key: event.key,
248
- code: event.code,
249
- value: target.value,
250
- input: target.value,
251
- ctrlKey: event.ctrlKey,
252
- shiftKey: event.shiftKey,
253
- altKey: event.altKey,
254
- metaKey: event.metaKey
255
- };
256
- const engine = element.__hypenEngine;
257
- if (engine) {
258
- engine.dispatchAction(actionName, payload);
259
- } else {
260
- console.warn(`[EventApplicator] No engine attached to element for onKey`);
261
- }
262
- }
263
- };
264
- element.__hypenKeyListener = listener;
265
- element.addEventListener("keydown", listener);
266
- console.log(`[EventApplicator] onKey handler attached for action: ${actionName} (triggers on Enter)`);
267
- } else {
268
- console.warn(`[EventApplicator] onKey value must be an action reference starting with @, got: ${value}`);
269
- }
270
- },
271
- "onKey.key": (element, keyValue) => {
272
- console.log(`[EventApplicator] onKey.key called with value:`, keyValue);
273
- element.__hypenKeyTarget = keyValue;
274
- },
275
- "onKey.action": (element, value) => {
276
- console.log(`[EventApplicator] onKey.action called with value:`, value);
277
- const { actionName } = extractActionDetails(value);
278
- if (actionName) {
279
- const targetKey = element.__hypenKeyTarget || "Enter";
280
- const existingListener = element.__hypenKeyListener;
281
- if (existingListener) {
282
- element.removeEventListener("keydown", existingListener);
283
- }
284
- const listener = (event) => {
285
- const keyToMatch = targetKey.toLowerCase() === "return" ? "Enter" : targetKey;
286
- if (event.key === keyToMatch) {
287
- console.log(`\uD83D\uDD25 [EventApplicator] onKey fired (${keyToMatch}), dispatching action: ${actionName}`);
288
- event.preventDefault();
289
- const target = event.target;
290
- const payload = {
291
- type: event.type,
292
- timestamp: Date.now(),
293
- key: event.key,
294
- code: event.code,
295
- value: target.value,
296
- input: target.value,
297
- ctrlKey: event.ctrlKey,
298
- shiftKey: event.shiftKey,
299
- altKey: event.altKey,
300
- metaKey: event.metaKey
301
- };
302
- const engine = element.__hypenEngine;
303
- if (engine) {
304
- engine.dispatchAction(actionName, payload);
305
- }
306
- }
307
- };
308
- element.__hypenKeyListener = listener;
309
- element.addEventListener("keydown", listener);
310
- console.log(`[EventApplicator] onKey handler attached for action: ${actionName} on key: ${targetKey}`);
311
- }
312
- },
313
- onScroll: (element, value) => {
314
- console.log(`[EventApplicator] onScroll called with value:`, value);
315
- const { actionName } = extractActionDetails(value);
316
- if (actionName) {
317
- const existingListener = element.__hypenScrollListener;
318
- if (existingListener) {
319
- element.removeEventListener("scroll", existingListener);
320
- }
321
- let throttleTimer = null;
322
- const listener = (event) => {
323
- if (throttleTimer)
324
- return;
325
- throttleTimer = setTimeout(() => {
326
- throttleTimer = null;
327
- }, 100);
328
- const target = event.target;
329
- const scrollTop = target.scrollTop;
330
- const scrollHeight = target.scrollHeight;
331
- const clientHeight = target.clientHeight;
332
- const scrollPercentage = scrollTop / (scrollHeight - clientHeight) * 100;
333
- const nearBottom = scrollHeight - scrollTop - clientHeight < 100 || scrollPercentage > 90;
334
- console.log(`\uD83D\uDD25 [EventApplicator] onScroll fired, scrollTop: ${scrollTop}, nearBottom: ${nearBottom}`);
335
- const payload = {
336
- type: "scroll",
337
- timestamp: Date.now(),
338
- scrollTop,
339
- scrollLeft: target.scrollLeft,
340
- scrollHeight,
341
- scrollWidth: target.scrollWidth,
342
- clientHeight,
343
- clientWidth: target.clientWidth,
344
- scrollPercentage: Math.round(scrollPercentage),
345
- nearBottom,
346
- atBottom: scrollHeight - scrollTop === clientHeight,
347
- atTop: scrollTop === 0
348
- };
349
- const engine = element.__hypenEngine;
350
- if (engine) {
351
- engine.dispatchAction(actionName, payload);
352
- } else {
353
- console.warn(`[EventApplicator] No engine attached to element for onScroll`);
354
- }
355
- };
356
- element.__hypenScrollListener = listener;
357
- element.addEventListener("scroll", listener, { passive: true });
358
- console.log(`[EventApplicator] onScroll handler attached for action: ${actionName}`);
359
- } else {
360
- console.warn(`[EventApplicator] onScroll value must be an action reference starting with @, got: ${value}`);
361
243
  }
362
- },
363
- onLongClick: (element, value) => {
364
- console.log(`[EventApplicator] onLongClick called with value:`, value);
365
- const { actionName, payload: customPayload } = extractActionDetails(value);
366
- if (!actionName) {
367
- console.warn(`[EventApplicator] onLongClick value must be an action reference, got:`, value);
368
- return;
369
- }
370
- const existingDownListener = element.__hypenLongClickDownListener;
371
- const existingUpListener = element.__hypenLongClickUpListener;
372
- if (existingDownListener) {
373
- element.removeEventListener("pointerdown", existingDownListener);
244
+ const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : options.extractPayload ? options.extractPayload(event, element) : extractEventData(event, element);
245
+ const engine = getEngine(element);
246
+ if (engine) {
247
+ engine.dispatchAction(actionName, payload);
374
248
  }
375
- if (existingUpListener) {
376
- element.removeEventListener("pointerup", existingUpListener);
377
- element.removeEventListener("pointerleave", existingUpListener);
249
+ };
250
+ disposables.add(disposableListener(element, eventType, listener, {
251
+ passive: options.passive
252
+ }));
253
+ disposables.addCallback(() => {
254
+ unregisterEvent(element, eventKey);
255
+ if (throttleTimer) {
256
+ throttleTimer.dispose();
378
257
  }
379
- let longClickTimer = null;
380
- const LONG_CLICK_THRESHOLD = 500;
381
- const downListener = (event) => {
382
- longClickTimer = setTimeout(() => {
383
- console.log(`\uD83D\uDD25 [EventApplicator] onLongClick fired, dispatching action: ${actionName}`);
384
- const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : {
385
- type: "longclick",
386
- timestamp: Date.now(),
387
- clientX: event.clientX,
388
- clientY: event.clientY
389
- };
390
- const engine = element.__hypenEngine;
391
- if (engine) {
392
- engine.dispatchAction(actionName, payload);
393
- } else {
394
- console.warn(`[EventApplicator] No engine attached to element for onLongClick`);
395
- }
396
- longClickTimer = null;
397
- }, LONG_CLICK_THRESHOLD);
398
- };
399
- const upListener = () => {
400
- if (longClickTimer) {
401
- clearTimeout(longClickTimer);
402
- longClickTimer = null;
403
- }
404
- };
405
- element.__hypenLongClickDownListener = downListener;
406
- element.__hypenLongClickUpListener = upListener;
407
- element.addEventListener("pointerdown", downListener);
408
- element.addEventListener("pointerup", upListener);
409
- element.addEventListener("pointerleave", upListener);
410
- console.log(`[EventApplicator] onLongClick handler attached for action: ${actionName}`);
411
- },
412
- onFocus: (element, value) => {
413
- console.log(`[EventApplicator] onFocus called with value:`, value);
414
- const { actionName, payload: customPayload } = extractActionDetails(value);
415
- if (!actionName) {
416
- console.warn(`[EventApplicator] onFocus value must be an action reference, got:`, value);
258
+ });
259
+ };
260
+ }
261
+ function createKeyHandler(defaultKey = "Enter") {
262
+ return (element, value) => {
263
+ const { actionName, payload: customPayload } = extractActionDetails(value);
264
+ if (!actionName) {
265
+ console.warn(`[EventApplicator] onKey requires an action reference starting with @, got:`, value);
266
+ return;
267
+ }
268
+ const disposables = getElementDisposables2(element);
269
+ const eventKey = `keydown:${actionName}:${defaultKey}`;
270
+ if (getRegisteredEvents(element).has(eventKey)) {
271
+ return;
272
+ }
273
+ registerEvent(element, eventKey);
274
+ const targetKey = getKeyTarget(element) || defaultKey;
275
+ const keyToMatch = targetKey.toLowerCase() === "return" ? "Enter" : targetKey;
276
+ const listener = (event) => {
277
+ const keyEvent = event;
278
+ if (keyEvent.key !== keyToMatch) {
417
279
  return;
418
280
  }
419
- const existingListener = element.__hypenFocusListener;
420
- if (existingListener) {
421
- element.removeEventListener("focus", existingListener);
422
- }
423
- const listener = (event) => {
424
- console.log(`\uD83D\uDD25 [EventApplicator] onFocus fired, dispatching action: ${actionName}`);
425
- const target = event.target;
426
- const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : {
427
- type: "focus",
428
- timestamp: Date.now(),
429
- value: target.value ?? undefined
430
- };
431
- const engine = element.__hypenEngine;
432
- if (engine) {
433
- engine.dispatchAction(actionName, payload);
434
- } else {
435
- console.warn(`[EventApplicator] No engine attached to element for onFocus`);
436
- }
281
+ event.preventDefault();
282
+ const target = event.target;
283
+ const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : {
284
+ type: event.type,
285
+ timestamp: Date.now(),
286
+ key: keyEvent.key,
287
+ code: keyEvent.code,
288
+ value: target.value,
289
+ input: target.value,
290
+ ctrlKey: keyEvent.ctrlKey,
291
+ shiftKey: keyEvent.shiftKey,
292
+ altKey: keyEvent.altKey,
293
+ metaKey: keyEvent.metaKey
437
294
  };
438
- element.__hypenFocusListener = listener;
439
- element.addEventListener("focus", listener);
440
- console.log(`[EventApplicator] onFocus handler attached for action: ${actionName}`);
441
- },
442
- onBlur: (element, value) => {
443
- console.log(`[EventApplicator] onBlur called with value:`, value);
444
- const { actionName, payload: customPayload } = extractActionDetails(value);
445
- if (!actionName) {
446
- console.warn(`[EventApplicator] onBlur value must be an action reference, got:`, value);
447
- return;
448
- }
449
- const existingListener = element.__hypenBlurListener;
450
- if (existingListener) {
451
- element.removeEventListener("blur", existingListener);
295
+ const engine = getEngine(element);
296
+ if (engine) {
297
+ engine.dispatchAction(actionName, payload);
452
298
  }
453
- const listener = (event) => {
454
- console.log(`\uD83D\uDD25 [EventApplicator] onBlur fired, dispatching action: ${actionName}`);
455
- const target = event.target;
299
+ };
300
+ disposables.add(disposableListener(element, "keydown", listener));
301
+ disposables.addCallback(() => {
302
+ unregisterEvent(element, eventKey);
303
+ });
304
+ };
305
+ }
306
+ function createLongClickHandler(thresholdMs = 500) {
307
+ return (element, value) => {
308
+ const { actionName, payload: customPayload } = extractActionDetails(value);
309
+ if (!actionName) {
310
+ console.warn(`[EventApplicator] onLongClick requires an action reference starting with @, got:`, value);
311
+ return;
312
+ }
313
+ const disposables = getElementDisposables2(element);
314
+ const eventKey = `longclick:${actionName}`;
315
+ if (getRegisteredEvents(element).has(eventKey)) {
316
+ return;
317
+ }
318
+ registerEvent(element, eventKey);
319
+ let longClickTimer = null;
320
+ const downListener = (event) => {
321
+ const pointerEvent = event;
322
+ longClickTimer = disposableTimeout(() => {
456
323
  const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : {
457
- type: "blur",
324
+ type: "longclick",
458
325
  timestamp: Date.now(),
459
- value: target.value ?? undefined
326
+ clientX: pointerEvent.clientX,
327
+ clientY: pointerEvent.clientY
460
328
  };
461
- const engine = element.__hypenEngine;
329
+ const engine = getEngine(element);
462
330
  if (engine) {
463
331
  engine.dispatchAction(actionName, payload);
464
- } else {
465
- console.warn(`[EventApplicator] No engine attached to element for onBlur`);
466
332
  }
467
- };
468
- element.__hypenBlurListener = listener;
469
- element.addEventListener("blur", listener);
470
- console.log(`[EventApplicator] onBlur handler attached for action: ${actionName}`);
471
- },
472
- onMouseEnter: (element, value) => {
473
- console.log(`[EventApplicator] onMouseEnter called with value:`, value);
474
- const { actionName, payload: customPayload } = extractActionDetails(value);
475
- if (!actionName) {
476
- console.warn(`[EventApplicator] onMouseEnter value must be an action reference, got:`, value);
477
- return;
478
- }
479
- const existingListener = element.__hypenMouseEnterListener;
480
- if (existingListener) {
481
- element.removeEventListener("mouseenter", existingListener);
333
+ longClickTimer = null;
334
+ }, thresholdMs);
335
+ };
336
+ const cancelListener = () => {
337
+ if (longClickTimer) {
338
+ longClickTimer.dispose();
339
+ longClickTimer = null;
482
340
  }
483
- const listener = (event) => {
484
- console.log(`\uD83D\uDD25 [EventApplicator] onMouseEnter fired, dispatching action: ${actionName}`);
485
- const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : {
486
- type: "mouseenter",
487
- timestamp: Date.now(),
488
- clientX: event.clientX,
489
- clientY: event.clientY
490
- };
491
- const engine = element.__hypenEngine;
492
- if (engine) {
493
- engine.dispatchAction(actionName, payload);
494
- } else {
495
- console.warn(`[EventApplicator] No engine attached to element for onMouseEnter`);
496
- }
497
- };
498
- element.__hypenMouseEnterListener = listener;
499
- element.addEventListener("mouseenter", listener);
500
- console.log(`[EventApplicator] onMouseEnter handler attached for action: ${actionName}`);
341
+ };
342
+ disposables.add(disposableListener(element, "pointerdown", downListener));
343
+ disposables.add(disposableListener(element, "pointerup", cancelListener));
344
+ disposables.add(disposableListener(element, "pointerleave", cancelListener));
345
+ disposables.addCallback(() => {
346
+ unregisterEvent(element, eventKey);
347
+ cancelListener();
348
+ });
349
+ };
350
+ }
351
+ var inputPayload = (event, element) => {
352
+ const target = element;
353
+ return {
354
+ type: event.type,
355
+ timestamp: Date.now(),
356
+ value: target.value,
357
+ input: target.value
358
+ };
359
+ }, scrollPayload = (_event, element) => {
360
+ const scrollTop = element.scrollTop;
361
+ const scrollHeight = element.scrollHeight;
362
+ const clientHeight = element.clientHeight;
363
+ const scrollPercentage = scrollHeight - clientHeight > 0 ? scrollTop / (scrollHeight - clientHeight) * 100 : 0;
364
+ const nearBottom = scrollHeight - scrollTop - clientHeight < 100 || scrollPercentage > 90;
365
+ return {
366
+ type: "scroll",
367
+ timestamp: Date.now(),
368
+ scrollTop,
369
+ scrollLeft: element.scrollLeft,
370
+ scrollHeight,
371
+ scrollWidth: element.scrollWidth,
372
+ clientHeight,
373
+ clientWidth: element.clientWidth,
374
+ scrollPercentage: Math.round(scrollPercentage),
375
+ nearBottom,
376
+ atBottom: scrollHeight - scrollTop === clientHeight,
377
+ atTop: scrollTop === 0
378
+ };
379
+ }, focusPayload = (event, element) => ({
380
+ type: event.type,
381
+ timestamp: Date.now(),
382
+ value: element.value ?? undefined
383
+ }), mousePayload = (event, _element) => {
384
+ const mouseEvent = event;
385
+ return {
386
+ type: event.type,
387
+ timestamp: Date.now(),
388
+ clientX: mouseEvent.clientX,
389
+ clientY: mouseEvent.clientY
390
+ };
391
+ }, eventHandlers;
392
+ var init_events = __esm(() => {
393
+ init_element_data();
394
+ eventHandlers = {
395
+ onClick: createEventHandler("click"),
396
+ onPress: createEventHandler("click"),
397
+ onChange: createEventHandler("change"),
398
+ onSubmit: createEventHandler("submit", { preventDefault: true }),
399
+ onInput: createEventHandler("input", { extractPayload: inputPayload }),
400
+ onKey: createKeyHandler("Enter"),
401
+ "onKey.key": (element, value) => {
402
+ setKeyTarget(element, String(value));
501
403
  },
502
- onMouseLeave: (element, value) => {
503
- console.log(`[EventApplicator] onMouseLeave called with value:`, value);
504
- const { actionName, payload: customPayload } = extractActionDetails(value);
505
- if (!actionName) {
506
- console.warn(`[EventApplicator] onMouseLeave value must be an action reference, got:`, value);
507
- return;
508
- }
509
- const existingListener = element.__hypenMouseLeaveListener;
510
- if (existingListener) {
511
- element.removeEventListener("mouseleave", existingListener);
512
- }
513
- const listener = (event) => {
514
- console.log(`\uD83D\uDD25 [EventApplicator] onMouseLeave fired, dispatching action: ${actionName}`);
515
- const payload = Object.keys(customPayload).length > 0 ? { ...customPayload } : {
516
- type: "mouseleave",
517
- timestamp: Date.now(),
518
- clientX: event.clientX,
519
- clientY: event.clientY
520
- };
521
- const engine = element.__hypenEngine;
522
- if (engine) {
523
- engine.dispatchAction(actionName, payload);
524
- } else {
525
- console.warn(`[EventApplicator] No engine attached to element for onMouseLeave`);
526
- }
527
- };
528
- element.__hypenMouseLeaveListener = listener;
529
- element.addEventListener("mouseleave", listener);
530
- console.log(`[EventApplicator] onMouseLeave handler attached for action: ${actionName}`);
531
- }
404
+ "onKey.action": createKeyHandler("Enter"),
405
+ onScroll: createEventHandler("scroll", {
406
+ throttleMs: 100,
407
+ passive: true,
408
+ extractPayload: scrollPayload
409
+ }),
410
+ onLongClick: createLongClickHandler(500),
411
+ onFocus: createEventHandler("focus", { extractPayload: focusPayload }),
412
+ onBlur: createEventHandler("blur", { extractPayload: focusPayload }),
413
+ onMouseEnter: createEventHandler("mouseenter", { extractPayload: mousePayload }),
414
+ onMouseLeave: createEventHandler("mouseleave", { extractPayload: mousePayload })
532
415
  };
533
416
  });
534
417
  init_events();
@@ -537,4 +420,4 @@ export {
537
420
  eventHandlers
538
421
  };
539
422
 
540
- //# debugId=86E1367389759DD764756E2164756E21
423
+ //# debugId=436C6B268F7401DA64756E2164756E21