@nuraly/lumenjs 0.1.2 → 0.1.4

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 (337) hide show
  1. package/README.md +76 -235
  2. package/dist/auth/config.d.ts +23 -0
  3. package/dist/auth/config.js +115 -0
  4. package/dist/auth/guard.d.ts +12 -0
  5. package/dist/auth/guard.js +28 -0
  6. package/dist/auth/index.d.ts +3 -0
  7. package/dist/auth/index.js +1 -0
  8. package/dist/auth/middleware.d.ts +23 -0
  9. package/dist/auth/middleware.js +89 -0
  10. package/dist/auth/native-auth.d.ts +73 -0
  11. package/dist/auth/native-auth.js +293 -0
  12. package/dist/auth/oidc-client.d.ts +17 -0
  13. package/dist/auth/oidc-client.js +123 -0
  14. package/dist/auth/providers/google.d.ts +23 -0
  15. package/dist/auth/providers/google.js +25 -0
  16. package/dist/auth/providers/index.d.ts +2 -0
  17. package/dist/auth/providers/index.js +1 -0
  18. package/dist/auth/routes/login.d.ts +8 -0
  19. package/dist/auth/routes/login.js +98 -0
  20. package/dist/auth/routes/logout.d.ts +4 -0
  21. package/dist/auth/routes/logout.js +79 -0
  22. package/dist/auth/routes/oidc-callback.d.ts +3 -0
  23. package/dist/auth/routes/oidc-callback.js +70 -0
  24. package/dist/auth/routes/password.d.ts +5 -0
  25. package/dist/auth/routes/password.js +149 -0
  26. package/dist/auth/routes/signup.d.ts +3 -0
  27. package/dist/auth/routes/signup.js +81 -0
  28. package/dist/auth/routes/token.d.ts +4 -0
  29. package/dist/auth/routes/token.js +70 -0
  30. package/dist/auth/routes/utils.d.ts +7 -0
  31. package/dist/auth/routes/utils.js +35 -0
  32. package/dist/auth/routes/verify.d.ts +3 -0
  33. package/dist/auth/routes/verify.js +26 -0
  34. package/dist/auth/routes.d.ts +8 -0
  35. package/dist/auth/routes.js +110 -0
  36. package/dist/auth/session.d.ts +8 -0
  37. package/dist/auth/session.js +54 -0
  38. package/dist/auth/token.d.ts +33 -0
  39. package/dist/auth/token.js +90 -0
  40. package/dist/auth/types.d.ts +156 -0
  41. package/dist/auth/types.js +2 -0
  42. package/dist/build/build-client.d.ts +15 -0
  43. package/dist/build/build-client.js +45 -0
  44. package/dist/build/build-prerender.d.ts +11 -0
  45. package/dist/build/build-prerender.js +159 -0
  46. package/dist/build/build-server.d.ts +17 -0
  47. package/dist/build/build-server.js +98 -0
  48. package/dist/build/build.js +52 -120
  49. package/dist/build/scan.d.ts +19 -0
  50. package/dist/build/scan.js +77 -6
  51. package/dist/build/serve-api.js +8 -2
  52. package/dist/build/serve-loaders.d.ts +4 -2
  53. package/dist/build/serve-loaders.js +128 -10
  54. package/dist/build/serve-ssr.js +38 -11
  55. package/dist/build/serve-static.js +3 -3
  56. package/dist/build/serve.js +229 -14
  57. package/dist/cli.js +37 -6
  58. package/dist/communication/encryption.d.ts +35 -0
  59. package/dist/communication/encryption.js +90 -0
  60. package/dist/communication/handlers/context.d.ts +27 -0
  61. package/dist/communication/handlers/context.js +1 -0
  62. package/dist/communication/handlers/conversation.d.ts +24 -0
  63. package/dist/communication/handlers/conversation.js +113 -0
  64. package/dist/communication/handlers/file-upload.d.ts +17 -0
  65. package/dist/communication/handlers/file-upload.js +62 -0
  66. package/dist/communication/handlers/messaging.d.ts +30 -0
  67. package/dist/communication/handlers/messaging.js +237 -0
  68. package/dist/communication/handlers/presence.d.ts +15 -0
  69. package/dist/communication/handlers/presence.js +76 -0
  70. package/dist/communication/handlers.d.ts +5 -0
  71. package/dist/communication/handlers.js +5 -0
  72. package/dist/communication/index.d.ts +9 -0
  73. package/dist/communication/index.js +7 -0
  74. package/dist/communication/link-preview.d.ts +18 -0
  75. package/dist/communication/link-preview.js +115 -0
  76. package/dist/communication/schema.d.ts +10 -0
  77. package/dist/communication/schema.js +101 -0
  78. package/dist/communication/server.d.ts +86 -0
  79. package/dist/communication/server.js +212 -0
  80. package/dist/communication/signaling.d.ts +43 -0
  81. package/dist/communication/signaling.js +271 -0
  82. package/dist/communication/store.d.ts +71 -0
  83. package/dist/communication/store.js +289 -0
  84. package/dist/communication/types.d.ts +454 -0
  85. package/dist/communication/types.js +1 -0
  86. package/dist/create.d.ts +1 -0
  87. package/dist/create.js +55 -0
  88. package/dist/db/auto-migrate.d.ts +3 -0
  89. package/dist/db/auto-migrate.js +100 -0
  90. package/dist/db/client.d.ts +3 -0
  91. package/dist/db/client.js +18 -0
  92. package/dist/db/context.d.ts +2 -0
  93. package/dist/db/context.js +9 -0
  94. package/dist/db/index.d.ts +23 -0
  95. package/dist/db/index.js +258 -0
  96. package/dist/db/seed.d.ts +12 -0
  97. package/dist/db/seed.js +88 -0
  98. package/dist/db/table.d.ts +10 -0
  99. package/dist/db/table.js +12 -0
  100. package/dist/dev-server/config.d.ts +14 -0
  101. package/dist/dev-server/config.js +26 -9
  102. package/dist/dev-server/index-html.d.ts +3 -0
  103. package/dist/dev-server/index-html.js +18 -6
  104. package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
  105. package/dist/dev-server/nuralyui-aliases.js +115 -94
  106. package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
  107. package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
  108. package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
  109. package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
  110. package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
  111. package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
  112. package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
  113. package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
  114. package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
  115. package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
  116. package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
  117. package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
  118. package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
  119. package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
  120. package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
  121. package/dist/dev-server/plugins/vite-plugin-loaders.d.ts +0 -1
  122. package/dist/dev-server/plugins/vite-plugin-loaders.js +311 -42
  123. package/dist/dev-server/plugins/vite-plugin-routes.js +18 -6
  124. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  125. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  126. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  127. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  128. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  129. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  130. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
  131. package/dist/dev-server/server.js +128 -12
  132. package/dist/dev-server/ssr-render.d.ts +2 -1
  133. package/dist/dev-server/ssr-render.js +107 -48
  134. package/dist/editor/ai/backend.d.ts +20 -0
  135. package/dist/editor/ai/backend.js +104 -0
  136. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  137. package/dist/editor/ai/claude-code-client.js +145 -0
  138. package/dist/editor/ai/opencode-client.d.ts +14 -0
  139. package/dist/editor/ai/opencode-client.js +125 -0
  140. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  141. package/dist/editor/ai/snapshot-store.js +35 -0
  142. package/dist/editor/ai/types.d.ts +30 -0
  143. package/dist/editor/ai/types.js +136 -0
  144. package/dist/editor/ai-chat-panel.d.ts +13 -0
  145. package/dist/editor/ai-chat-panel.js +587 -0
  146. package/dist/editor/ai-markdown.d.ts +10 -0
  147. package/dist/editor/ai-markdown.js +70 -0
  148. package/dist/editor/ai-project-panel.d.ts +11 -0
  149. package/dist/editor/ai-project-panel.js +332 -0
  150. package/dist/editor/ast-modification.d.ts +11 -0
  151. package/dist/editor/ast-modification.js +1 -0
  152. package/dist/editor/ast-service.d.ts +30 -0
  153. package/dist/editor/ast-service.js +180 -0
  154. package/dist/editor/css-rules.d.ts +54 -0
  155. package/dist/editor/css-rules.js +423 -0
  156. package/dist/editor/editor-api-client.d.ts +51 -0
  157. package/dist/editor/editor-api-client.js +162 -0
  158. package/dist/editor/editor-bridge.d.ts +1 -0
  159. package/dist/editor/editor-bridge.js +17 -8
  160. package/dist/editor/editor-toolbar.d.ts +14 -0
  161. package/dist/editor/editor-toolbar.js +115 -0
  162. package/dist/editor/file-editor.d.ts +9 -0
  163. package/dist/editor/file-editor.js +236 -0
  164. package/dist/editor/file-service.d.ts +16 -0
  165. package/dist/editor/file-service.js +52 -0
  166. package/dist/editor/i18n-key-gen.d.ts +1 -0
  167. package/dist/editor/i18n-key-gen.js +7 -0
  168. package/dist/editor/inline-text-edit.d.ts +5 -0
  169. package/dist/editor/inline-text-edit.js +173 -92
  170. package/dist/editor/overlay-events.d.ts +5 -0
  171. package/dist/editor/overlay-events.js +364 -0
  172. package/dist/editor/overlay-hmr.d.ts +2 -0
  173. package/dist/editor/overlay-hmr.js +75 -0
  174. package/dist/editor/overlay-selection.d.ts +29 -0
  175. package/dist/editor/overlay-selection.js +148 -0
  176. package/dist/editor/overlay-utils.d.ts +12 -0
  177. package/dist/editor/overlay-utils.js +59 -0
  178. package/dist/editor/properties-panel-persist.d.ts +14 -0
  179. package/dist/editor/properties-panel-persist.js +70 -0
  180. package/dist/editor/properties-panel-rows.d.ts +10 -0
  181. package/dist/editor/properties-panel-rows.js +349 -0
  182. package/dist/editor/properties-panel-styles.d.ts +4 -0
  183. package/dist/editor/properties-panel-styles.js +174 -0
  184. package/dist/editor/properties-panel.d.ts +4 -0
  185. package/dist/editor/properties-panel.js +148 -0
  186. package/dist/editor/property-registry.d.ts +16 -0
  187. package/dist/editor/property-registry.js +303 -0
  188. package/dist/editor/standalone-file-panel.d.ts +0 -0
  189. package/dist/editor/standalone-file-panel.js +1 -0
  190. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  191. package/dist/editor/standalone-overlay-dom.js +1 -0
  192. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  193. package/dist/editor/standalone-overlay-styles.js +1 -0
  194. package/dist/editor/standalone-overlay.d.ts +1 -0
  195. package/dist/editor/standalone-overlay.js +76 -0
  196. package/dist/editor/syntax-highlighter.d.ts +4 -0
  197. package/dist/editor/syntax-highlighter.js +81 -0
  198. package/dist/editor/text-toolbar.d.ts +11 -0
  199. package/dist/editor/text-toolbar.js +327 -0
  200. package/dist/editor/toolbar-styles.d.ts +4 -0
  201. package/dist/editor/toolbar-styles.js +198 -0
  202. package/dist/email/index.d.ts +32 -0
  203. package/dist/email/index.js +154 -0
  204. package/dist/email/providers/resend.d.ts +2 -0
  205. package/dist/email/providers/resend.js +24 -0
  206. package/dist/email/providers/sendgrid.d.ts +2 -0
  207. package/dist/email/providers/sendgrid.js +31 -0
  208. package/dist/email/providers/smtp.d.ts +13 -0
  209. package/dist/email/providers/smtp.js +125 -0
  210. package/dist/email/template-engine.d.ts +18 -0
  211. package/dist/email/template-engine.js +116 -0
  212. package/dist/email/templates/base.d.ts +9 -0
  213. package/dist/email/templates/base.js +65 -0
  214. package/dist/email/templates/password-reset.d.ts +5 -0
  215. package/dist/email/templates/password-reset.js +15 -0
  216. package/dist/email/templates/verify-email.d.ts +5 -0
  217. package/dist/email/templates/verify-email.js +15 -0
  218. package/dist/email/templates/welcome.d.ts +5 -0
  219. package/dist/email/templates/welcome.js +13 -0
  220. package/dist/email/types.d.ts +49 -0
  221. package/dist/email/types.js +1 -0
  222. package/dist/llms/generate.d.ts +46 -0
  223. package/dist/llms/generate.js +185 -0
  224. package/dist/permissions/guard.d.ts +28 -0
  225. package/dist/permissions/guard.js +30 -0
  226. package/dist/permissions/index.d.ts +6 -0
  227. package/dist/permissions/index.js +3 -0
  228. package/dist/permissions/service.d.ts +80 -0
  229. package/dist/permissions/service.js +210 -0
  230. package/dist/permissions/tables.d.ts +5 -0
  231. package/dist/permissions/tables.js +68 -0
  232. package/dist/permissions/types.d.ts +33 -0
  233. package/dist/permissions/types.js +1 -0
  234. package/dist/runtime/app-shell.js +163 -0
  235. package/dist/runtime/auth.d.ts +10 -0
  236. package/dist/runtime/auth.js +30 -0
  237. package/dist/runtime/communication.d.ts +137 -0
  238. package/dist/runtime/communication.js +228 -0
  239. package/dist/runtime/error-boundary.d.ts +23 -0
  240. package/dist/runtime/error-boundary.js +120 -0
  241. package/dist/runtime/i18n.d.ts +6 -1
  242. package/dist/runtime/i18n.js +42 -21
  243. package/dist/runtime/router-data.d.ts +5 -0
  244. package/dist/runtime/router-data.js +121 -16
  245. package/dist/runtime/router-hydration.js +25 -0
  246. package/dist/runtime/router.d.ts +21 -1
  247. package/dist/runtime/router.js +221 -39
  248. package/dist/runtime/socket-client.d.ts +2 -0
  249. package/dist/runtime/socket-client.js +30 -0
  250. package/dist/runtime/webrtc.d.ts +47 -0
  251. package/dist/runtime/webrtc.js +178 -0
  252. package/dist/shared/graceful-shutdown.d.ts +8 -0
  253. package/dist/shared/graceful-shutdown.js +36 -0
  254. package/dist/shared/health.d.ts +8 -0
  255. package/dist/shared/health.js +25 -0
  256. package/dist/shared/llms-txt.d.ts +31 -0
  257. package/dist/shared/llms-txt.js +85 -0
  258. package/dist/shared/logger.d.ts +32 -0
  259. package/dist/shared/logger.js +93 -0
  260. package/dist/shared/meta.d.ts +27 -0
  261. package/dist/shared/meta.js +71 -0
  262. package/dist/shared/middleware-runner.d.ts +9 -0
  263. package/dist/shared/middleware-runner.js +29 -0
  264. package/dist/shared/rate-limit.d.ts +18 -0
  265. package/dist/shared/rate-limit.js +71 -0
  266. package/dist/shared/request-id.d.ts +5 -0
  267. package/dist/shared/request-id.js +18 -0
  268. package/dist/shared/route-matching.js +16 -1
  269. package/dist/shared/security-headers.d.ts +18 -0
  270. package/dist/shared/security-headers.js +38 -0
  271. package/dist/shared/socket-io-setup.d.ts +11 -0
  272. package/dist/shared/socket-io-setup.js +51 -0
  273. package/dist/shared/types.d.ts +16 -0
  274. package/dist/shared/utils.d.ts +37 -7
  275. package/dist/shared/utils.js +175 -26
  276. package/dist/storage/adapters/local.d.ts +44 -0
  277. package/dist/storage/adapters/local.js +85 -0
  278. package/dist/storage/adapters/s3.d.ts +32 -0
  279. package/dist/storage/adapters/s3.js +116 -0
  280. package/dist/storage/adapters/types.d.ts +53 -0
  281. package/dist/storage/adapters/types.js +1 -0
  282. package/dist/storage/index.d.ts +76 -0
  283. package/dist/storage/index.js +83 -0
  284. package/package.json +20 -1
  285. package/templates/blog/api/posts.ts +6 -0
  286. package/templates/blog/data/migrations/001_init.sql +13 -0
  287. package/templates/blog/lumenjs.config.ts +3 -0
  288. package/templates/blog/package.json +14 -0
  289. package/templates/blog/pages/_layout.ts +25 -0
  290. package/templates/blog/pages/index.ts +65 -0
  291. package/templates/blog/pages/posts/[slug].ts +60 -0
  292. package/templates/blog/pages/tag/[tag].ts +44 -0
  293. package/templates/dashboard/api/stats.ts +10 -0
  294. package/templates/dashboard/data/migrations/001_init.sql +13 -0
  295. package/templates/dashboard/lumenjs.config.ts +3 -0
  296. package/templates/dashboard/package.json +14 -0
  297. package/templates/dashboard/pages/_layout.ts +25 -0
  298. package/templates/dashboard/pages/index.ts +72 -0
  299. package/templates/dashboard/pages/settings/index.ts +29 -0
  300. package/templates/default/lumenjs.config.ts +3 -0
  301. package/templates/default/package.json +14 -0
  302. package/templates/default/pages/index.ts +24 -0
  303. package/templates/social/api/posts/[id].ts +14 -0
  304. package/templates/social/api/posts.ts +11 -0
  305. package/templates/social/api/profile/[username].ts +10 -0
  306. package/templates/social/api/upload.ts +19 -0
  307. package/templates/social/data/migrations/001_init.sql +78 -0
  308. package/templates/social/data/migrations/002_add_image_url.sql +1 -0
  309. package/templates/social/data/migrations/003_auth.sql +7 -0
  310. package/templates/social/docs/architecture.md +76 -0
  311. package/templates/social/docs/components.md +100 -0
  312. package/templates/social/docs/data.md +89 -0
  313. package/templates/social/docs/pages.md +96 -0
  314. package/templates/social/docs/theming.md +52 -0
  315. package/templates/social/lib/media.ts +130 -0
  316. package/templates/social/lumenjs.auth.ts +21 -0
  317. package/templates/social/lumenjs.config.ts +3 -0
  318. package/templates/social/package.json +5 -0
  319. package/templates/social/pages/_layout.ts +239 -0
  320. package/templates/social/pages/apps/[id].ts +173 -0
  321. package/templates/social/pages/apps/index.ts +116 -0
  322. package/templates/social/pages/auth/login.ts +92 -0
  323. package/templates/social/pages/bookmarks.ts +57 -0
  324. package/templates/social/pages/explore.ts +73 -0
  325. package/templates/social/pages/index.ts +351 -0
  326. package/templates/social/pages/messages.ts +298 -0
  327. package/templates/social/pages/new.ts +77 -0
  328. package/templates/social/pages/notifications.ts +73 -0
  329. package/templates/social/pages/post/[id].ts +124 -0
  330. package/templates/social/pages/profile/[username].ts +100 -0
  331. package/templates/social/pages/settings/accessibility.ts +153 -0
  332. package/templates/social/pages/settings/account.ts +260 -0
  333. package/templates/social/pages/settings/help.ts +141 -0
  334. package/templates/social/pages/settings/language.ts +103 -0
  335. package/templates/social/pages/settings/privacy.ts +183 -0
  336. package/templates/social/pages/settings/security.ts +133 -0
  337. package/templates/social/pages/settings.ts +185 -0
