@hypen-space/web 0.2.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.
Files changed (195) hide show
  1. package/dist/chunk-2s02mkzs.js +32 -0
  2. package/dist/chunk-2s02mkzs.js.map +9 -0
  3. package/dist/src/canvas/accessibility.js +152 -0
  4. package/dist/src/canvas/accessibility.js.map +10 -0
  5. package/dist/src/canvas/events.js +198 -0
  6. package/dist/src/canvas/events.js.map +10 -0
  7. package/dist/src/canvas/index.js +28 -0
  8. package/dist/src/canvas/index.js.map +9 -0
  9. package/dist/src/canvas/input.js +132 -0
  10. package/dist/src/canvas/input.js.map +10 -0
  11. package/dist/src/canvas/layout.js +309 -0
  12. package/dist/src/canvas/layout.js.map +10 -0
  13. package/dist/src/canvas/paint.js +878 -0
  14. package/dist/src/canvas/paint.js.map +10 -0
  15. package/dist/src/canvas/renderer.js +276 -0
  16. package/dist/src/canvas/renderer.js.map +10 -0
  17. package/dist/src/canvas/text.js +118 -0
  18. package/dist/src/canvas/text.js.map +10 -0
  19. package/dist/src/canvas/types.js +2 -0
  20. package/dist/src/canvas/types.js.map +9 -0
  21. package/dist/src/canvas/utils.js +139 -0
  22. package/dist/src/canvas/utils.js.map +10 -0
  23. package/dist/src/dom/applicators/advanced-layout.js +111 -0
  24. package/dist/src/dom/applicators/advanced-layout.js.map +10 -0
  25. package/dist/src/dom/applicators/background.js +54 -0
  26. package/dist/src/dom/applicators/background.js.map +10 -0
  27. package/dist/src/dom/applicators/border.js +33 -0
  28. package/dist/src/dom/applicators/border.js.map +10 -0
  29. package/dist/src/dom/applicators/color.js +36 -0
  30. package/dist/src/dom/applicators/color.js.map +10 -0
  31. package/dist/src/dom/applicators/display.js +57 -0
  32. package/dist/src/dom/applicators/display.js.map +10 -0
  33. package/dist/src/dom/applicators/effects.js +89 -0
  34. package/dist/src/dom/applicators/effects.js.map +10 -0
  35. package/dist/src/dom/applicators/events.js +518 -0
  36. package/dist/src/dom/applicators/events.js.map +10 -0
  37. package/dist/src/dom/applicators/font.js +39 -0
  38. package/dist/src/dom/applicators/font.js.map +10 -0
  39. package/dist/src/dom/applicators/index.js +296 -0
  40. package/dist/src/dom/applicators/index.js.map +10 -0
  41. package/dist/src/dom/applicators/layout.js +86 -0
  42. package/dist/src/dom/applicators/layout.js.map +10 -0
  43. package/dist/src/dom/applicators/margin.js +32 -0
  44. package/dist/src/dom/applicators/margin.js.map +10 -0
  45. package/dist/src/dom/applicators/padding.js +35 -0
  46. package/dist/src/dom/applicators/padding.js.map +10 -0
  47. package/dist/src/dom/applicators/size.js +42 -0
  48. package/dist/src/dom/applicators/size.js.map +10 -0
  49. package/dist/src/dom/applicators/transform.js +92 -0
  50. package/dist/src/dom/applicators/transform.js.map +10 -0
  51. package/dist/src/dom/applicators/transition.js +66 -0
  52. package/dist/src/dom/applicators/transition.js.map +10 -0
  53. package/dist/src/dom/applicators/typography.js +87 -0
  54. package/dist/src/dom/applicators/typography.js.map +10 -0
  55. package/dist/src/dom/canvas/index.js +50 -0
  56. package/dist/src/dom/canvas/index.js.map +10 -0
  57. package/dist/src/dom/components/audio.js +48 -0
  58. package/dist/src/dom/components/audio.js.map +10 -0
  59. package/dist/src/dom/components/avatar.js +58 -0
  60. package/dist/src/dom/components/avatar.js.map +10 -0
  61. package/dist/src/dom/components/badge.js +55 -0
  62. package/dist/src/dom/components/badge.js.map +10 -0
  63. package/dist/src/dom/components/button.js +29 -0
  64. package/dist/src/dom/components/button.js.map +10 -0
  65. package/dist/src/dom/components/card.js +33 -0
  66. package/dist/src/dom/components/card.js.map +10 -0
  67. package/dist/src/dom/components/center.js +32 -0
  68. package/dist/src/dom/components/center.js.map +10 -0
  69. package/dist/src/dom/components/checkbox.js +54 -0
  70. package/dist/src/dom/components/checkbox.js.map +10 -0
  71. package/dist/src/dom/components/column.js +31 -0
  72. package/dist/src/dom/components/column.js.map +10 -0
  73. package/dist/src/dom/components/container.js +29 -0
  74. package/dist/src/dom/components/container.js.map +10 -0
  75. package/dist/src/dom/components/divider.js +45 -0
  76. package/dist/src/dom/components/divider.js.map +10 -0
  77. package/dist/src/dom/components/grid.js +44 -0
  78. package/dist/src/dom/components/grid.js.map +10 -0
  79. package/dist/src/dom/components/heading.js +47 -0
  80. package/dist/src/dom/components/heading.js.map +10 -0
  81. package/dist/src/dom/components/image.js +39 -0
  82. package/dist/src/dom/components/image.js.map +10 -0
  83. package/dist/src/dom/components/index.js +217 -0
  84. package/dist/src/dom/components/index.js.map +10 -0
  85. package/dist/src/dom/components/input.js +41 -0
  86. package/dist/src/dom/components/input.js.map +10 -0
  87. package/dist/src/dom/components/link.js +42 -0
  88. package/dist/src/dom/components/link.js.map +10 -0
  89. package/dist/src/dom/components/list.js +42 -0
  90. package/dist/src/dom/components/list.js.map +10 -0
  91. package/dist/src/dom/components/paragraph.js +35 -0
  92. package/dist/src/dom/components/paragraph.js.map +10 -0
  93. package/dist/src/dom/components/progressbar.js +57 -0
  94. package/dist/src/dom/components/progressbar.js.map +10 -0
  95. package/dist/src/dom/components/route.js +44 -0
  96. package/dist/src/dom/components/route.js.map +10 -0
  97. package/dist/src/dom/components/router.js +33 -0
  98. package/dist/src/dom/components/router.js.map +10 -0
  99. package/dist/src/dom/components/row.js +31 -0
  100. package/dist/src/dom/components/row.js.map +10 -0
  101. package/dist/src/dom/components/select.js +57 -0
  102. package/dist/src/dom/components/select.js.map +10 -0
  103. package/dist/src/dom/components/slider.js +48 -0
  104. package/dist/src/dom/components/slider.js.map +10 -0
  105. package/dist/src/dom/components/spacer.js +30 -0
  106. package/dist/src/dom/components/spacer.js.map +10 -0
  107. package/dist/src/dom/components/spinner.js +65 -0
  108. package/dist/src/dom/components/spinner.js.map +10 -0
  109. package/dist/src/dom/components/stack.js +45 -0
  110. package/dist/src/dom/components/stack.js.map +10 -0
  111. package/dist/src/dom/components/switch.js +83 -0
  112. package/dist/src/dom/components/switch.js.map +10 -0
  113. package/dist/src/dom/components/text.js +37 -0
  114. package/dist/src/dom/components/text.js.map +10 -0
  115. package/dist/src/dom/components/textarea.js +51 -0
  116. package/dist/src/dom/components/textarea.js.map +10 -0
  117. package/dist/src/dom/components/video.js +51 -0
  118. package/dist/src/dom/components/video.js.map +10 -0
  119. package/dist/src/dom/debug.js +170 -0
  120. package/dist/src/dom/debug.js.map +10 -0
  121. package/dist/src/dom/events.js +112 -0
  122. package/dist/src/dom/events.js.map +10 -0
  123. package/dist/src/dom/index.js +73 -0
  124. package/dist/src/dom/index.js.map +9 -0
  125. package/dist/src/dom/renderer.js +277 -0
  126. package/dist/src/dom/renderer.js.map +10 -0
  127. package/dist/src/index.js +89 -0
  128. package/dist/src/index.js.map +9 -0
  129. package/package.json +84 -0
  130. package/src/canvas/QUICKSTART.md +421 -0
  131. package/src/canvas/README.md +376 -0
  132. package/src/canvas/accessibility.ts +218 -0
  133. package/src/canvas/events.ts +307 -0
  134. package/src/canvas/index.ts +35 -0
  135. package/src/canvas/input.ts +210 -0
  136. package/src/canvas/layout.ts +401 -0
  137. package/src/canvas/paint.ts +1321 -0
  138. package/src/canvas/renderer.ts +422 -0
  139. package/src/canvas/text.ts +182 -0
  140. package/src/canvas/types.ts +137 -0
  141. package/src/canvas/utils.ts +218 -0
  142. package/src/dom/README.md +265 -0
  143. package/src/dom/applicators/advanced-layout.ts +128 -0
  144. package/src/dom/applicators/background.ts +50 -0
  145. package/src/dom/applicators/border.ts +19 -0
  146. package/src/dom/applicators/color.ts +23 -0
  147. package/src/dom/applicators/display.ts +54 -0
  148. package/src/dom/applicators/effects.ts +97 -0
  149. package/src/dom/applicators/events.ts +689 -0
  150. package/src/dom/applicators/font.ts +27 -0
  151. package/src/dom/applicators/index.ts +354 -0
  152. package/src/dom/applicators/layout.ts +92 -0
  153. package/src/dom/applicators/margin.ts +18 -0
  154. package/src/dom/applicators/padding.ts +18 -0
  155. package/src/dom/applicators/size.ts +31 -0
  156. package/src/dom/applicators/transform.ts +93 -0
  157. package/src/dom/applicators/transition.ts +65 -0
  158. package/src/dom/applicators/typography.ts +91 -0
  159. package/src/dom/canvas/index.ts +60 -0
  160. package/src/dom/components/audio.ts +45 -0
  161. package/src/dom/components/avatar.ts +49 -0
  162. package/src/dom/components/badge.ts +45 -0
  163. package/src/dom/components/button.ts +13 -0
  164. package/src/dom/components/card.ts +19 -0
  165. package/src/dom/components/center.ts +16 -0
  166. package/src/dom/components/checkbox.ts +54 -0
  167. package/src/dom/components/column.ts +15 -0
  168. package/src/dom/components/container.ts +13 -0
  169. package/src/dom/components/divider.ts +37 -0
  170. package/src/dom/components/grid.ts +40 -0
  171. package/src/dom/components/heading.ts +41 -0
  172. package/src/dom/components/image.ts +27 -0
  173. package/src/dom/components/index.ts +115 -0
  174. package/src/dom/components/input.ts +29 -0
  175. package/src/dom/components/link.ts +35 -0
  176. package/src/dom/components/list.ts +30 -0
  177. package/src/dom/components/paragraph.ts +23 -0
  178. package/src/dom/components/progressbar.ts +51 -0
  179. package/src/dom/components/route.ts +37 -0
  180. package/src/dom/components/router.ts +22 -0
  181. package/src/dom/components/row.ts +15 -0
  182. package/src/dom/components/select.ts +56 -0
  183. package/src/dom/components/slider.ts +45 -0
  184. package/src/dom/components/spacer.ts +16 -0
  185. package/src/dom/components/spinner.ts +60 -0
  186. package/src/dom/components/stack.ts +34 -0
  187. package/src/dom/components/switch.ts +86 -0
  188. package/src/dom/components/text.ts +24 -0
  189. package/src/dom/components/textarea.ts +50 -0
  190. package/src/dom/components/video.ts +50 -0
  191. package/src/dom/debug.ts +247 -0
  192. package/src/dom/events.ts +168 -0
  193. package/src/dom/index.ts +11 -0
  194. package/src/dom/renderer.ts +327 -0
  195. package/src/index.ts +56 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Debug utilities for DOM rendering visualization
