@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,137 @@
1
+ /**
2
+ * Canvas Renderer Types
3
+ *
4
+ * Shared type definitions for the canvas renderer
5
+ */
6
+
7
+ export interface VirtualNode {
8
+ id: string;
9
+ type: string;
10
+ props: Record<string, any>;
11
+ children: VirtualNode[];
12
+ parent: VirtualNode | null;
13
+
14
+ // Computed layout
15
+ layout?: Layout;
16
+
17
+ // Rendering state
18
+ visible: boolean;
19
+ opacity: number;
20
+
21
+ // Interaction state
22
+ clickable: boolean;
23
+ hoverable: boolean;
24
+ focusable: boolean;
25
+ focused: boolean;
26
+ hovered: boolean;
27
+ }
28
+
29
+ export interface Layout {
30
+ x: number;
31
+ y: number;
32
+ width: number;
33
+ height: number;
34
+
35
+ // Box model
36
+ margin: BoxSpacing;
37
+ padding: BoxSpacing;
38
+ border: BorderStyle;
39
+
40
+ // Content area (after padding)
41
+ contentX: number;
42
+ contentY: number;
43
+ contentWidth: number;
44
+ contentHeight: number;
45
+ }
46
+
47
+ export interface BoxSpacing {
48
+ top: number;
49
+ right: number;
50
+ bottom: number;
51
+ left: number;
52
+ }
53
+
54
+ export interface BorderStyle {
55
+ width: number;
56
+ color: string;
57
+ radius: number;
58
+ }
59
+
60
+ export interface Rectangle {
61
+ x: number;
62
+ y: number;
63
+ width: number;
64
+ height: number;
65
+ }
66
+
67
+ export interface Point {
68
+ x: number;
69
+ y: number;
70
+ }
71
+
72
+ export interface FontStyle {
73
+ fontFamily: string;
74
+ fontSize: number;
75
+ fontWeight: string | number;
76
+ lineHeight?: number;
77
+ }
78
+
79
+ export interface TextStyle extends FontStyle {
80
+ color: string;
81
+ textAlign: "left" | "center" | "right";
82
+ verticalAlign: "top" | "middle" | "bottom";
83
+ }
84
+
85
+ export interface TextMetrics {
86
+ width: number;
87
+ height: number;
88
+ lines: string[];
89
+ lineHeight: number;
90
+ }
91
+
92
+ export interface CanvasRendererOptions {
93
+ // Display
94
+ devicePixelRatio?: number;
95
+ backgroundColor?: string;
96
+
97
+ // Features
98
+ enableAccessibility?: boolean;
99
+ enableHitTesting?: boolean;
100
+ enableInputOverlay?: boolean;
101
+
102
+ // Performance
103
+ enableDirtyRects?: boolean;
104
+ enableLayerCaching?: boolean;
105
+ maxLayerCacheSize?: number;
106
+
107
+ // Debug
108
+ showLayoutBounds?: boolean;
109
+ showDirtyRects?: boolean;
110
+ logPerformance?: boolean;
111
+ }
112
+
113
+ export interface PainterFunction {
114
+ (ctx: CanvasRenderingContext2D, node: VirtualNode): void;
115
+ }
116
+
117
+ export interface LayoutFunction {
118
+ (node: VirtualNode, availableWidth: number, availableHeight: number): {
119
+ width: number;
120
+ height: number;
121
+ };
122
+ }
123
+
124
+ export interface DirtyRect extends Rectangle {
125
+ frameId: number;
126
+ }
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+
135
+
136
+
137
+
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Canvas Renderer Utilities
3
+ *
4
+ * Common utility functions
5
+ */
6
+
7
+ import type { BoxSpacing, Rectangle, Point, VirtualNode } from "./types.js";
8
+
9
+ /**
10
+ * Parse spacing value (margin, padding)
11
+ * Supports: number, "10", "10 20", "10 20 30 40"
12
+ */
13
+ export function parseSpacing(value: any): BoxSpacing {
14
+ if (typeof value === "number") {
15
+ return { top: value, right: value, bottom: value, left: value };
16
+ }
17
+
18
+ if (typeof value === "string") {
19
+ const parts = value.split(/\s+/).map((v) => parseFloat(v) || 0);
20
+ if (parts.length === 1) {
21
+ return { top: parts[0], right: parts[0], bottom: parts[0], left: parts[0] };
22
+ }
23
+ if (parts.length === 2) {
24
+ return { top: parts[0], right: parts[1], bottom: parts[0], left: parts[1] };
25
+ }
26
+ if (parts.length === 4) {
27
+ return { top: parts[0], right: parts[1], bottom: parts[2], left: parts[3] };
28
+ }
29
+ }
30
+
31
+ if (typeof value === "object" && value !== null) {
32
+ return {
33
+ top: parseFloat(value.top) || 0,
34
+ right: parseFloat(value.right) || 0,
35
+ bottom: parseFloat(value.bottom) || 0,
36
+ left: parseFloat(value.left) || 0,
37
+ };
38
+ }
39
+
40
+ return { top: 0, right: 0, bottom: 0, left: 0 };
41
+ }
42
+
43
+ /**
44
+ * Parse size value (width, height)
45
+ * Returns pixel value or null for "auto"
46
+ */
47
+ export function parseSize(value: any): number | null {
48
+ if (typeof value === "number") return value;
49
+ if (typeof value === "string") {
50
+ if (value === "auto") return null;
51
+ const num = parseFloat(value);
52
+ return isNaN(num) ? null : num;
53
+ }
54
+ return null;
55
+ }
56
+
57
+ /**
58
+ * Check if point is inside rectangle
59
+ */
60
+ export function isPointInRect(point: Point, rect: Rectangle): boolean {
61
+ return (
62
+ point.x >= rect.x &&
63
+ point.x <= rect.x + rect.width &&
64
+ point.y >= rect.y &&
65
+ point.y <= rect.y + rect.height
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Check if point is inside rounded rectangle
71
+ */
72
+ export function isPointInRoundedRect(
73
+ point: Point,
74
+ rect: Rectangle,
75
+ radius: number
76
+ ): boolean {
77
+ const { x, y, width, height } = rect;
78
+
79
+ // Quick reject if outside bounding box
80
+ if (!isPointInRect(point, rect)) return false;
81
+
82
+ // No radius means simple rectangle
83
+ if (radius <= 0) return true;
84
+
85
+ const px = point.x;
86
+ const py = point.y;
87
+
88
+ // Check corners
89
+ // Top-left
90
+ if (px < x + radius && py < y + radius) {
91
+ return Math.pow(px - (x + radius), 2) + Math.pow(py - (y + radius), 2) <= Math.pow(radius, 2);
92
+ }
93
+
94
+ // Top-right
95
+ if (px > x + width - radius && py < y + radius) {
96
+ return (
97
+ Math.pow(px - (x + width - radius), 2) + Math.pow(py - (y + radius), 2) <=
98
+ Math.pow(radius, 2)
99
+ );
100
+ }
101
+
102
+ // Bottom-left
103
+ if (px < x + radius && py > y + height - radius) {
104
+ return (
105
+ Math.pow(px - (x + radius), 2) + Math.pow(py - (y + height - radius), 2) <=
106
+ Math.pow(radius, 2)
107
+ );
108
+ }
109
+
110
+ // Bottom-right
111
+ if (px > x + width - radius && py > y + height - radius) {
112
+ return (
113
+ Math.pow(px - (x + width - radius), 2) + Math.pow(py - (y + height - radius), 2) <=
114
+ Math.pow(radius, 2)
115
+ );
116
+ }
117
+
118
+ // Inside rectangle
119
+ return true;
120
+ }
121
+
122
+ /**
123
+ * Merge rectangles into bounding box
124
+ */
125
+ export function mergeRects(rects: Rectangle[]): Rectangle | null {
126
+ if (rects.length === 0) return null;
127
+ if (rects.length === 1) return rects[0];
128
+
129
+ let minX = Infinity;
130
+ let minY = Infinity;
131
+ let maxX = -Infinity;
132
+ let maxY = -Infinity;
133
+
134
+ for (const rect of rects) {
135
+ minX = Math.min(minX, rect.x);
136
+ minY = Math.min(minY, rect.y);
137
+ maxX = Math.max(maxX, rect.x + rect.width);
138
+ maxY = Math.max(maxY, rect.y + rect.height);
139
+ }
140
+
141
+ return {
142
+ x: minX,
143
+ y: minY,
144
+ width: maxX - minX,
145
+ height: maxY - minY,
146
+ };
147
+ }
148
+
149
+ /**
150
+ * Create a canvas font string from font style
151
+ */
152
+ export function createFontString(
153
+ fontSize: number,
154
+ fontWeight: string | number,
155
+ fontFamily: string
156
+ ): string {
157
+ return `${fontWeight} ${fontSize}px ${fontFamily}`;
158
+ }
159
+
160
+ /**
161
+ * Walk tree depth-first
162
+ */
163
+ export function walkTree(node: VirtualNode, callback: (node: VirtualNode) => void): void {
164
+ callback(node);
165
+ for (const child of node.children) {
166
+ walkTree(child, callback);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Find node by ID in tree
172
+ */
173
+ export function findNodeById(root: VirtualNode, id: string): VirtualNode | null {
174
+ if (root.id === id) return root;
175
+
176
+ for (const child of root.children) {
177
+ const found = findNodeById(child, id);
178
+ if (found) return found;
179
+ }
180
+
181
+ return null;
182
+ }
183
+
184
+ /**
185
+ * Get absolute bounds of node (including transformations)
186
+ */
187
+ export function getAbsoluteBounds(node: VirtualNode): Rectangle | null {
188
+ if (!node.layout) return null;
189
+
190
+ let x = node.layout.x;
191
+ let y = node.layout.y;
192
+
193
+ // Walk up tree to accumulate offsets
194
+ let current = node.parent;
195
+ while (current && current.layout) {
196
+ x += current.layout.contentX;
197
+ y += current.layout.contentY;
198
+ current = current.parent;
199
+ }
200
+
201
+ return {
202
+ x,
203
+ y,
204
+ width: node.layout.width,
205
+ height: node.layout.height,
206
+ };
207
+ }
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+
@@ -0,0 +1,265 @@
1
+ # DOM Renderer
2
+
3
+ Browser-only module for rendering Hypen UI to the DOM.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ src/dom/
9
+ ├── index.ts # Main exports
10
+ ├── renderer.ts # DOMRenderer class
11
+ ├── events.ts # Event management
12
+ ├── components/ # Component handlers
13
+ │ ├── index.ts # Component registry
14
+ │ ├── column.ts
15
+ │ ├── row.ts
16
+ │ ├── text.ts
17
+ │ ├── image.ts
18
+ │ ├── button.ts
19
+ │ ├── container.ts
20
+ │ ├── center.ts
21
+ │ ├── list.ts
22
+ │ └── input.ts
23
+ ├── applicators/ # Style applicators
24
+ │ ├── index.ts # Applicator registry
25
+ │ ├── padding.ts
26
+ │ ├── margin.ts
27
+ │ ├── color.ts
28
+ │ ├── border.ts
29
+ │ ├── size.ts
30
+ │ ├── font.ts
31
+ │ └── layout.ts
32
+ └── canvas/ # Canvas support
33
+ └── index.ts # Canvas component & applicators
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Browser Import
39
+
40
+ ```typescript
41
+ import { Engine, app, HypenModuleInstance } from "@hypen/core";
42
+ import { DOMRenderer } from "@hypen/core/dom";
43
+
44
+ const engine = new Engine();
45
+ await engine.init();
46
+
47
+ const renderer = new DOMRenderer(document.body, engine);
48
+ engine.setRenderCallback((patches) => {
49
+ renderer.applyPatches(patches);
50
+ });
51
+ ```
52
+
53
+ ### Server Import
54
+
55
+ ```typescript
56
+ // This will fail in Node.js/Bun (no DOM)
57
+ import { DOMRenderer } from "@hypen/core/dom"; // ❌ Error
58
+
59
+ // Use server-safe renderer instead
60
+ import { ConsoleRenderer } from "@hypen/core"; // ✅ Works
61
+ ```
62
+
63
+ ## Components
64
+
65
+ All components are registered by default:
66
+
67
+ - **Column** - Vertical flex container
68
+ - **Row** - Horizontal flex container
69
+ - **Text** - Text content
70
+ - **Image** - Image element
71
+ - **Button** - Button element
72
+ - **Container/Box** - Generic div
73
+ - **Center** - Centered content
74
+ - **List** - Scrollable stack with gap
75
+ - **Input** - Input field
76
+ - **Canvas** - Canvas element
77
+
78
+ ### Custom Components
79
+
80
+ ```typescript
81
+ const renderer = new DOMRenderer(document.body, engine);
82
+ const registry = renderer.getComponentRegistry();
83
+
84
+ registry.register("mycomponent", {
85
+ create(): HTMLElement {
86
+ const el = document.createElement("div");
87
+ el.classList.add("my-component");
88
+ return el;
89
+ },
90
+ applyProps(el: HTMLElement, props: Record<string, any>): void {
91
+ if (props.title) {
92
+ el.setAttribute("title", props.title);
93
+ }
94
+ },
95
+ });
96
+ ```
97
+
98
+ ## Applicators
99
+
100
+ Style applicators are registered by default:
101
+
102
+ **Spacing:**
103
+ - `padding` - All sides or {left, right, top, bottom}
104
+ - `margin` - All sides or {left, right, top, bottom}
105
+ - `gap` - Flex/grid gap
106
+
107
+ **Colors:**
108
+ - `color` - Text color
109
+ - `backgroundColor` - Background color
110
+ - `borderColor` - Border color
111
+ - `opacity` - Opacity (0-1)
112
+
113
+ **Border:**
114
+ - `borderWidth` - Border width
115
+ - `borderStyle` - Border style (solid, dashed, etc.)
116
+ - `borderRadius` - Border radius
117
+
118
+ **Size:**
119
+ - `width`, `height` - Element size
120
+ - `minWidth`, `minHeight` - Minimum size
121
+ - `maxWidth`, `maxHeight` - Maximum size
122
+
123
+ **Font:**
124
+ - `fontSize` - Font size
125
+ - `fontWeight` - Font weight (normal, bold, 100-900)
126
+ - `fontFamily` - Font family
127
+ - `textAlign` - Text alignment
128
+ - `lineHeight` - Line height
129
+
130
+ **Layout (Flexbox):**
131
+ - `horizontalAlign` - justify-content
132
+ - `verticalAlign` - align-items
133
+ - `flex` - Flex shorthand
134
+ - `flexGrow`, `flexShrink` - Flex properties
135
+
136
+ **Misc:**
137
+ - `cursor` - Cursor style
138
+ - `overflow` - Overflow behavior
139
+
140
+ ### Custom Applicators
141
+
142
+ ```typescript
143
+ const renderer = new DOMRenderer(document.body, engine);
144
+ const applicators = renderer.getApplicatorRegistry();
145
+
146
+ applicators.register("shadow", (el, value) => {
147
+ el.style.boxShadow = `0 ${value}px ${value * 2}px rgba(0,0,0,0.2)`;
148
+ });
149
+ ```
150
+
151
+ ## Events
152
+
153
+ Events are automatically wired up when patches include `attachEvent`:
154
+
155
+ ```typescript
156
+ // Hypen DSL:
157
+ Button("@actions.increment") { Text("+") }
158
+
159
+ // Becomes:
160
+ // 1. Create button
161
+ // 2. Attach "click" event
162
+ // 3. On click, dispatch "increment" action to engine
163
+ ```
164
+
165
+ Supported events:
166
+ - Mouse: `click`, `dblclick`, `mousedown`, `mouseup`, `mouseenter`, `mouseleave`
167
+ - Keyboard: `keydown`, `keyup`, `keypress`
168
+ - Input: `input`, `change`, `focus`, `blur`
169
+ - Form: `submit`
170
+ - Touch: `touchstart`, `touchend`, `touchmove`
171
+
172
+ Event data includes:
173
+ - `type` - Event type
174
+ - `timestamp` - When it occurred
175
+ - `clientX`, `clientY` - Mouse position (mouse events)
176
+ - `key`, `code` - Key info (keyboard events)
177
+ - `value` - Input value (form elements)
178
+
179
+ ## Canvas
180
+
181
+ Canvas components have special applicators for drawing:
182
+
183
+ ```typescript
184
+ // Register canvas applicators
185
+ const renderer = new DOMRenderer(document.body, engine);
186
+ const applicators = renderer.getApplicatorRegistry();
187
+
188
+ // Canvas-specific applicators
189
+ applicators.register("fillStyle", (el, value) => {
190
+ const canvas = el as HTMLCanvasElement;
191
+ const ctx = canvas.getContext("2d");
192
+ if (ctx) ctx.fillStyle = value;
193
+ });
194
+ ```
195
+
196
+ Built-in canvas applicators:
197
+ - `fillStyle` - Fill color
198
+ - `strokeStyle` - Stroke color
199
+ - `lineWidth` - Line width
200
+
201
+ ## Extensibility
202
+
203
+ ### Adding a New Component
204
+
205
+ 1. Create `src/dom/components/mycomponent.ts`:
206
+
207
+ ```typescript
208
+ import type { ComponentHandler } from "./index.js";
209
+
210
+ export const myComponentHandler: ComponentHandler = {
211
+ create(): HTMLElement {
212
+ const el = document.createElement("div");
213
+ el.dataset.hypenType = "mycomponent";
214
+ return el;
215
+ },
216
+ applyProps(el, props) {
217
+ // Handle props
218
+ },
219
+ };
220
+ ```
221
+
222
+ 2. Register in `src/dom/components/index.ts`:
223
+
224
+ ```typescript
225
+ const { myComponentHandler } = require("./mycomponent.js");
226
+ this.register("mycomponent", myComponentHandler);
227
+ ```
228
+
229
+ ### Adding a New Applicator
230
+
231
+ 1. Create `src/dom/applicators/myapplicator.ts`:
232
+
233
+ ```typescript
234
+ import type { ApplicatorHandler } from "./index.js";
235
+
236
+ export const myApplicatorHandler: ApplicatorHandler = (el, value) => {
237
+ el.style.someProperty = String(value);
238
+ };
239
+ ```
240
+
241
+ 2. Register in `src/dom/applicators/index.ts`:
242
+
243
+ ```typescript
244
+ const { myApplicatorHandler } = require("./myapplicator.js");
245
+ this.register("myapplicator", myApplicatorHandler);
246
+ ```
247
+
248
+ ## Performance
249
+
250
+ - **Minimal DOM operations** - Only patches are applied
251
+ - **Efficient updates** - Only changed props are updated
252
+ - **Event delegation** - Events managed per-element
253
+ - **Keyed reconciliation** - Use `key` prop for lists
254
+
255
+ ## Browser Support
256
+
257
+ - Modern browsers with ES6+ support
258
+ - Requires: `Proxy`, `Map`, `Set`, `Promise`
259
+ - No IE11 support (use Babel + polyfills if needed)
260
+
261
+ ## See Also
262
+
263
+ - [Main README](../../README.md) - Full SDK documentation
264
+ - [REFACTORING.md](../../REFACTORING.md) - State management details
265
+ - [IMPLEMENTATION.md](../../IMPLEMENTATION.md) - Implementation guide