@@ -1,18 +1,175 @@
1
1
  import { sendToHost, isPreviewMode } from './editor-bridge.js';
2
+ import { applyAstModification, updateTranslation } from './editor-api-client.js';
3
+ const EDITABLE_TAGS = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'SPAN', 'A', 'LABEL', 'LI'];
4
+ let editingEl = null;
5
+ /**
6
+ * Find the text element and annotated parent from a target element,
7
+ * walking up the DOM tree. Works for both real events and direct calls.
8
+ */
9
+ function findEditTarget(startEl) {
10
+ let textEl = null;
11
+ let annotatedParent = null;
12
+ let el = startEl;
13
+ while (el) {
14
+ if (!textEl && EDITABLE_TAGS.includes(el.tagName)) {
15
+ textEl = el;
16
+ }
17
+ if (!annotatedParent && el.getAttribute('data-nk-source')) {
18
+ annotatedParent = el;
19
+ }
20
+ if (textEl && annotatedParent)
21
+ break;
22
+ el = el.parentElement;
23
+ }
24
+ // If no direct text element, check if start element has only text content
25
+ if (!textEl) {
26
+ if (startEl.childNodes.length > 0) {
27
+ const hasOnlyText = Array.from(startEl.childNodes).every(n => n.nodeType === Node.TEXT_NODE);
28
+ if (hasOnlyText && startEl.textContent?.trim()) {
29
+ textEl = startEl;
30
+ }
31
+ }
32
+ }
33
+ if (!textEl || !annotatedParent)
34
+ return null;
35
+ return { textEl, annotatedParent };
36
+ }
37
+ function showDynamicWarning(textEl) {
38
+ textEl.style.outline = '2px dashed #f59e0b';
39
+ textEl.style.outlineOffset = '2px';
40
+ const indicator = document.createElement('div');
41
+ Object.assign(indicator.style, {
42
+ position: 'fixed',
43
+ background: '#f59e0b',
44
+ color: '#000',
45
+ padding: '4px 8px',
46
+ borderRadius: '4px',
47
+ fontSize: '11px',
48
+ fontFamily: 'system-ui',
49
+ zIndex: '10000',
50
+ pointerEvents: 'none',
51
+ });
52
+ indicator.textContent = '\u26A1 Bound to variable \u2014 edit in code';
53
+ const rect = textEl.getBoundingClientRect();
54
+ indicator.style.left = `${rect.left}px`;
55
+ indicator.style.top = `${rect.top - 28}px`;
56
+ document.body.appendChild(indicator);
57
+ setTimeout(() => {
58
+ textEl.style.outline = '';
59
+ textEl.style.outlineOffset = '';
60
+ indicator.remove();
61
+ }, 2000);
62
+ }
63
+ function startEditing(textEl, annotatedParent) {
64
+ if (editingEl)
65
+ return;
66
+ editingEl = textEl;
67
+ const originalText = textEl.textContent || '';
68
+ textEl.setAttribute('contenteditable', 'true');
69
+ textEl.focus();
70
+ textEl.style.outline = '2px solid #3b82f6';
71
+ textEl.style.outlineOffset = '2px';
72
+ textEl.style.borderRadius = '2px';
73
+ textEl.style.minWidth = '20px';
74
+ const range = document.createRange();
75
+ range.selectNodeContents(textEl);
76
+ const sel = window.getSelection();
77
+ sel?.removeAllRanges();
78
+ sel?.addRange(range);
79
+ const sourceAttr = annotatedParent.getAttribute('data-nk-source');
80
+ const lastColon = sourceAttr.lastIndexOf(':');
81
+ const sourceFile = sourceAttr.substring(0, lastColon);
82
+ const line = parseInt(sourceAttr.substring(lastColon + 1), 10);
83
+ const commitEdit = () => {
84
+ if (!editingEl)
85
+ return;
86
+ const newText = editingEl.textContent || '';
87
+ editingEl.removeAttribute('contenteditable');
88
+ editingEl.style.outline = '';
89
+ editingEl.style.outlineOffset = '';
90
+ editingEl.style.borderRadius = '';
91
+ editingEl.style.minWidth = '';
92
+ editingEl = null;
93
+ if (newText !== originalText) {
94
+ const i18nKey = textEl.getAttribute('data-nk-i18n-key');
95
+ if (i18nKey) {
96
+ const locale = document.documentElement.lang || 'en';
97
+ updateTranslation(locale, i18nKey, newText).then(() => {
98
+ sendToHost({
99
+ type: 'NK_TRANSLATION_CHANGED',
100
+ payload: { key: i18nKey, locale, originalText, newText, appliedLocally: true }
101
+ });
102
+ }).catch(() => {
103
+ sendToHost({
104
+ type: 'NK_TRANSLATION_CHANGED',
105
+ payload: { key: i18nKey, locale, originalText, newText }
106
+ });
107
+ });
108
+ }
109
+ else {
110
+ applyAstModification(sourceFile, {
111
+ type: 'setTextContent',
112
+ elementSelector: textEl.tagName.toLowerCase(),
113
+ sourceLine: line,
114
+ html: newText,
115
+ }).then(() => {
116
+ sendToHost({
117
+ type: 'NK_TEXT_CHANGED',
118
+ payload: { sourceFile, line, originalText, newText, appliedLocally: true }
119
+ });
120
+ }).catch(() => {
121
+ sendToHost({
122
+ type: 'NK_TEXT_CHANGED',
123
+ payload: { sourceFile, line, originalText, newText }
124
+ });
125
+ });
126
+ }
127
+ }
128
+ };
129
+ textEl.addEventListener('blur', commitEdit, { once: true });
130
+ textEl.addEventListener('keydown', (e) => {
131
+ if (e.key === 'Enter' && !e.shiftKey) {
132
+ e.preventDefault();
133
+ textEl.blur();
134
+ }
135
+ if (e.key === 'Escape') {
136
+ textEl.textContent = originalText;
137
+ textEl.blur();
138
+ }
139
+ });
140
+ }
141
+ /**
142
+ * Trigger inline text editing on an element directly.
143
+ * Called from standalone-overlay.ts on double-tap (mobile).
144
+ */
145
+ export function triggerInlineEdit(target) {
146
+ if (isPreviewMode() || editingEl)
147
+ return false;
148
+ const result = findEditTarget(target);
149
+ if (!result)
150
+ return false;
151
+ const { textEl, annotatedParent } = result;
152
+ const isDynamic = textEl.hasAttribute('data-nk-dynamic') || !!textEl.closest('[data-nk-dynamic]');
153
+ const isI18n = !!textEl.getAttribute('data-nk-i18n-key') || !!textEl.closest('[data-nk-i18n-key]');
154
+ if (isDynamic && !isI18n) {
155
+ showDynamicWarning(textEl);
156
+ return true;
157
+ }
158
+ startEditing(textEl, annotatedParent);
159
+ return true;
160
+ }
2
161
  export function setupInlineTextEdit() {
3
- let editingEl = null;
4
162
  document.addEventListener('dblclick', (event) => {
5
163
  if (isPreviewMode())
6
164
  return;
7
- // Walk the composed path to find a text-bearing element
8
- const editableTags = ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P', 'SPAN', 'A', 'LABEL', 'LI'];
165
+ // Try composedPath first (works in shadow DOM with real events)
9
166
  const composedPath = event.composedPath();
10
167
  let textEl = null;
11
168
  let annotatedParent = null;
12
169
  for (const node of composedPath) {
13
170
  if (!(node instanceof HTMLElement))
14
171
  continue;
15
- if (!textEl && editableTags.includes(node.tagName)) {
172
+ if (!textEl && EDITABLE_TAGS.includes(node.tagName)) {
16
173
  textEl = node;
17
174
  }
18
175
  if (!annotatedParent && node.getAttribute('data-nk-source')) {
@@ -21,105 +178,29 @@ export function setupInlineTextEdit() {
21
178
  if (textEl && annotatedParent)
22
179
  break;
23
180
  }
24
- // If no direct text element, check if target itself has only text content
25
- if (!textEl) {
181
+ // Fallback: walk from event.target
182
+ if (!textEl || !annotatedParent) {
26
183
  const target = event.target;
27
- if (target && target.childNodes.length > 0) {
28
- const hasOnlyText = Array.from(target.childNodes).every(n => n.nodeType === Node.TEXT_NODE);
29
- if (hasOnlyText && target.textContent?.trim()) {
30
- textEl = target;
184
+ if (target) {
185
+ const result = findEditTarget(target);
186
+ if (result) {
187
+ textEl = result.textEl;
188
+ annotatedParent = result.annotatedParent;
31
189
  }
32
190
  }
33
191
  }
34
192
  if (!textEl || !annotatedParent || editingEl)
35
193
  return;
36
- // Block inline editing for elements bound to dynamic expressions
37
- if (textEl.hasAttribute('data-nk-dynamic') || textEl.closest('[data-nk-dynamic]')) {
194
+ const isDynamic = textEl.hasAttribute('data-nk-dynamic') || !!textEl.closest('[data-nk-dynamic]');
195
+ const isI18n = !!textEl.getAttribute('data-nk-i18n-key') || !!textEl.closest('[data-nk-i18n-key]');
196
+ if (isDynamic && !isI18n) {
38
197
  event.preventDefault();
39
198
  event.stopPropagation();
40
- textEl.style.outline = '2px dashed #f59e0b';
41
- textEl.style.outlineOffset = '2px';
42
- const indicator = document.createElement('div');
43
- Object.assign(indicator.style, {
44
- position: 'fixed',
45
- background: '#f59e0b',
46
- color: '#000',
47
- padding: '4px 8px',
48
- borderRadius: '4px',
49
- fontSize: '11px',
50
- fontFamily: 'system-ui',
51
- zIndex: '10000',
52
- pointerEvents: 'none',
53
- });
54
- indicator.textContent = '\u26A1 Bound to variable \u2014 edit in code';
55
- const rect = textEl.getBoundingClientRect();
56
- indicator.style.left = `${rect.left}px`;
57
- indicator.style.top = `${rect.top - 28}px`;
58
- document.body.appendChild(indicator);
59
- setTimeout(() => {
60
- textEl.style.outline = '';
61
- textEl.style.outlineOffset = '';
62
- indicator.remove();
63
- }, 2000);
199
+ showDynamicWarning(textEl);
64
200
  return;
65
201
  }
66
202
  event.preventDefault();
67
203
  event.stopPropagation();
68
- editingEl = textEl;
69
- const originalText = textEl.textContent || '';
70
- textEl.setAttribute('contenteditable', 'true');
71
- textEl.focus();
72
- textEl.style.outline = '2px solid #3b82f6';
73
- textEl.style.outlineOffset = '2px';
74
- textEl.style.borderRadius = '2px';
75
- textEl.style.minWidth = '20px';
76
- const range = document.createRange();
77
- range.selectNodeContents(textEl);
78
- const sel = window.getSelection();
79
- sel?.removeAllRanges();
80
- sel?.addRange(range);
81
- const sourceAttr = annotatedParent.getAttribute('data-nk-source');
82
- const lastColon = sourceAttr.lastIndexOf(':');
83
- const sourceFile = sourceAttr.substring(0, lastColon);
84
- const line = parseInt(sourceAttr.substring(lastColon + 1), 10);
85
- const commitEdit = () => {
86
- if (!editingEl)
87
- return;
88
- const newText = editingEl.textContent || '';
89
- editingEl.removeAttribute('contenteditable');
90
- editingEl.style.outline = '';
91
- editingEl.style.outlineOffset = '';
92
- editingEl.style.borderRadius = '';
93
- editingEl.style.minWidth = '';
94
- editingEl = null;
95
- if (newText !== originalText) {
96
- // Check if this element has an i18n key — if so, send a translation change
97
- const i18nKey = textEl.getAttribute('data-nk-i18n-key');
98
- if (i18nKey) {
99
- const locale = document.documentElement.lang || 'en';
100
- sendToHost({
101
- type: 'NK_TRANSLATION_CHANGED',
102
- payload: { key: i18nKey, locale, originalText, newText }
103
- });
104
- }
105
- else {
106
- sendToHost({
107
- type: 'NK_TEXT_CHANGED',
108
- payload: { sourceFile, line, originalText, newText }
109
- });
110
- }
111
- }
112
- };
113
- textEl.addEventListener('blur', commitEdit, { once: true });
114
- textEl.addEventListener('keydown', (e) => {
115
- if (e.key === 'Enter' && !e.shiftKey) {
116
- e.preventDefault();
117
- textEl.blur();
118
- }
119
- if (e.key === 'Escape') {
120
- textEl.textContent = originalText;
121
- textEl.blur();
122
- }
123
- });
204
+ startEditing(textEl, annotatedParent);
124
205
  });
125
206
  }
@@ -0,0 +1,5 @@
1
+ export declare function setupMouseEvents(): void;
2
+ export declare function setupTouchEvents(): void;
3
+ export declare function setupToolbarHandlers(toolbar: HTMLDivElement, filePanel: HTMLDivElement): void;
4
+ export declare function setupKeyboardHandlers(toolbar: HTMLDivElement): void;
5
+ export declare function setupScrollResize(): void;
@@ -0,0 +1,364 @@
1
+ /**
2
+ * Overlay Events — mouse, touch, toolbar, keyboard, and scroll/resize
3
+ * event handlers for the standalone editor overlay.
4
+ */
5
+ import { findAnnotatedElement, parseSourceAttr } from './element-annotator.js';
6
+ import { triggerInlineEdit } from './inline-text-edit.js';
7
+ import { deepElementFromPoint, positionOverlay, hideOverlay } from './overlay-utils.js';
8
+ import { positionTextToolbar, hideTextToolbar } from './text-toolbar.js';
9
+ import { showPropertiesForElement, hidePropertiesPanel, isPropertiesPanelOpen } from './properties-panel.js';
10
+ import { hideAiChatPanel, isAiChatPanelOpen, updateAiChatPosition } from './ai-chat-panel.js';
11
+ import { showAiProjectPanel, hideAiProjectPanel, isAiProjectPanelOpen } from './ai-project-panel.js';
12
+ import { showTextToolbarForElement } from './text-toolbar.js';
13
+ import { showAiChatForElement } from './ai-chat-panel.js';
14
+ import { updateSelectionInfo, setMode, closeFilePanel, loadFileList, saveCurrentFile, getIsEditorMode, getCurrentEditorFile, getIsFilePanelOpen, setIsFilePanelOpen, } from './editor-toolbar.js';
15
+ import { getSelectedElement, setSelectedElement, getHoverOverlay, getSelectOverlay, getMultiSelectedElements, getMultiSelectOverlays, deselect, selectSingle, toggleMultiSelect, touchToElement, sendPageAiPrompt, } from './overlay-selection.js';
16
+ const isTouchDevice = ('ontouchstart' in window) || navigator.maxTouchPoints > 0;
17
+ // ── Mouse events (desktop) ──
18
+ export function setupMouseEvents() {
19
+ const hoverOverlay = getHoverOverlay();
20
+ let lastHoverEl = null;
21
+ let hoverRaf = 0;
22
+ document.addEventListener('mousemove', (event) => {
23
+ if (!getIsEditorMode())
24
+ return;
25
+ if (hoverRaf)
26
+ return;
27
+ hoverRaf = requestAnimationFrame(() => {
28
+ hoverRaf = 0;
29
+ const selectedElement = getSelectedElement();
30
+ let hoverEl = document.elementFromPoint(event.clientX, event.clientY);
31
+ while (hoverEl?.shadowRoot) {
32
+ const inner = hoverEl.shadowRoot.elementFromPoint(event.clientX, event.clientY);
33
+ if (!inner || inner === hoverEl)
34
+ break;
35
+ hoverEl = inner;
36
+ }
37
+ if (hoverEl && hoverEl !== selectedElement && hoverEl !== document.body && hoverEl !== document.documentElement && !hoverEl.closest('#nk-editor-toolbar') && !hoverEl.closest('#nk-props-panel') && !hoverEl.closest('#nk-file-panel') && !hoverEl.closest('#nk-ai-chat') && !hoverEl.closest('#nk-ai-project') && !hoverEl.closest('#nk-pp-fab')) {
38
+ if (hoverEl !== lastHoverEl) {
39
+ lastHoverEl = hoverEl;
40
+ positionOverlay(hoverOverlay, hoverEl);
41
+ }
42
+ }
43
+ else {
44
+ lastHoverEl = null;
45
+ hideOverlay(hoverOverlay);
46
+ }
47
+ });
48
+ }, true);
49
+ document.addEventListener('mouseleave', () => {
50
+ lastHoverEl = null;
51
+ hideOverlay(hoverOverlay);
52
+ });
53
+ // Pointerdown handler to select disabled/pointer-events:none elements.
54
+ document.addEventListener('pointerdown', (event) => {
55
+ if (isTouchDevice)
56
+ return;
57
+ if (!getIsEditorMode())
58
+ return;
59
+ const t = event.target;
60
+ if (t.closest('#nk-editor-toolbar') || t.closest('#nk-file-panel') || t.closest('#nk-file-editor') || t.closest('#nk-text-toolbar') || t.closest('#nk-props-panel') || t.closest('#nk-ai-chat') || t.closest('#nk-ai-project') || t.closest('#nk-pp-fab'))
61
+ return;
62
+ const deepEl = deepElementFromPoint(event.clientX, event.clientY);
63
+ if (!deepEl)
64
+ return;
65
+ const deepRoot = deepEl.getRootNode();
66
+ const hostEl = deepRoot instanceof ShadowRoot ? deepRoot.host : null;
67
+ const isHostUnclickable = hostEl && (hostEl.hasAttribute('disabled') ||
68
+ hostEl.getAttribute('aria-disabled') === 'true' ||
69
+ window.getComputedStyle(hostEl).pointerEvents === 'none');
70
+ const isDeepUnclickable = deepEl.disabled ||
71
+ window.getComputedStyle(deepEl).pointerEvents === 'none';
72
+ if (!isHostUnclickable && !isDeepUnclickable)
73
+ return;
74
+ let selectEl = hostEl && hostEl.getAttribute('data-nk-source') ? hostEl : deepEl;
75
+ if (!selectEl.getAttribute('data-nk-source')) {
76
+ let el = selectEl;
77
+ while (el) {
78
+ if (el.getAttribute('data-nk-source')) {
79
+ selectEl = el;
80
+ break;
81
+ }
82
+ const r = el.getRootNode();
83
+ if (r instanceof ShadowRoot) {
84
+ el = r.host;
85
+ continue;
86
+ }
87
+ el = el.parentElement;
88
+ }
89
+ }
90
+ event.preventDefault();
91
+ event.stopPropagation();
92
+ if (event.shiftKey) {
93
+ toggleMultiSelect(selectEl);
94
+ }
95
+ else {
96
+ selectSingle(selectEl);
97
+ }
98
+ }, true);
99
+ // Click to select (desktop) — supports Shift+click for multi-select
100
+ let clickTimer = null;
101
+ document.addEventListener('click', (event) => {
102
+ if (isTouchDevice)
103
+ return;
104
+ if (!getIsEditorMode())
105
+ return;
106
+ const t = event.target;
107
+ if (t.closest('#nk-editor-toolbar') || t.closest('#nk-file-panel') || t.closest('#nk-file-editor') || t.closest('#nk-text-toolbar') || t.closest('#nk-props-panel') || t.closest('#nk-ai-chat') || t.closest('#nk-ai-project') || t.closest('#nk-pp-fab'))
108
+ return;
109
+ let result = findAnnotatedElement(event);
110
+ if (result?.element) {
111
+ const root = result.element.getRootNode();
112
+ if (root instanceof ShadowRoot) {
113
+ const host = root.host;
114
+ const hostSrc = host.getAttribute('data-nk-source');
115
+ if (hostSrc) {
116
+ const parsed = parseSourceAttr(hostSrc);
117
+ if (parsed)
118
+ result = { element: host, source: parsed };
119
+ }
120
+ }
121
+ }
122
+ if (!result && t) {
123
+ let el = t;
124
+ const root = t.getRootNode();
125
+ if (root instanceof ShadowRoot) {
126
+ const host = root.host;
127
+ const hostSrc = host.getAttribute('data-nk-source');
128
+ if (hostSrc) {
129
+ const parsed = parseSourceAttr(hostSrc);
130
+ if (parsed)
131
+ result = { element: host, source: parsed };
132
+ }
133
+ }
134
+ if (!result) {
135
+ while (el) {
136
+ const src = el.getAttribute('data-nk-source');
137
+ if (src) {
138
+ const parsed = parseSourceAttr(src);
139
+ if (parsed) {
140
+ result = { element: el, source: parsed };
141
+ break;
142
+ }
143
+ }
144
+ el = el.parentElement;
145
+ }
146
+ }
147
+ }
148
+ let targetEl = result?.element ?? t;
149
+ if (!targetEl || targetEl === document.body || targetEl === document.documentElement) {
150
+ deselect();
151
+ return;
152
+ }
153
+ event.preventDefault();
154
+ event.stopPropagation();
155
+ if (clickTimer)
156
+ clearTimeout(clickTimer);
157
+ const selectEl = targetEl;
158
+ const isShift = event.shiftKey;
159
+ clickTimer = setTimeout(() => {
160
+ if (isShift) {
161
+ toggleMultiSelect(selectEl);
162
+ }
163
+ else {
164
+ selectSingle(selectEl);
165
+ }
166
+ }, 200);
167
+ }, true);
168
+ document.addEventListener('dblclick', () => {
169
+ if (clickTimer) {
170
+ clearTimeout(clickTimer);
171
+ clickTimer = null;
172
+ }
173
+ }, true);
174
+ }
175
+ // ── Touch events (mobile/tablet) ──
176
+ export function setupTouchEvents() {
177
+ const hoverOverlay = getHoverOverlay();
178
+ const selectOverlay = getSelectOverlay();
179
+ let lastTapTime = 0;
180
+ let lastTapTarget = null;
181
+ let tapTimer = null;
182
+ document.addEventListener('touchend', (event) => {
183
+ const target = event.target;
184
+ if (target.closest('#nk-editor-toolbar') || target.closest('#nk-file-panel') || target.closest('#nk-file-editor') || target.closest('#nk-text-toolbar') || target.closest('#nk-props-panel') || target.closest('#nk-ai-chat') || target.closest('#nk-ai-project') || target.closest('#nk-pp-fab')) {
185
+ return;
186
+ }
187
+ if (!getIsEditorMode())
188
+ return;
189
+ const touch = event.changedTouches[0];
190
+ if (!touch)
191
+ return;
192
+ const result = touchToElement(touch);
193
+ let touchTargetEl = result?.element ?? document.elementFromPoint(touch.clientX, touch.clientY);
194
+ if (!touchTargetEl || touchTargetEl === document.body || touchTargetEl === document.documentElement)
195
+ return;
196
+ const now = Date.now();
197
+ const resultSource = touchTargetEl.getAttribute('data-nk-source') || '';
198
+ const lastSource = lastTapTarget?.getAttribute('data-nk-source') || '';
199
+ const isDoubleTap = (now - lastTapTime < 350) && (resultSource !== '' ? resultSource === lastSource : touchTargetEl === lastTapTarget);
200
+ lastTapTime = now;
201
+ lastTapTarget = touchTargetEl;
202
+ if (isDoubleTap) {
203
+ if (tapTimer) {
204
+ clearTimeout(tapTimer);
205
+ tapTimer = null;
206
+ }
207
+ hideTextToolbar();
208
+ let touchTarget = document.elementFromPoint(touch.clientX, touch.clientY);
209
+ if (touchTarget?.shadowRoot) {
210
+ const inner = touchTarget.shadowRoot.elementFromPoint(touch.clientX, touch.clientY);
211
+ if (inner instanceof HTMLElement)
212
+ touchTarget = inner;
213
+ }
214
+ if (touchTarget) {
215
+ triggerInlineEdit(touchTarget);
216
+ }
217
+ event.preventDefault();
218
+ }
219
+ else {
220
+ if (tapTimer)
221
+ clearTimeout(tapTimer);
222
+ const tapEl = touchTargetEl;
223
+ tapTimer = setTimeout(() => {
224
+ setSelectedElement(tapEl);
225
+ positionOverlay(selectOverlay, tapEl);
226
+ hideOverlay(hoverOverlay);
227
+ updateSelectionInfo(tapEl);
228
+ showTextToolbarForElement(tapEl);
229
+ showPropertiesForElement(tapEl);
230
+ showAiChatForElement(tapEl);
231
+ }, 300);
232
+ event.preventDefault();
233
+ }
234
+ }, { passive: false, capture: true });
235
+ }
236
+ // ── Toolbar button handlers ──
237
+ export function setupToolbarHandlers(toolbar, filePanel) {
238
+ // Page-level AI input
239
+ const pageAiInput = toolbar.querySelector('.nk-tb-page-ai-input');
240
+ const pageAiSend = toolbar.querySelector('.nk-tb-page-ai-send');
241
+ pageAiInput.addEventListener('input', () => {
242
+ pageAiSend.disabled = !pageAiInput.value.trim();
243
+ });
244
+ pageAiInput.addEventListener('keydown', (e) => {
245
+ if (e.key === 'Enter' && pageAiInput.value.trim()) {
246
+ e.preventDefault();
247
+ sendPageAiPrompt(pageAiInput.value.trim());
248
+ pageAiInput.value = '';
249
+ pageAiSend.disabled = true;
250
+ }
251
+ e.stopPropagation();
252
+ });
253
+ pageAiSend.addEventListener('click', (e) => {
254
+ e.stopPropagation();
255
+ if (pageAiInput.value.trim()) {
256
+ sendPageAiPrompt(pageAiInput.value.trim());
257
+ pageAiInput.value = '';
258
+ pageAiSend.disabled = true;
259
+ }
260
+ });
261
+ // Edit / Preview toggle
262
+ document.getElementById('nk-tb-toggle').addEventListener('click', (e) => {
263
+ e.stopPropagation();
264
+ setMode(!getIsEditorMode());
265
+ });
266
+ // Deselect button
267
+ toolbar.querySelector('.nk-tb-deselect').addEventListener('click', (e) => {
268
+ e.stopPropagation();
269
+ deselect();
270
+ });
271
+ // Project AI panel toggle
272
+ toolbar.querySelector('.nk-tb-project-ai').addEventListener('click', (e) => {
273
+ e.stopPropagation();
274
+ if (isAiProjectPanelOpen()) {
275
+ hideAiProjectPanel();
276
+ toolbar.querySelector('.nk-tb-project-ai').classList.remove('active');
277
+ }
278
+ else {
279
+ showAiProjectPanel();
280
+ toolbar.querySelector('.nk-tb-project-ai').classList.add('active');
281
+ }
282
+ });
283
+ // File panel toggle
284
+ toolbar.querySelector('.nk-tb-files').addEventListener('click', (e) => {
285
+ e.stopPropagation();
286
+ if (getIsFilePanelOpen()) {
287
+ closeFilePanel();
288
+ }
289
+ else {
290
+ setIsFilePanelOpen(true);
291
+ filePanel.classList.add('open');
292
+ toolbar.querySelector('.nk-tb-files').classList.add('active');
293
+ loadFileList();
294
+ }
295
+ });
296
+ // Mobile close button in file panel header
297
+ document.getElementById('nk-fp-close').addEventListener('click', (e) => {
298
+ e.stopPropagation();
299
+ closeFilePanel();
300
+ });
301
+ // File editor save / close
302
+ document.getElementById('nk-fe-save').addEventListener('click', saveCurrentFile);
303
+ document.getElementById('nk-fe-close').addEventListener('click', () => {
304
+ document.getElementById('nk-file-editor').classList.remove('open');
305
+ // On mobile, re-show the file list
306
+ if (window.innerWidth <= 640 && getIsFilePanelOpen()) {
307
+ filePanel.classList.add('open');
308
+ }
309
+ });
310
+ }
311
+ // ── Keyboard handlers ──
312
+ export function setupKeyboardHandlers(toolbar) {
313
+ document.addEventListener('keydown', (e) => {
314
+ if ((e.ctrlKey || e.metaKey) && e.key === 's' && getCurrentEditorFile()) {
315
+ e.preventDefault();
316
+ saveCurrentFile();
317
+ }
318
+ if (e.key === 'Escape') {
319
+ if (getCurrentEditorFile()) {
320
+ document.getElementById('nk-file-editor').classList.remove('open');
321
+ }
322
+ else if (isAiProjectPanelOpen()) {
323
+ hideAiProjectPanel();
324
+ toolbar.querySelector('.nk-tb-project-ai')?.classList.remove('active');
325
+ }
326
+ else if (isAiChatPanelOpen()) {
327
+ hideAiChatPanel();
328
+ }
329
+ else if (isPropertiesPanelOpen()) {
330
+ hidePropertiesPanel();
331
+ }
332
+ else if (getIsFilePanelOpen()) {
333
+ closeFilePanel();
334
+ }
335
+ else if (getSelectedElement()) {
336
+ deselect();
337
+ }
338
+ }
339
+ });
340
+ }
341
+ // ── Scroll / resize overlay repositioning ──
342
+ export function setupScrollResize() {
343
+ const selectOverlay = getSelectOverlay();
344
+ const updateOverlays = () => {
345
+ const selectedElement = getSelectedElement();
346
+ if (selectedElement) {
347
+ positionOverlay(selectOverlay, selectedElement);
348
+ const textTb = document.getElementById('nk-text-toolbar');
349
+ if (textTb && textTb.style.display !== 'none')
350
+ positionTextToolbar(selectedElement);
351
+ }
352
+ // Reposition multi-select overlays
353
+ const multiSelectedElements = getMultiSelectedElements();
354
+ const multiSelectOverlays = getMultiSelectOverlays();
355
+ for (let i = 0; i < multiSelectedElements.length; i++) {
356
+ if (multiSelectedElements[i].isConnected && multiSelectOverlays[i]) {
357
+ positionOverlay(multiSelectOverlays[i], multiSelectedElements[i]);
358
+ }
359
+ }
360
+ updateAiChatPosition();
361
+ };
362
+ window.addEventListener('scroll', updateOverlays, true);
363
+ window.addEventListener('resize', updateOverlays);
364
+ }
@@ -0,0 +1,2 @@
1
+ export declare function reselectAfterHmr(): void;
2
+ export declare function setupHmrListener(): void;