3
+ *
4
+ * Provides heatmap overlays to visualize re-renders
5
+ */
6
+
7
+ export interface DebugConfig {
8
+ /** Enable debug mode */
9
+ enabled: boolean;
10
+ /** Show heatmap overlays on re-renders */
11
+ showHeatmap: boolean;
12
+ /** Increment per re-render (default: 5%) */
13
+ heatmapIncrement: number;
14
+ /** Maximum opacity for heatmap (default: 0.8) */
15
+ maxOpacity: number;
16
+ /** Fade out duration in ms (0 to disable) */
17
+ fadeOutDuration: number;
18
+ }
19
+
20
+ export const defaultDebugConfig: DebugConfig = {
21
+ enabled: false,
22
+ showHeatmap: true,
23
+ heatmapIncrement: 5,
24
+ maxOpacity: 0.8,
25
+ fadeOutDuration: 2000,
26
+ };
27
+
28
+ /**
29
+ * Tracks re-render counts for each element
30
+ */
31
+ export class RerenderTracker {
32
+ private renderCounts = new Map<string, number>();
33
+ private overlays = new Map<string, HTMLDivElement>();
34
+ private config: DebugConfig;
35
+
36
+ constructor(config: DebugConfig = defaultDebugConfig) {
37
+ this.config = config;
38
+ }
39
+
40
+ /**
41
+ * Update the configuration
42
+ */
43
+ setConfig(config: Partial<DebugConfig>): void {
44
+ this.config = { ...this.config, ...config };
45
+
46
+ // If debug mode is disabled, clean up all overlays
47
+ if (!this.config.enabled) {
48
+ this.cleanup();
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Track a re-render for an element
54
+ */
55
+ trackRerender(id: string, element: HTMLElement, patchType: string): void {
56
+ if (!this.config.enabled || !this.config.showHeatmap) {
57
+ return;
58
+ }
59
+
60
+ console.log(`๐Ÿ”ฅ [Debug] Tracking re-render: ${id} - ${patchType}`);
61
+
62
+ // Increment render count
63
+ const currentCount = this.renderCounts.get(id) || 0;
64
+ const newCount = currentCount + 1;
65
+ this.renderCounts.set(id, newCount);
66
+
67
+ // Create or update heatmap overlay
68
+ this.updateHeatmap(id, element, newCount, patchType);
69
+ }
70
+
71
+ /**
72
+ * Create or update the heatmap overlay for an element
73
+ */
74
+ private updateHeatmap(id: string, element: HTMLElement, renderCount: number, patchType: string): void {
75
+ // Calculate opacity based on render count (increment by heatmapIncrement% each time)
76
+ const opacity = Math.min(
77
+ (renderCount * this.config.heatmapIncrement) / 100,
78
+ this.config.maxOpacity
79
+ );
80
+
81
+ console.log(`๐Ÿ”ฅ [Debug] Updating heatmap for ${id}, count: ${renderCount}, opacity: ${opacity}`);
82
+
83
+ // For inline elements or text, use a simpler approach: background color + outline
84
+ const isInline = window.getComputedStyle(element).display.includes('inline');
85
+
86
+ if (isInline || element.tagName === 'SPAN') {
87
+ // Store original styles if not already stored
88
+ if (!element.dataset.hypenDebugOriginalBg) {
89
+ element.dataset.hypenDebugOriginalBg = element.style.backgroundColor || '';
90
+ element.dataset.hypenDebugOriginalOutline = element.style.outline || '';
91
+ element.dataset.hypenDebugOriginalPosition = element.style.position || '';
92
+ }
93
+
94
+ // Apply red background and outline directly to the element
95
+ element.style.backgroundColor = `rgba(255, 0, 0, ${Math.max(opacity, 0.15)})`;
96
+ element.style.outline = `2px solid rgba(255, 0, 0, ${Math.max(opacity + 0.2, 0.3)})`;
97
+ element.style.outlineOffset = '2px';
98
+ element.style.position = 'relative';
99
+
100
+ // Add count badge as ::before pseudo-element or data attribute
101
+ element.setAttribute('data-hypen-renders', `${renderCount}ร— ${patchType}`);
102
+
103
+ // Add CSS for the badge if not already added
104
+ if (!document.getElementById('hypen-debug-styles')) {
105
+ const style = document.createElement('style');
106
+ style.id = 'hypen-debug-styles';
107
+ style.textContent = `
108
+ [data-hypen-renders]::before {
109
+ content: attr(data-hypen-renders);
110
+ position: absolute;
111
+ top: -18px;
112
+ left: 0;
113
+ background: rgba(255, 0, 0, 0.9);
114
+ color: white;
115
+ padding: 2px 6px;
116
+ font-size: 10px;
117
+ font-family: 'Courier New', monospace;
118
+ font-weight: bold;
119
+ border-radius: 3px;
120
+ z-index: 999999;
121
+ pointer-events: none;
122
+ white-space: nowrap;
123
+ text-shadow: none;
124
+ }
125
+ `;
126
+ document.head.appendChild(style);
127
+ }
128
+
129
+ // Store in overlays map for cleanup
130
+ this.overlays.set(id, element as any);
131
+
132
+ // Fade out after duration if enabled
133
+ if (this.config.fadeOutDuration > 0) {
134
+ setTimeout(() => {
135
+ const originalBg = element.dataset.hypenDebugOriginalBg || '';
136
+ const originalOutline = element.dataset.hypenDebugOriginalOutline || '';
137
+ element.style.backgroundColor = originalBg;
138
+ element.style.outline = originalOutline;
139
+ element.style.opacity = '1';
140
+ }, this.config.fadeOutDuration);
141
+ }
142
+ } else {
143
+ // For block elements, use overlay approach
144
+ let overlay = this.overlays.get(id);
145
+
146
+ if (!overlay) {
147
+ overlay = document.createElement("div");
148
+ overlay.className = "hypen-debug-overlay";
149
+ overlay.style.cssText = `
150
+ position: absolute;
151
+ top: 0;
152
+ left: 0;
153
+ right: 0;
154
+ bottom: 0;
155
+ pointer-events: none;
156
+ z-index: 999999 !important;
157
+ transition: opacity ${this.config.fadeOutDuration}ms ease-out;
158
+ border: 2px solid rgba(255, 0, 0, 0.7) !important;
159
+ box-sizing: border-box;
160
+ font-size: 11px;
161
+ color: white;
162
+ text-shadow: 0 0 3px black, 0 0 5px black;
163
+ padding: 4px;
164
+ font-family: 'Courier New', monospace;
165
+ font-weight: bold;
166
+ display: block !important;
167
+ visibility: visible !important;
168
+ `;
169
+
170
+ const currentPosition = window.getComputedStyle(element).position;
171
+ if (currentPosition === 'static') {
172
+ element.style.position = 'relative';
173
+ }
174
+
175
+ element.appendChild(overlay);
176
+ this.overlays.set(id, overlay);
177
+ }
178
+
179
+ overlay.style.backgroundColor = `rgba(255, 0, 0, ${Math.max(opacity, 0.15)})`;
180
+ overlay.style.opacity = '1';
181
+ overlay.textContent = `${renderCount}ร— ${patchType}`;
182
+
183
+ if (this.config.fadeOutDuration > 0) {
184
+ setTimeout(() => {
185
+ if (overlay) {
186
+ overlay.style.opacity = '0.2';
187
+ }
188
+ }, this.config.fadeOutDuration);
189
+ }
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Reset tracking for a specific element
195
+ */
196
+ reset(id: string): void {
197
+ this.renderCounts.delete(id);
198
+ const overlay = this.overlays.get(id);
199
+ if (overlay) {
200
+ overlay.remove();
201
+ this.overlays.delete(id);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Reset tracking for all elements
207
+ */
208
+ resetAll(): void {
209
+ this.renderCounts.clear();
210
+ for (const overlay of this.overlays.values()) {
211
+ overlay.remove();
212
+ }
213
+ this.overlays.clear();
214
+ }
215
+
216
+ /**
217
+ * Get render count for an element
218
+ */
219
+ getRenderCount(id: string): number {
220
+ return this.renderCounts.get(id) || 0;
221
+ }
222
+
223
+ /**
224
+ * Clean up all overlays (called when debug mode is disabled)
225
+ */
226
+ private cleanup(): void {
227
+ for (const overlay of this.overlays.values()) {
228
+ overlay.remove();
229
+ }
230
+ this.overlays.clear();
231
+ }
232
+
233
+ /**
234
+ * Get statistics about re-renders
235
+ */
236
+ getStats(): { totalRerenders: number; elementCount: number; avgRerenders: number } {
237
+ const totalRerenders = Array.from(this.renderCounts.values()).reduce((sum, count) => sum + count, 0);
238
+ const elementCount = this.renderCounts.size;
239
+ const avgRerenders = elementCount > 0 ? totalRerenders / elementCount : 0;
240
+
241
+ return {
242
+ totalRerenders,
243
+ elementCount,
244
+ avgRerenders: Math.round(avgRerenders * 100) / 100,
245
+ };
246
+ }
247
+ }
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Event Management System
3
+ *
4
+ * Handles DOM event binding and action dispatching
5
+ */
6
+
7
+ // Interface for the engine that EventManager needs
8
+ interface IEngine {
9
+ dispatchAction(name: string, payload?: any): void;
10
+ }
11
+
12
+ export interface EventBinding {
13
+ elementId: string;
14
+ eventName: string;
15
+ actionName: string;
16
+ }
17
+
18
+ export class EventManager {
19
+ private engine: IEngine;
20
+ private bindings: Map<string, Map<string, EventListener>> = new Map();
21
+
22
+ constructor(engine: IEngine) {
23
+ this.engine = engine;
24
+ }
25
+
26
+ /**
27
+ * Attach an event listener to an element
28
+ */
29
+ attach(elementId: string, element: HTMLElement, eventName: string, actionName: string): void {
30
+ // Convert onClick to click for DOM events
31
+ const domEventName = eventName === "onClick" ? "click" : eventName;
32
+ console.log(`[EventManager] Attaching ${eventName} (DOM: ${domEventName}) to element ${elementId}, action: ${actionName}`);
33
+
34
+ // Create event listener that dispatches action
35
+ const listener = (event: Event) => {
36
+ console.log(`๐Ÿ”ฅ [EventManager] Event fired: ${eventName} on ${elementId}, dispatching action: ${actionName}`);
37
+ console.log(`๐Ÿ”ฅ [EventManager] Event object:`, event);
38
+ console.log(`๐Ÿ”ฅ [EventManager] Element:`, element);
39
+
40
+ // Prevent default for certain events
41
+ if (eventName === "submit" || (eventName === "click" && element.tagName === "A")) {
42
+ event.preventDefault();
43
+ }
44
+
45
+ // Extract event data
46
+ const payload = this.extractEventData(event, element);
47
+ console.log(`๐Ÿ”ฅ [EventManager] Event payload:`, payload);
48
+
49
+ // Dispatch action to engine
50
+ console.log(`๐Ÿ”ฅ [EventManager] Calling engine.dispatchAction(${actionName})`);
51
+ try {
52
+ this.engine.dispatchAction(actionName, payload);
53
+ console.log(`๐Ÿ”ฅ [EventManager] โœ… dispatchAction succeeded`);
54
+ } catch (error) {
55
+ console.error(`๐Ÿ”ฅ [EventManager] โŒ dispatchAction failed:`, error);
56
+ }
57
+ };
58
+
59
+ // Store listener reference
60
+ let elementBindings = this.bindings.get(elementId);
61
+ if (!elementBindings) {
62
+ elementBindings = new Map();
63
+ this.bindings.set(elementId, elementBindings);
64
+ }
65
+ elementBindings.set(eventName, listener);
66
+
67
+ // Attach to DOM
68
+ element.addEventListener(domEventName, listener);
69
+ console.log(`[EventManager] Listener attached to DOM for ${domEventName}`);
70
+ console.log(`[EventManager] Element details:`, {
71
+ tagName: element.tagName,
72
+ id: element.id,
73
+ dataset: element.dataset,
74
+ textContent: element.textContent?.substring(0, 50)
75
+ });
76
+
77
+ // Test: Add a simple click listener to verify DOM events work
78
+ if (domEventName === "click") {
79
+ element.addEventListener("click", (e) => {
80
+ console.log(`๐Ÿงช [TEST] Raw DOM click detected on ${element.tagName}`, e);
81
+ });
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Detach an event listener from an element
87
+ */
88
+ detach(elementId: string, element: HTMLElement, eventName: string): void {
89
+ const elementBindings = this.bindings.get(elementId);
90
+ if (!elementBindings) return;
91
+
92
+ const listener = elementBindings.get(eventName);
93
+ if (listener) {
94
+ element.removeEventListener(eventName, listener);
95
+ elementBindings.delete(eventName);
96
+ }
97
+
98
+ if (elementBindings.size === 0) {
99
+ this.bindings.delete(elementId);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Extract relevant data from an event
105
+ */
106
+ private extractEventData(event: Event, element: HTMLElement): any {
107
+ const data: any = {
108
+ type: event.type,
109
+ timestamp: Date.now(),
110
+ };
111
+
112
+ // Mouse events
113
+ if (event instanceof MouseEvent) {
114
+ data.clientX = event.clientX;
115
+ data.clientY = event.clientY;
116
+ data.button = event.button;
117
+ }
118
+
119
+ // Keyboard events
120
+ if (event instanceof KeyboardEvent) {
121
+ data.key = event.key;
122
+ data.code = event.code;
123
+ data.ctrlKey = event.ctrlKey;
124
+ data.shiftKey = event.shiftKey;
125
+ data.altKey = event.altKey;
126
+ data.metaKey = event.metaKey;
127
+ }
128
+
129
+ // Input events (for form elements)
130
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
131
+ data.value = element.value;
132
+ }
133
+
134
+ // Select events
135
+ if (element instanceof HTMLSelectElement) {
136
+ data.value = element.value;
137
+ data.selectedIndex = element.selectedIndex;
138
+ }
139
+
140
+ // Form events
141
+ if (event.type === "submit" && element instanceof HTMLFormElement) {
142
+ data.formData = new FormData(element);
143
+ }
144
+
145
+ return data;
146
+ }
147
+
148
+ /**
149
+ * Clear all event bindings for an element
150
+ */
151
+ clearElement(elementId: string, element: HTMLElement): void {
152
+ const elementBindings = this.bindings.get(elementId);
153
+ if (!elementBindings) return;
154
+
155
+ for (const [eventName, listener] of elementBindings) {
156
+ element.removeEventListener(eventName, listener);
157
+ }
158
+
159
+ this.bindings.delete(elementId);
160
+ }
161
+
162
+ /**
163
+ * Clear all event bindings
164
+ */
165
+ clearAll(): void {
166
+ this.bindings.clear();
167
+ }
168
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * DOM Renderer for Hypen
3
+ *
4
+ * Browser-only module for rendering Hypen UI to the DOM
5
+ */
6
+
7
+ export { DOMRenderer } from "./renderer.js";
8
+ export { ComponentRegistry } from "./components/index.js";
9
+ export { ApplicatorRegistry } from "./applicators/index.js";
10
+ export { EventManager } from "./events.js";
11
+ export { RerenderTracker, type DebugConfig, defaultDebugConfig } from "./debug.js";