@hypen-space/web 0.2.12 → 0.3.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 (39) hide show
  1. package/dist/src/dom/applicators/effects.js +38 -2
  2. package/dist/src/dom/applicators/effects.js.map +3 -3
  3. package/dist/src/dom/applicators/events.js +280 -397
  4. package/dist/src/dom/applicators/events.js.map +5 -4
  5. package/dist/src/dom/applicators/font.js +94 -5
  6. package/dist/src/dom/applicators/font.js.map +3 -3
  7. package/dist/src/dom/applicators/index.js +590 -425
  8. package/dist/src/dom/applicators/index.js.map +10 -9
  9. package/dist/src/dom/applicators/layout.js +33 -5
  10. package/dist/src/dom/applicators/layout.js.map +3 -3
  11. package/dist/src/dom/applicators/size.js +81 -16
  12. package/dist/src/dom/applicators/size.js.map +3 -3
  13. package/dist/src/dom/components/hypenapp.js +296 -0
  14. package/dist/src/dom/components/hypenapp.js.map +10 -0
  15. package/dist/src/dom/components/index.js +263 -1
  16. package/dist/src/dom/components/index.js.map +5 -4
  17. package/dist/src/dom/element-data.js +140 -0
  18. package/dist/src/dom/element-data.js.map +10 -0
  19. package/dist/src/dom/index.js +857 -430
  20. package/dist/src/dom/index.js.map +13 -11
  21. package/dist/src/dom/renderer.js +857 -430
  22. package/dist/src/dom/renderer.js.map +13 -11
  23. package/dist/src/hypen.js +857 -430
  24. package/dist/src/hypen.js.map +13 -11
  25. package/dist/src/index.js +862 -430
  26. package/dist/src/index.js.map +15 -12
  27. package/package.json +3 -3
  28. package/src/canvas/QUICKSTART.md +2 -4
  29. package/src/dom/applicators/effects.ts +45 -1
  30. package/src/dom/applicators/events.ts +348 -537
  31. package/src/dom/applicators/font.ts +127 -2
  32. package/src/dom/applicators/index.ts +117 -7
  33. package/src/dom/applicators/layout.ts +40 -4
  34. package/src/dom/applicators/size.ts +101 -16
  35. package/src/dom/components/hypenapp.ts +348 -0
  36. package/src/dom/components/index.ts +2 -0
  37. package/src/dom/element-data.ts +234 -0
  38. package/src/dom/renderer.ts +8 -5
  39. package/src/index.ts +3 -0
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/dom/applicators/layout.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Layout Applicators (Flexbox/Grid)\n */\n\nimport type { ApplicatorHandler } from \"./index.js\";\n\nexport const layoutHandlers: Record<string, ApplicatorHandler> = {\n // Unified alignment API - works for both Column and Row\n verticalAlignment: (el, value) => {\n const val = String(value);\n // Check flex-direction to determine which CSS property to set\n const flexDirection = getComputedStyle(el).flexDirection;\n if (flexDirection === \"column\" || flexDirection === \"column-reverse\") {\n // For column: vertical is the main axis (justify-content)\n el.style.justifyContent = val;\n } else {\n // For row: vertical is the cross axis (align-items)\n el.style.alignItems = val;\n }\n },\n\n horizontalAlignment: (el, value) => {\n const val = String(value);\n // Check flex-direction to determine which CSS property to set\n const flexDirection = getComputedStyle(el).flexDirection;\n if (flexDirection === \"column\" || flexDirection === \"column-reverse\") {\n // For column: horizontal is the cross axis (align-items)\n el.style.alignItems = val;\n } else {\n // For row: horizontal is the main axis (justify-content)\n el.style.justifyContent = val;\n }\n },\n\n // Legacy aliases (kept for backward compatibility)\n horizontalAlign: (el, value) => {\n el.style.justifyContent = String(value);\n },\n\n verticalAlign: (el, value) => {\n el.style.alignItems = String(value);\n },\n\n gap: (el, value) => {\n el.style.gap = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n // weight: unified cross-platform API (same as flex)\n // Use .weight(1) to make element take remaining space in Row/Column\n weight: (el, value) => {\n el.style.flex = String(value);\n },\n\n // flex: CSS flex shorthand (kept for CSS compatibility)\n flex: (el, value) => {\n el.style.flex = String(value);\n },\n\n flexGrow: (el, value) => {\n el.style.flexGrow = String(value);\n },\n\n flexShrink: (el, value) => {\n el.style.flexShrink = String(value);\n },\n\n cursor: (el, value) => {\n el.style.cursor = String(value);\n },\n\n overflow: (el, value) => {\n el.style.overflow = String(value);\n },\n\n scrollable: (el, value) => {\n if (value === true || value === \"true\") {\n el.style.overflow = \"auto\";\n } else if (value === false || value === \"false\") {\n el.style.overflow = \"hidden\";\n } else if (value === \"vertical\") {\n el.style.overflowX = \"hidden\";\n el.style.overflowY = \"auto\";\n } else if (value === \"horizontal\") {\n el.style.overflowX = \"auto\";\n el.style.overflowY = \"hidden\";\n } else if (value === \"both\") {\n el.style.overflow = \"auto\";\n } else {\n el.style.overflow = String(value);\n }\n },\n};\n"
5
+ "/**\n * Layout Applicators (Flexbox/Grid)\n */\n\nimport type { ApplicatorHandler } from \"./index.js\";\n\n/**\n * Maps Hypen alignment values to CSS flexbox values.\n * Ensures consistent cross-platform API (Android/iOS/Web).\n */\nfunction mapAlignmentValue(value: string): string {\n const v = String(value).toLowerCase();\n switch (v) {\n // Positional values -> CSS equivalents\n case \"top\":\n case \"start\":\n case \"leading\":\n case \"left\":\n return \"flex-start\";\n case \"bottom\":\n case \"end\":\n case \"trailing\":\n case \"right\":\n return \"flex-end\";\n case \"center\":\n return \"center\";\n // Spacing values -> CSS equivalents\n case \"spacebetween\":\n case \"space-between\":\n return \"space-between\";\n case \"spacearound\":\n case \"space-around\":\n return \"space-around\";\n case \"spaceevenly\":\n case \"space-evenly\":\n return \"space-evenly\";\n // Pass through CSS values as-is\n default:\n return v;\n }\n}\n\nexport const layoutHandlers: Record<string, ApplicatorHandler> = {\n // Unified alignment API - works for both Column and Row\n verticalAlignment: (el, value) => {\n const val = mapAlignmentValue(String(value));\n // Check flex-direction to determine which CSS property to set\n const flexDirection = getComputedStyle(el).flexDirection;\n if (flexDirection === \"column\" || flexDirection === \"column-reverse\") {\n // For column: vertical is the main axis (justify-content)\n el.style.justifyContent = val;\n } else {\n // For row: vertical is the cross axis (align-items)\n el.style.alignItems = val;\n }\n },\n\n horizontalAlignment: (el, value) => {\n const val = mapAlignmentValue(String(value));\n // Check flex-direction to determine which CSS property to set\n const flexDirection = getComputedStyle(el).flexDirection;\n if (flexDirection === \"column\" || flexDirection === \"column-reverse\") {\n // For column: horizontal is the cross axis (align-items)\n el.style.alignItems = val;\n } else {\n // For row: horizontal is the main axis (justify-content)\n el.style.justifyContent = val;\n }\n },\n\n // Legacy aliases (kept for backward compatibility)\n horizontalAlign: (el, value) => {\n el.style.justifyContent = mapAlignmentValue(String(value));\n },\n\n verticalAlign: (el, value) => {\n el.style.alignItems = mapAlignmentValue(String(value));\n },\n\n gap: (el, value) => {\n el.style.gap = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n // weight: unified cross-platform API (same as flex)\n // Use .weight(1) to make element take remaining space in Row/Column\n weight: (el, value) => {\n el.style.flex = String(value);\n },\n\n // flex: CSS flex shorthand (kept for CSS compatibility)\n flex: (el, value) => {\n el.style.flex = String(value);\n },\n\n flexGrow: (el, value) => {\n el.style.flexGrow = String(value);\n },\n\n flexShrink: (el, value) => {\n el.style.flexShrink = String(value);\n },\n\n cursor: (el, value) => {\n el.style.cursor = String(value);\n },\n\n overflow: (el, value) => {\n el.style.overflow = String(value);\n },\n\n scrollable: (el, value) => {\n if (value === true || value === \"true\") {\n el.style.overflow = \"auto\";\n } else if (value === false || value === \"false\") {\n el.style.overflow = \"hidden\";\n } else if (value === \"vertical\") {\n el.style.overflowX = \"hidden\";\n el.style.overflowY = \"auto\";\n } else if (value === \"horizontal\") {\n el.style.overflowX = \"auto\";\n el.style.overflowY = \"hidden\";\n } else if (value === \"both\") {\n el.style.overflow = \"auto\";\n } else {\n el.style.overflow = String(value);\n }\n },\n};\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAMa;AAAA;AAAA,mBAAoD;AAAA,IAE/D,mBAAmB,CAAC,IAAI,UAAU;AAAA,MAChC,MAAM,MAAM,OAAO,KAAK;AAAA,MAExB,MAAM,gBAAgB,iBAAiB,EAAE,EAAE;AAAA,MAC3C,IAAI,kBAAkB,YAAY,kBAAkB,kBAAkB;AAAA,QAEpE,GAAG,MAAM,iBAAiB;AAAA,MAC5B,EAAO;AAAA,QAEL,GAAG,MAAM,aAAa;AAAA;AAAA;AAAA,IAI1B,qBAAqB,CAAC,IAAI,UAAU;AAAA,MAClC,MAAM,MAAM,OAAO,KAAK;AAAA,MAExB,MAAM,gBAAgB,iBAAiB,EAAE,EAAE;AAAA,MAC3C,IAAI,kBAAkB,YAAY,kBAAkB,kBAAkB;AAAA,QAEpE,GAAG,MAAM,aAAa;AAAA,MACxB,EAAO;AAAA,QAEL,GAAG,MAAM,iBAAiB;AAAA;AAAA;AAAA,IAK9B,iBAAiB,CAAC,IAAI,UAAU;AAAA,MAC9B,GAAG,MAAM,iBAAiB,OAAO,KAAK;AAAA;AAAA,IAGxC,eAAe,CAAC,IAAI,UAAU;AAAA,MAC5B,GAAG,MAAM,aAAa,OAAO,KAAK;AAAA;AAAA,IAGpC,KAAK,CAAC,IAAI,UAAU;AAAA,MAClB,GAAG,MAAM,MAAM,OAAO,UAAU,WAAW,GAAG,YAAY,OAAO,KAAK;AAAA;AAAA,IAKxE,QAAQ,CAAC,IAAI,UAAU;AAAA,MACrB,GAAG,MAAM,OAAO,OAAO,KAAK;AAAA;AAAA,IAI9B,MAAM,CAAC,IAAI,UAAU;AAAA,MACnB,GAAG,MAAM,OAAO,OAAO,KAAK;AAAA;AAAA,IAG9B,UAAU,CAAC,IAAI,UAAU;AAAA,MACvB,GAAG,MAAM,WAAW,OAAO,KAAK;AAAA;AAAA,IAGlC,YAAY,CAAC,IAAI,UAAU;AAAA,MACzB,GAAG,MAAM,aAAa,OAAO,KAAK;AAAA;AAAA,IAGpC,QAAQ,CAAC,IAAI,UAAU;AAAA,MACrB,GAAG,MAAM,SAAS,OAAO,KAAK;AAAA;AAAA,IAGhC,UAAU,CAAC,IAAI,UAAU;AAAA,MACvB,GAAG,MAAM,WAAW,OAAO,KAAK;AAAA;AAAA,IAGlC,YAAY,CAAC,IAAI,UAAU;AAAA,MACzB,IAAI,UAAU,QAAQ,UAAU,QAAQ;AAAA,QACtC,GAAG,MAAM,WAAW;AAAA,MACtB,EAAO,SAAI,UAAU,SAAS,UAAU,SAAS;AAAA,QAC/C,GAAG,MAAM,WAAW;AAAA,MACtB,EAAO,SAAI,UAAU,YAAY;AAAA,QAC/B,GAAG,MAAM,YAAY;AAAA,QACrB,GAAG,MAAM,YAAY;AAAA,MACvB,EAAO,SAAI,UAAU,cAAc;AAAA,QACjC,GAAG,MAAM,YAAY;AAAA,QACrB,GAAG,MAAM,YAAY;AAAA,MACvB,EAAO,SAAI,UAAU,QAAQ;AAAA,QAC3B,GAAG,MAAM,WAAW;AAAA,MACtB,EAAO;AAAA,QACL,GAAG,MAAM,WAAW,OAAO,KAAK;AAAA;AAAA;AAAA,EAGtC;AAAA;",
8
- "debugId": "0E73A4A92035E71B64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "461290E6A992400364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -32,43 +32,108 @@ var exports_size = {};
32
32
  __export(exports_size, {
33
33
  sizeHandlers: () => sizeHandlers
34
34
  });
35
+ function parseSizeValue(value) {
36
+ if (value === null || value === undefined)
37
+ return null;
38
+ if (typeof value === "number") {
39
+ return `${value}px`;
40
+ }
41
+ const str = String(value).trim().toLowerCase();
42
+ switch (str) {
43
+ case "fill":
44
+ case "match_parent":
45
+ return "100%";
46
+ case "wrap":
47
+ case "wrap_content":
48
+ case "auto":
49
+ return "auto";
50
+ case "infinity":
51
+ case "inf":
52
+ case "max":
53
+ return "100%";
54
+ }
55
+ const match = str.match(/^(-?[\d.]+)\s*(px|dp|pt|%|vw|vh|vmin|vmax|em|rem)?$/);
56
+ if (!match) {
57
+ return str;
58
+ }
59
+ const num = parseFloat(match[1]);
60
+ const unit = match[2] || "px";
61
+ switch (unit) {
62
+ case "px":
63
+ return `${num}px`;
64
+ case "dp":
65
+ case "pt":
66
+ return `${num}px`;
67
+ case "%":
68
+ return `${num}%`;
69
+ case "vw":
70
+ return `${num}vw`;
71
+ case "vh":
72
+ return `${num}vh`;
73
+ case "vmin":
74
+ return `${num}vmin`;
75
+ case "vmax":
76
+ return `${num}vmax`;
77
+ case "em":
78
+ return `${num}em`;
79
+ case "rem":
80
+ return `${num}rem`;
81
+ default:
82
+ return `${num}px`;
83
+ }
84
+ }
35
85
  var sizeHandlers;
36
86
  var init_size = __esm(() => {
37
87
  sizeHandlers = {
38
88
  width: (el, value) => {
39
- el.style.width = typeof value === "number" ? `${value}px` : String(value);
89
+ const size = parseSizeValue(value);
90
+ if (size)
91
+ el.style.width = size;
40
92
  },
41
93
  height: (el, value) => {
42
- el.style.height = typeof value === "number" ? `${value}px` : String(value);
94
+ const size = parseSizeValue(value);
95
+ if (size)
96
+ el.style.height = size;
43
97
  },
44
98
  minWidth: (el, value) => {
45
- el.style.minWidth = typeof value === "number" ? `${value}px` : String(value);
99
+ const size = parseSizeValue(value);
100
+ if (size)
101
+ el.style.minWidth = size;
46
102
  },
47
103
  minHeight: (el, value) => {
48
- el.style.minHeight = typeof value === "number" ? `${value}px` : String(value);
104
+ const size = parseSizeValue(value);
105
+ if (size)
106
+ el.style.minHeight = size;
49
107
  },
50
108
  maxWidth: (el, value) => {
51
- el.style.maxWidth = typeof value === "number" ? `${value}px` : String(value);
109
+ const size = parseSizeValue(value);
110
+ if (size)
111
+ el.style.maxWidth = size;
52
112
  },
53
113
  maxHeight: (el, value) => {
54
- el.style.maxHeight = typeof value === "number" ? `${value}px` : String(value);
114
+ const size = parseSizeValue(value);
115
+ if (size)
116
+ el.style.maxHeight = size;
55
117
  },
56
118
  size: (el, value) => {
57
- if (typeof value === "number") {
58
- el.style.width = `${value}px`;
59
- el.style.height = `${value}px`;
60
- } else if (typeof value === "object" && value !== null) {
119
+ if (typeof value === "object" && value !== null) {
61
120
  const obj = value;
62
121
  if (obj.width !== undefined) {
63
- el.style.width = typeof obj.width === "number" ? `${obj.width}px` : String(obj.width);
122
+ const w = parseSizeValue(obj.width);
123
+ if (w)
124
+ el.style.width = w;
64
125
  }
65
126
  if (obj.height !== undefined) {
66
- el.style.height = typeof obj.height === "number" ? `${obj.height}px` : String(obj.height);
127
+ const h = parseSizeValue(obj.height);
128
+ if (h)
129
+ el.style.height = h;
67
130
  }
68
131
  } else {
69
- const size = String(value);
70
- el.style.width = size;
71
- el.style.height = size;
132
+ const size = parseSizeValue(value);
133
+ if (size) {
134
+ el.style.width = size;
135
+ el.style.height = size;
136
+ }
72
137
  }
73
138
  },
74
139
  fillMaxWidth: (el, value) => {
@@ -98,4 +163,4 @@ export {
98
163
  sizeHandlers
99
164
  };
100
165
 
101
- //# debugId=6AEB29B00DD38BB964756E2164756E21
166
+ //# debugId=4734BF3C18B80B6664756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/dom/applicators/size.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Size Applicators\n */\n\nimport type { ApplicatorHandler } from \"./index.js\";\n\nexport const sizeHandlers: Record<string, ApplicatorHandler> = {\n width: (el, value) => {\n el.style.width = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n height: (el, value) => {\n el.style.height = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n minWidth: (el, value) => {\n el.style.minWidth = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n minHeight: (el, value) => {\n el.style.minHeight = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n maxWidth: (el, value) => {\n el.style.maxWidth = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n maxHeight: (el, value) => {\n el.style.maxHeight = typeof value === \"number\" ? `${value}px` : String(value);\n },\n\n // Combined size applicator - sets both width and height\n size: (el, value) => {\n if (typeof value === \"number\") {\n el.style.width = `${value}px`;\n el.style.height = `${value}px`;\n } else if (typeof value === \"object\" && value !== null) {\n const obj = value as Record<string, any>;\n if (obj.width !== undefined) {\n el.style.width = typeof obj.width === \"number\" ? `${obj.width}px` : String(obj.width);\n }\n if (obj.height !== undefined) {\n el.style.height = typeof obj.height === \"number\" ? `${obj.height}px` : String(obj.height);\n }\n } else {\n // Single value for both\n const size = String(value);\n el.style.width = size;\n el.style.height = size;\n }\n },\n\n // Fill max width - shorthand for width: 100%\n fillMaxWidth: (el, value) => {\n if (value === false) return;\n // Value can be a fraction (0-1) or boolean\n const fraction = typeof value === \"number\" ? value : 1;\n el.style.width = `${fraction * 100}%`;\n },\n\n // Fill max height - shorthand for height: 100%\n fillMaxHeight: (el, value) => {\n if (value === false) return;\n // Value can be a fraction (0-1) or boolean\n const fraction = typeof value === \"number\" ? value : 1;\n el.style.height = `${fraction * 100}%`;\n },\n\n // Fill max size - shorthand for width: 100% and height: 100%\n fillMaxSize: (el, value) => {\n if (value === false) return;\n // Value can be a fraction (0-1) or boolean\n const fraction = typeof value === \"number\" ? value : 1;\n el.style.width = `${fraction * 100}%`;\n el.style.height = `${fraction * 100}%`;\n },\n};\n"
5
+ "/**\n * Size Applicators\n *\n * Cross-platform sizing value support:\n * - Numbers: treated as px (platform default)\n * - \"100px\": absolute pixels (1px = 1px everywhere)\n * - \"100dp\" / \"100pt\": density-independent (1dp ≈ 1pt, scaled by device)\n * - \"50%\": percentage of parent\n * - \"50vw\" / \"50vh\": viewport width/height\n * - \"fill\" / \"100%\": fill available space\n * - \"wrap\" / \"auto\": fit content\n */\n\nimport type { ApplicatorHandler } from \"./index.js\";\n\n/**\n * Parse a size value and return CSS-compatible string.\n * Ensures cross-platform compatibility with Android/iOS.\n */\nfunction parseSizeValue(value: any): string | null {\n if (value === null || value === undefined) return null;\n\n // Numbers default to px\n if (typeof value === \"number\") {\n return `${value}px`;\n }\n\n const str = String(value).trim().toLowerCase();\n\n // Keywords\n switch (str) {\n case \"fill\":\n case \"match_parent\":\n return \"100%\";\n case \"wrap\":\n case \"wrap_content\":\n case \"auto\":\n return \"auto\";\n case \"infinity\":\n case \"inf\":\n case \"max\":\n return \"100%\";\n }\n\n // Parse value with unit\n const match = str.match(/^(-?[\\d.]+)\\s*(px|dp|pt|%|vw|vh|vmin|vmax|em|rem)?$/);\n if (!match) {\n // Pass through other CSS values as-is (e.g., \"calc(...)\", \"fit-content\")\n return str;\n }\n\n const num = parseFloat(match[1]);\n const unit = match[2] || \"px\";\n\n switch (unit) {\n case \"px\":\n // Absolute pixels - use as-is\n return `${num}px`;\n case \"dp\":\n case \"pt\":\n // Density-independent points\n // On web, 1dp/1pt ≈ 1px at standard density (96dpi)\n // CSS already handles this via px, so we just use px\n // For true density independence, we'd need to query devicePixelRatio\n // but CSS px is already defined as 1/96th of an inch\n return `${num}px`;\n case \"%\":\n return `${num}%`;\n case \"vw\":\n return `${num}vw`;\n case \"vh\":\n return `${num}vh`;\n case \"vmin\":\n return `${num}vmin`;\n case \"vmax\":\n return `${num}vmax`;\n case \"em\":\n return `${num}em`;\n case \"rem\":\n return `${num}rem`;\n default:\n return `${num}px`;\n }\n}\n\nexport const sizeHandlers: Record<string, ApplicatorHandler> = {\n width: (el, value) => {\n const size = parseSizeValue(value);\n if (size) el.style.width = size;\n },\n\n height: (el, value) => {\n const size = parseSizeValue(value);\n if (size) el.style.height = size;\n },\n\n minWidth: (el, value) => {\n const size = parseSizeValue(value);\n if (size) el.style.minWidth = size;\n },\n\n minHeight: (el, value) => {\n const size = parseSizeValue(value);\n if (size) el.style.minHeight = size;\n },\n\n maxWidth: (el, value) => {\n const size = parseSizeValue(value);\n if (size) el.style.maxWidth = size;\n },\n\n maxHeight: (el, value) => {\n const size = parseSizeValue(value);\n if (size) el.style.maxHeight = size;\n },\n\n // Combined size applicator - sets both width and height\n size: (el, value) => {\n if (typeof value === \"object\" && value !== null) {\n const obj = value as Record<string, any>;\n if (obj.width !== undefined) {\n const w = parseSizeValue(obj.width);\n if (w) el.style.width = w;\n }\n if (obj.height !== undefined) {\n const h = parseSizeValue(obj.height);\n if (h) el.style.height = h;\n }\n } else {\n const size = parseSizeValue(value);\n if (size) {\n el.style.width = size;\n el.style.height = size;\n }\n }\n },\n\n // Fill max width - shorthand for width: 100%\n fillMaxWidth: (el, value) => {\n if (value === false) return;\n // Value can be a fraction (0-1) or boolean\n const fraction = typeof value === \"number\" ? value : 1;\n el.style.width = `${fraction * 100}%`;\n },\n\n // Fill max height - shorthand for height: 100%\n fillMaxHeight: (el, value) => {\n if (value === false) return;\n // Value can be a fraction (0-1) or boolean\n const fraction = typeof value === \"number\" ? value : 1;\n el.style.height = `${fraction * 100}%`;\n },\n\n // Fill max size - shorthand for width: 100% and height: 100%\n fillMaxSize: (el, value) => {\n if (value === false) return;\n // Value can be a fraction (0-1) or boolean\n const fraction = typeof value === \"number\" ? value : 1;\n el.style.width = `${fraction * 100}%`;\n el.style.height = `${fraction * 100}%`;\n },\n};\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAMa;AAAA;AAAA,iBAAkD;AAAA,IAC7D,OAAO,CAAC,IAAI,UAAU;AAAA,MACpB,GAAG,MAAM,QAAQ,OAAO,UAAU,WAAW,GAAG,YAAY,OAAO,KAAK;AAAA;AAAA,IAG1E,QAAQ,CAAC,IAAI,UAAU;AAAA,MACrB,GAAG,MAAM,SAAS,OAAO,UAAU,WAAW,GAAG,YAAY,OAAO,KAAK;AAAA;AAAA,IAG3E,UAAU,CAAC,IAAI,UAAU;AAAA,MACvB,GAAG,MAAM,WAAW,OAAO,UAAU,WAAW,GAAG,YAAY,OAAO,KAAK;AAAA;AAAA,IAG7E,WAAW,CAAC,IAAI,UAAU;AAAA,MACxB,GAAG,MAAM,YAAY,OAAO,UAAU,WAAW,GAAG,YAAY,OAAO,KAAK;AAAA;AAAA,IAG9E,UAAU,CAAC,IAAI,UAAU;AAAA,MACvB,GAAG,MAAM,WAAW,OAAO,UAAU,WAAW,GAAG,YAAY,OAAO,KAAK;AAAA;AAAA,IAG7E,WAAW,CAAC,IAAI,UAAU;AAAA,MACxB,GAAG,MAAM,YAAY,OAAO,UAAU,WAAW,GAAG,YAAY,OAAO,KAAK;AAAA;AAAA,IAI9E,MAAM,CAAC,IAAI,UAAU;AAAA,MACnB,IAAI,OAAO,UAAU,UAAU;AAAA,QAC7B,GAAG,MAAM,QAAQ,GAAG;AAAA,QACpB,GAAG,MAAM,SAAS,GAAG;AAAA,MACvB,EAAO,SAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAAA,QACtD,MAAM,MAAM;AAAA,QACZ,IAAI,IAAI,UAAU,WAAW;AAAA,UAC3B,GAAG,MAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,GAAG,IAAI,YAAY,OAAO,IAAI,KAAK;AAAA,QACtF;AAAA,QACA,IAAI,IAAI,WAAW,WAAW;AAAA,UAC5B,GAAG,MAAM,SAAS,OAAO,IAAI,WAAW,WAAW,GAAG,IAAI,aAAa,OAAO,IAAI,MAAM;AAAA,QAC1F;AAAA,MACF,EAAO;AAAA,QAEL,MAAM,OAAO,OAAO,KAAK;AAAA,QACzB,GAAG,MAAM,QAAQ;AAAA,QACjB,GAAG,MAAM,SAAS;AAAA;AAAA;AAAA,IAKtB,cAAc,CAAC,IAAI,UAAU;AAAA,MAC3B,IAAI,UAAU;AAAA,QAAO;AAAA,MAErB,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ;AAAA,MACrD,GAAG,MAAM,QAAQ,GAAG,WAAW;AAAA;AAAA,IAIjC,eAAe,CAAC,IAAI,UAAU;AAAA,MAC5B,IAAI,UAAU;AAAA,QAAO;AAAA,MAErB,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ;AAAA,MACrD,GAAG,MAAM,SAAS,GAAG,WAAW;AAAA;AAAA,IAIlC,aAAa,CAAC,IAAI,UAAU;AAAA,MAC1B,IAAI,UAAU;AAAA,QAAO;AAAA,MAErB,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ;AAAA,MACrD,GAAG,MAAM,QAAQ,GAAG,WAAW;AAAA,MAC/B,GAAG,MAAM,SAAS,GAAG,WAAW;AAAA;AAAA,EAEpC;AAAA;",
8
- "debugId": "6AEB29B00DD38BB964756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "4734BF3C18B80B6664756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,296 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
6
+ var __toCommonJS = (from) => {
7
+ var entry = __moduleCache.get(from), desc;
8
+ if (entry)
9
+ return entry;
10
+ entry = __defProp({}, "__esModule", { value: true });
11
+ if (from && typeof from === "object" || typeof from === "function")
12
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ }));
16
+ __moduleCache.set(from, entry);
17
+ return entry;
18
+ };
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
29
+
30
+ // src/dom/components/hypenapp.ts
31
+ var exports_hypenapp = {};
32
+ __export(exports_hypenapp, {
33
+ hypenAppHandler: () => hypenAppHandler,
34
+ disconnectHypenApp: () => disconnectHypenApp
35
+ });
36
+ import { RemoteEngine } from "@hypen-space/core/remote/client";
37
+ function applyPatches(container, nodes, patches, engine, onRoot) {
38
+ for (const patch of patches) {
39
+ switch (patch.type) {
40
+ case "create": {
41
+ const el = createElement(patch.element_type, patch.props || {});
42
+ el.dataset.hypenId = patch.id;
43
+ el.__hypenEngine = engine;
44
+ nodes.set(patch.id, el);
45
+ break;
46
+ }
47
+ case "setProp": {
48
+ const el = nodes.get(patch.id);
49
+ if (el) {
50
+ applyProp(el, patch.name, patch.value);
51
+ }
52
+ break;
53
+ }
54
+ case "setText": {
55
+ const el = nodes.get(patch.id);
56
+ if (el) {
57
+ el.textContent = patch.text;
58
+ }
59
+ break;
60
+ }
61
+ case "insert": {
62
+ const parentId = patch.parent_id;
63
+ const parent = parentId === "root" ? container : nodes.get(parentId);
64
+ const child = nodes.get(patch.id);
65
+ const beforeId = patch.before_id;
66
+ if (parent && child) {
67
+ if (parentId === "root") {
68
+ onRoot(patch.id);
69
+ }
70
+ if (beforeId) {
71
+ const before = nodes.get(beforeId);
72
+ if (before && before.parentNode === parent) {
73
+ parent.insertBefore(child, before);
74
+ } else if (!parent.contains(child)) {
75
+ parent.appendChild(child);
76
+ }
77
+ } else if (!parent.contains(child)) {
78
+ parent.appendChild(child);
79
+ }
80
+ }
81
+ break;
82
+ }
83
+ case "move": {
84
+ const parentId = patch.parent_id;
85
+ const parent = parentId === "root" ? container : nodes.get(parentId);
86
+ const child = nodes.get(patch.id);
87
+ const beforeId = patch.before_id;
88
+ if (parent && child) {
89
+ if (beforeId) {
90
+ const before = nodes.get(beforeId);
91
+ if (before && before.parentNode === parent) {
92
+ parent.insertBefore(child, before);
93
+ }
94
+ } else {
95
+ parent.appendChild(child);
96
+ }
97
+ }
98
+ break;
99
+ }
100
+ case "remove": {
101
+ const el = nodes.get(patch.id);
102
+ if (el && el.parentNode) {
103
+ el.parentNode.removeChild(el);
104
+ }
105
+ nodes.delete(patch.id);
106
+ break;
107
+ }
108
+ }
109
+ }
110
+ }
111
+ function createElement(type, props) {
112
+ const normalizedType = type.toLowerCase();
113
+ const tagMap = {
114
+ column: "div",
115
+ row: "div",
116
+ text: "span",
117
+ button: "button",
118
+ input: "input",
119
+ image: "img",
120
+ container: "div",
121
+ box: "div",
122
+ center: "div",
123
+ list: "div",
124
+ spacer: "div",
125
+ stack: "div",
126
+ divider: "hr",
127
+ grid: "div",
128
+ card: "div",
129
+ heading: "h2",
130
+ link: "a",
131
+ textarea: "textarea",
132
+ checkbox: "input",
133
+ select: "select",
134
+ slider: "input",
135
+ switch: "input",
136
+ spinner: "div",
137
+ badge: "span",
138
+ avatar: "img",
139
+ progressbar: "div",
140
+ video: "video",
141
+ audio: "audio"
142
+ };
143
+ const tag = tagMap[normalizedType] || "div";
144
+ const el = document.createElement(tag);
145
+ el.dataset.hypenType = normalizedType;
146
+ if (normalizedType === "column") {
147
+ el.style.display = "flex";
148
+ el.style.flexDirection = "column";
149
+ } else if (normalizedType === "row") {
150
+ el.style.display = "flex";
151
+ el.style.flexDirection = "row";
152
+ } else if (normalizedType === "center") {
153
+ el.style.display = "flex";
154
+ el.style.alignItems = "center";
155
+ el.style.justifyContent = "center";
156
+ } else if (normalizedType === "text") {
157
+ if (props["0"]) {
158
+ el.textContent = String(props["0"]);
159
+ }
160
+ } else if (normalizedType === "button") {
161
+ el.style.cursor = "pointer";
162
+ } else if (normalizedType === "checkbox" || normalizedType === "switch") {
163
+ el.type = "checkbox";
164
+ } else if (normalizedType === "slider") {
165
+ el.type = "range";
166
+ }
167
+ return el;
168
+ }
169
+ function applyProp(el, name, value) {
170
+ if (name === "0" || name === "text") {
171
+ el.textContent = String(value);
172
+ return;
173
+ }
174
+ const styleProps = {
175
+ padding: "padding",
176
+ margin: "margin",
177
+ backgroundColor: "backgroundColor",
178
+ background: "background",
179
+ color: "color",
180
+ fontSize: "fontSize",
181
+ fontWeight: "fontWeight",
182
+ width: "width",
183
+ height: "height",
184
+ minWidth: "minWidth",
185
+ minHeight: "minHeight",
186
+ maxWidth: "maxWidth",
187
+ maxHeight: "maxHeight",
188
+ borderRadius: "borderRadius",
189
+ border: "border",
190
+ gap: "gap",
191
+ flex: "flex",
192
+ alignItems: "alignItems",
193
+ justifyContent: "justifyContent",
194
+ opacity: "opacity",
195
+ overflow: "overflow"
196
+ };
197
+ if (styleProps[name]) {
198
+ const cssValue = typeof value === "number" ? `${value}px` : String(value);
199
+ el.style[styleProps[name]] = cssValue;
200
+ return;
201
+ }
202
+ if (name === "onClick" || name === "onclick") {
203
+ el.onclick = () => {
204
+ const engine = el.__hypenEngine;
205
+ if (engine && typeof value === "string" && value.startsWith("@actions.")) {
206
+ const action = value.replace("@actions.", "");
207
+ engine.dispatchAction(action);
208
+ }
209
+ };
210
+ return;
211
+ }
212
+ el.setAttribute(name, String(value));
213
+ }
214
+ function disconnectHypenApp(element) {
215
+ const instance = activeInstances.get(element);
216
+ if (instance) {
217
+ instance.engine.disconnect();
218
+ activeInstances.delete(element);
219
+ }
220
+ }
221
+ var activeInstances, hypenAppHandler;
222
+ var init_hypenapp = __esm(() => {
223
+ activeInstances = new WeakMap;
224
+ hypenAppHandler = {
225
+ create() {
226
+ const el = document.createElement("div");
227
+ el.dataset.hypenType = "hypenapp";
228
+ el.style.display = "contents";
229
+ return el;
230
+ },
231
+ applyProps(element, props) {
232
+ const url = props["0"] || props.url;
233
+ if (!url || typeof url !== "string") {
234
+ console.error("[HypenApp] URL is required");
235
+ element.innerHTML = '<div style="color: red;">HypenApp: URL required</div>';
236
+ return;
237
+ }
238
+ const existing = activeInstances.get(element);
239
+ if (existing) {
240
+ return;
241
+ }
242
+ const engine = new RemoteEngine(url, {
243
+ autoReconnect: props.autoReconnect ?? true,
244
+ reconnectInterval: props.reconnectInterval ?? 3000,
245
+ maxReconnectAttempts: props.maxReconnectAttempts ?? 10
246
+ });
247
+ const nodes = new Map;
248
+ let rootId = null;
249
+ activeInstances.set(element, { engine, nodes });
250
+ engine.onPatches((patches) => {
251
+ applyPatches(element, nodes, patches, engine, (id) => {
252
+ if (!rootId)
253
+ rootId = id;
254
+ });
255
+ });
256
+ element.innerHTML = '<div class="hypen-app-loading">Connecting...</div>';
257
+ engine.connect().then(() => {
258
+ element.innerHTML = "";
259
+ console.log(`[HypenApp] Connected to ${url}`);
260
+ }).catch((error) => {
261
+ element.innerHTML = `<div style="color: red;">HypenApp: Connection failed - ${error.message}</div>`;
262
+ console.error("[HypenApp] Connection failed:", error);
263
+ });
264
+ engine.onDisconnect(() => {
265
+ console.log("[HypenApp] Disconnected");
266
+ });
267
+ engine.onError((error) => {
268
+ console.error("[HypenApp] Error:", error);
269
+ });
270
+ const observer = new MutationObserver((mutations) => {
271
+ for (const mutation of mutations) {
272
+ for (const removedNode of mutation.removedNodes) {
273
+ if (removedNode === element || removedNode.contains?.(element)) {
274
+ engine.disconnect();
275
+ activeInstances.delete(element);
276
+ observer.disconnect();
277
+ console.log("[HypenApp] Cleaned up");
278
+ return;
279
+ }
280
+ }
281
+ }
282
+ });
283
+ if (element.parentNode) {
284
+ observer.observe(element.parentNode, { childList: true, subtree: true });
285
+ }
286
+ }
287
+ };
288
+ });
289
+ init_hypenapp();
290
+
291
+ export {
292
+ hypenAppHandler,
293
+ disconnectHypenApp
294
+ };
295
+
296
+ //# debugId=FF8625BC3E34C63E64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/dom/components/hypenapp.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * HypenApp Component\n *\n * Embeds a remote Hypen app via WebSocket\n *\n * Usage in Hypen DSL:\n * ```hypen\n * HypenApp(\"ws://localhost:3000\")\n *\n * // Or with named prop:\n * HypenApp(url: \"ws://localhost:3000\")\n * ```\n */\n\nimport type { ComponentHandler } from \"./index.js\";\nimport { RemoteEngine } from \"@hypen-space/core/remote/client\";\nimport type { Patch } from \"@hypen-space/core/remote\";\n\n// Store active HypenApp instances for cleanup\nconst activeInstances = new WeakMap<\n HTMLElement,\n {\n engine: RemoteEngine;\n nodes: Map<string, HTMLElement>;\n }\n>();\n\nexport const hypenAppHandler: ComponentHandler = {\n create(): HTMLElement {\n const el = document.createElement(\"div\");\n el.dataset.hypenType = \"hypenapp\";\n el.style.display = \"contents\"; // Don't affect layout\n return el;\n },\n\n applyProps(element: HTMLElement, props: Record<string, any>): void {\n // Get URL from props (can be positional \"0\" or named \"url\")\n const url = props[\"0\"] || props.url;\n\n if (!url || typeof url !== \"string\") {\n console.error(\"[HypenApp] URL is required\");\n element.innerHTML = '<div style=\"color: red;\">HypenApp: URL required</div>';\n return;\n }\n\n // Check if already connected\n const existing = activeInstances.get(element);\n if (existing) {\n // Already connected, don't reconnect\n return;\n }\n\n // Create the remote engine\n const engine = new RemoteEngine(url, {\n autoReconnect: props.autoReconnect ?? true,\n reconnectInterval: props.reconnectInterval ?? 3000,\n maxReconnectAttempts: props.maxReconnectAttempts ?? 10,\n });\n\n // Map to track created nodes\n const nodes = new Map<string, HTMLElement>();\n let rootId: string | null = null;\n\n // Store instance for cleanup\n activeInstances.set(element, { engine, nodes });\n\n // Set up patch handling\n engine.onPatches((patches) => {\n applyPatches(element, nodes, patches, engine, (id) => {\n if (!rootId) rootId = id;\n });\n });\n\n // Show loading state\n element.innerHTML = '<div class=\"hypen-app-loading\">Connecting...</div>';\n\n // Connect\n engine\n .connect()\n .then(() => {\n // Clear loading state - patches will populate content\n element.innerHTML = \"\";\n console.log(`[HypenApp] Connected to ${url}`);\n })\n .catch((error) => {\n element.innerHTML = `<div style=\"color: red;\">HypenApp: Connection failed - ${error.message}</div>`;\n console.error(\"[HypenApp] Connection failed:\", error);\n });\n\n // Handle disconnection\n engine.onDisconnect(() => {\n console.log(\"[HypenApp] Disconnected\");\n });\n\n engine.onError((error) => {\n console.error(\"[HypenApp] Error:\", error);\n });\n\n // Cleanup on element removal\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const removedNode of mutation.removedNodes) {\n if (removedNode === element || (removedNode as Element).contains?.(element)) {\n engine.disconnect();\n activeInstances.delete(element);\n observer.disconnect();\n console.log(\"[HypenApp] Cleaned up\");\n return;\n }\n }\n }\n });\n\n // Observe parent for removal\n if (element.parentNode) {\n observer.observe(element.parentNode, { childList: true, subtree: true });\n }\n },\n};\n\n/**\n * Minimal patch application for HypenApp container\n */\nfunction applyPatches(\n container: HTMLElement,\n nodes: Map<string, HTMLElement>,\n patches: Patch[],\n engine: RemoteEngine,\n onRoot: (id: string) => void\n): void {\n for (const patch of patches) {\n switch (patch.type) {\n case \"create\": {\n const el = createElement((patch as any).element_type, patch.props || {});\n el.dataset.hypenId = patch.id!;\n (el as any).__hypenEngine = engine;\n nodes.set(patch.id!, el);\n break;\n }\n\n case \"setProp\": {\n const el = nodes.get(patch.id!);\n if (el) {\n applyProp(el, patch.name!, patch.value);\n }\n break;\n }\n\n case \"setText\": {\n const el = nodes.get(patch.id!);\n if (el) {\n el.textContent = patch.text!;\n }\n break;\n }\n\n case \"insert\": {\n const parentId = (patch as any).parent_id;\n const parent = parentId === \"root\" ? container : nodes.get(parentId);\n const child = nodes.get(patch.id!);\n const beforeId = (patch as any).before_id;\n\n if (parent && child) {\n if (parentId === \"root\") {\n onRoot(patch.id!);\n }\n\n if (beforeId) {\n const before = nodes.get(beforeId);\n if (before && before.parentNode === parent) {\n parent.insertBefore(child, before);\n } else if (!parent.contains(child)) {\n parent.appendChild(child);\n }\n } else if (!parent.contains(child)) {\n parent.appendChild(child);\n }\n }\n break;\n }\n\n case \"move\": {\n const parentId = (patch as any).parent_id;\n const parent = parentId === \"root\" ? container : nodes.get(parentId);\n const child = nodes.get(patch.id!);\n const beforeId = (patch as any).before_id;\n\n if (parent && child) {\n if (beforeId) {\n const before = nodes.get(beforeId);\n if (before && before.parentNode === parent) {\n parent.insertBefore(child, before);\n }\n } else {\n parent.appendChild(child);\n }\n }\n break;\n }\n\n case \"remove\": {\n const el = nodes.get(patch.id!);\n if (el && el.parentNode) {\n el.parentNode.removeChild(el);\n }\n nodes.delete(patch.id!);\n break;\n }\n }\n }\n}\n\n/**\n * Create element by type\n */\nfunction createElement(type: string, props: Record<string, any>): HTMLElement {\n const normalizedType = type.toLowerCase();\n\n // Map Hypen types to HTML elements\n const tagMap: Record<string, string> = {\n column: \"div\",\n row: \"div\",\n text: \"span\",\n button: \"button\",\n input: \"input\",\n image: \"img\",\n container: \"div\",\n box: \"div\",\n center: \"div\",\n list: \"div\",\n spacer: \"div\",\n stack: \"div\",\n divider: \"hr\",\n grid: \"div\",\n card: \"div\",\n heading: \"h2\",\n link: \"a\",\n textarea: \"textarea\",\n checkbox: \"input\",\n select: \"select\",\n slider: \"input\",\n switch: \"input\",\n spinner: \"div\",\n badge: \"span\",\n avatar: \"img\",\n progressbar: \"div\",\n video: \"video\",\n audio: \"audio\",\n };\n\n const tag = tagMap[normalizedType] || \"div\";\n const el = document.createElement(tag);\n el.dataset.hypenType = normalizedType;\n\n // Apply basic styles\n if (normalizedType === \"column\") {\n el.style.display = \"flex\";\n el.style.flexDirection = \"column\";\n } else if (normalizedType === \"row\") {\n el.style.display = \"flex\";\n el.style.flexDirection = \"row\";\n } else if (normalizedType === \"center\") {\n el.style.display = \"flex\";\n el.style.alignItems = \"center\";\n el.style.justifyContent = \"center\";\n } else if (normalizedType === \"text\") {\n // Text content from props\n if (props[\"0\"]) {\n el.textContent = String(props[\"0\"]);\n }\n } else if (normalizedType === \"button\") {\n el.style.cursor = \"pointer\";\n } else if (normalizedType === \"checkbox\" || normalizedType === \"switch\") {\n (el as HTMLInputElement).type = \"checkbox\";\n } else if (normalizedType === \"slider\") {\n (el as HTMLInputElement).type = \"range\";\n }\n\n return el;\n}\n\n/**\n * Apply a prop to an element\n */\nfunction applyProp(el: HTMLElement, name: string, value: any): void {\n // Text content\n if (name === \"0\" || name === \"text\") {\n el.textContent = String(value);\n return;\n }\n\n // Style props\n const styleProps: Record<string, string> = {\n padding: \"padding\",\n margin: \"margin\",\n backgroundColor: \"backgroundColor\",\n background: \"background\",\n color: \"color\",\n fontSize: \"fontSize\",\n fontWeight: \"fontWeight\",\n width: \"width\",\n height: \"height\",\n minWidth: \"minWidth\",\n minHeight: \"minHeight\",\n maxWidth: \"maxWidth\",\n maxHeight: \"maxHeight\",\n borderRadius: \"borderRadius\",\n border: \"border\",\n gap: \"gap\",\n flex: \"flex\",\n alignItems: \"alignItems\",\n justifyContent: \"justifyContent\",\n opacity: \"opacity\",\n overflow: \"overflow\",\n };\n\n if (styleProps[name]) {\n const cssValue = typeof value === \"number\" ? `${value}px` : String(value);\n (el.style as any)[styleProps[name]] = cssValue;\n return;\n }\n\n // Event handlers\n if (name === \"onClick\" || name === \"onclick\") {\n el.onclick = () => {\n const engine = (el as any).__hypenEngine as RemoteEngine;\n if (engine && typeof value === \"string\" && value.startsWith(\"@actions.\")) {\n const action = value.replace(\"@actions.\", \"\");\n engine.dispatchAction(action);\n }\n };\n return;\n }\n\n // Other attributes\n el.setAttribute(name, String(value));\n}\n\n/**\n * Disconnect a HypenApp instance\n */\nexport function disconnectHypenApp(element: HTMLElement): void {\n const instance = activeInstances.get(element);\n if (instance) {\n instance.engine.disconnect();\n activeInstances.delete(element);\n }\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "FF8625BC3E34C63E64756E2164756E21",
9
+ "names": []
10
+ }