@ccslabs/xtend 0.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (664) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/LICENSE +201 -0
  3. package/README.md +184 -0
  4. package/a11y/motion-contrast-policy.d.ts +32 -0
  5. package/a11y/motion-contrast-policy.js +261 -0
  6. package/a11y/runtime-a11y-contract.d.ts +44 -0
  7. package/a11y/runtime-a11y-contract.js +385 -0
  8. package/a11y/screenreader-signals.d.ts +32 -0
  9. package/a11y/screenreader-signals.js +372 -0
  10. package/api.d.ts +168 -0
  11. package/api.js +864 -0
  12. package/catalog/catalog-public-types.d.ts +66 -0
  13. package/catalog/component-catalog-coverage.d.ts +20 -0
  14. package/catalog/component-catalog-coverage.js +377 -0
  15. package/catalog/component-long-tail-migration.d.ts +18 -0
  16. package/catalog/component-long-tail-migration.js +305 -0
  17. package/catalog/component-regression-priority.d.ts +20 -0
  18. package/catalog/component-regression-priority.js +305 -0
  19. package/catalog/enterprise-component-flex-release-handoff.d.ts +32 -0
  20. package/catalog/enterprise-component-flex-release-handoff.js +437 -0
  21. package/catalog/enterprise-component-style-audit.d.ts +22 -0
  22. package/catalog/enterprise-component-style-audit.js +353 -0
  23. package/catalog/enterprise-form-control-theme-a11y.d.ts +19 -0
  24. package/catalog/enterprise-form-control-theme-a11y.js +220 -0
  25. package/catalog/enterprise-icon-control-audit.d.ts +21 -0
  26. package/catalog/enterprise-icon-control-audit.js +258 -0
  27. package/catalog/enterprise-layout-display-media-tokenization.d.ts +20 -0
  28. package/catalog/enterprise-layout-display-media-tokenization.js +237 -0
  29. package/catalog/enterprise-navigation-routing-state-hardening.d.ts +20 -0
  30. package/catalog/enterprise-navigation-routing-state-hardening.js +255 -0
  31. package/catalog/enterprise-overlay-mode-token-parity.d.ts +15 -0
  32. package/catalog/enterprise-overlay-mode-token-parity.js +178 -0
  33. package/catalog/enterprise-third-party-authoring-guide.d.ts +23 -0
  34. package/catalog/enterprise-third-party-authoring-guide.js +310 -0
  35. package/catalog/enterprise-visual-dom-snapshot-matrix.d.ts +31 -0
  36. package/catalog/enterprise-visual-dom-snapshot-matrix.js +357 -0
  37. package/catalog/epic10-existing-component-metadata.d.ts +25 -0
  38. package/catalog/epic10-existing-component-metadata.js +534 -0
  39. package/catalog/epic10-p0-component-wave.d.ts +28 -0
  40. package/catalog/epic10-p0-component-wave.js +688 -0
  41. package/catalog/epic10-platform-gates.d.ts +31 -0
  42. package/catalog/epic10-platform-gates.js +425 -0
  43. package/catalog/epic10-release-handoff.d.ts +30 -0
  44. package/catalog/epic10-release-handoff.js +195 -0
  45. package/catalog/epic11-enterprise-ux-handoff.d.ts +29 -0
  46. package/catalog/epic11-enterprise-ux-handoff.js +403 -0
  47. package/catalog/epic12-docs-adoption.d.ts +29 -0
  48. package/catalog/epic12-docs-adoption.js +183 -0
  49. package/catalog/epic12-rc0-gate-matrix.d.ts +36 -0
  50. package/catalog/epic12-rc0-gate-matrix.js +439 -0
  51. package/catalog/epic12-rc0-handoff.d.ts +30 -0
  52. package/catalog/epic12-rc0-handoff.js +385 -0
  53. package/catalog/epic13-conditional-network-evidence-ci.d.ts +35 -0
  54. package/catalog/epic13-conditional-network-evidence-ci.js +278 -0
  55. package/catalog/epic13-conditional-network-evidence.d.ts +34 -0
  56. package/catalog/epic13-conditional-network-evidence.js +280 -0
  57. package/catalog/epic13-docs-rmt-production-hardening.d.ts +39 -0
  58. package/catalog/epic13-docs-rmt-production-hardening.js +286 -0
  59. package/catalog/epic13-hydration-performance-closure.d.ts +33 -0
  60. package/catalog/epic13-hydration-performance-closure.js +234 -0
  61. package/catalog/epic13-known-residual-triage.d.ts +32 -0
  62. package/catalog/epic13-known-residual-triage.js +339 -0
  63. package/catalog/epic13-package-export-lock.d.ts +41 -0
  64. package/catalog/epic13-package-export-lock.js +604 -0
  65. package/catalog/epic13-prod-browser-csp-smoke.d.ts +35 -0
  66. package/catalog/epic13-prod-browser-csp-smoke.js +218 -0
  67. package/catalog/epic13-rc1-gate-matrix-ci-handoff.d.ts +36 -0
  68. package/catalog/epic13-rc1-gate-matrix-ci-handoff.js +418 -0
  69. package/catalog/epic13-rc1-migration-notes.d.ts +36 -0
  70. package/catalog/epic13-rc1-migration-notes.js +271 -0
  71. package/catalog/epic13-rc1-readiness.d.ts +33 -0
  72. package/catalog/epic13-rc1-readiness.js +487 -0
  73. package/catalog/epic13-release-owner-acceptance.d.ts +33 -0
  74. package/catalog/epic13-release-owner-acceptance.js +354 -0
  75. package/catalog/epic13-release-report-pack-dry-run-evidence.d.ts +36 -0
  76. package/catalog/epic13-release-report-pack-dry-run-evidence.js +253 -0
  77. package/catalog/epic13-rmt-production-readiness.d.ts +35 -0
  78. package/catalog/epic13-rmt-production-readiness.js +314 -0
  79. package/catalog/epic13-trusted-dom-boundary.d.ts +36 -0
  80. package/catalog/epic13-trusted-dom-boundary.js +230 -0
  81. package/catalog/epic13-visual-owner-artifact.d.ts +35 -0
  82. package/catalog/epic13-visual-owner-artifact.js +233 -0
  83. package/catalog/epic14-lsp-handoff.d.ts +28 -0
  84. package/catalog/epic14-lsp-handoff.js +312 -0
  85. package/catalog/epic14-rmt-tooling.d.ts +33 -0
  86. package/catalog/epic14-rmt-tooling.js +282 -0
  87. package/catalog/surface-manager-adapter-runtime.d.ts +37 -0
  88. package/catalog/surface-manager-adapter-runtime.js +203 -0
  89. package/catalog/surface-manager-browser-lab.d.ts +39 -0
  90. package/catalog/surface-manager-browser-lab.js +225 -0
  91. package/catalog/surface-manager-controller.d.ts +43 -0
  92. package/catalog/surface-manager-controller.js +290 -0
  93. package/catalog/surface-manager-layout-engines.d.ts +32 -0
  94. package/catalog/surface-manager-layout-engines.js +161 -0
  95. package/catalog/surface-manager-lazy-loading.d.ts +35 -0
  96. package/catalog/surface-manager-lazy-loading.js +173 -0
  97. package/catalog/surface-manager-materialization.d.ts +37 -0
  98. package/catalog/surface-manager-materialization.js +202 -0
  99. package/catalog/surface-manager-native-rmt-surfaces.d.ts +48 -0
  100. package/catalog/surface-manager-native-rmt-surfaces.js +325 -0
  101. package/catalog/surface-manager-overlay-bridge.d.ts +42 -0
  102. package/catalog/surface-manager-overlay-bridge.js +247 -0
  103. package/catalog/surface-manager-persistence.d.ts +37 -0
  104. package/catalog/surface-manager-persistence.js +178 -0
  105. package/catalog/surface-manager-quality-gates.d.ts +48 -0
  106. package/catalog/surface-manager-quality-gates.js +324 -0
  107. package/catalog/surface-manager-release-handoff.d.ts +47 -0
  108. package/catalog/surface-manager-release-handoff.js +274 -0
  109. package/catalog/surface-manager-remote-policy.d.ts +34 -0
  110. package/catalog/surface-manager-remote-policy.js +199 -0
  111. package/catalog/surface-manager-rmt-authoring.d.ts +44 -0
  112. package/catalog/surface-manager-rmt-authoring.js +368 -0
  113. package/catalog/surface-manager-route-lifecycle.d.ts +32 -0
  114. package/catalog/surface-manager-route-lifecycle.js +162 -0
  115. package/catalog/surface-manager-runtime-release-handoff.d.ts +36 -0
  116. package/catalog/surface-manager-runtime-release-handoff.js +245 -0
  117. package/catalog/surface-manager-side-panel-runtime.d.ts +46 -0
  118. package/catalog/surface-manager-side-panel-runtime.js +307 -0
  119. package/catalog/surface-manager-stack-policy.d.ts +32 -0
  120. package/catalog/surface-manager-stack-policy.js +169 -0
  121. package/catalog/surface-manager-window-runtime.d.ts +45 -0
  122. package/catalog/surface-manager-window-runtime.js +285 -0
  123. package/catalog/surface-manager-workbench-fixture.d.ts +50 -0
  124. package/catalog/surface-manager-workbench-fixture.js +315 -0
  125. package/catalog/type-exports-api.js +236 -0
  126. package/catalog/type-exports-builder.js +405 -0
  127. package/catalog/type-exports-catalog.js +394 -0
  128. package/catalog/type-exports-loader.js +266 -0
  129. package/catalog/type-exports-policy.js +461 -0
  130. package/catalog/type-exports-rmt.js +407 -0
  131. package/catalog/type-exports-vendor.js +365 -0
  132. package/catalog/type-exports.js +574 -0
  133. package/components/icon-packs/core.js +154 -0
  134. package/components/icon-packs/lucide.js +136 -0
  135. package/components/manifest.json +44 -0
  136. package/components/prism.d.ts +73 -0
  137. package/components/prism.js +300 -0
  138. package/components/turndown.d.ts +34 -0
  139. package/components/turndown.js +107 -0
  140. package/components/x-rmt-lifecycle-demo-build.d.ts +78 -0
  141. package/components/x-rmt-lifecycle-demo-build.js +1175 -0
  142. package/components/x-rmt-lifecycle-demo.d.ts +83 -0
  143. package/components/x-rmt-lifecycle-demo.js +1175 -0
  144. package/components/xalert.d.ts +42 -0
  145. package/components/xalert.js +538 -0
  146. package/components/xbutton.d.ts +127 -0
  147. package/components/xbutton.js +612 -0
  148. package/components/xcalendar.d.ts +39 -0
  149. package/components/xcalendar.js +338 -0
  150. package/components/xcards.d.ts +34 -0
  151. package/components/xcards.js +253 -0
  152. package/components/xcheckbox.d.ts +48 -0
  153. package/components/xcheckbox.js +448 -0
  154. package/components/xcode.d.ts +35 -0
  155. package/components/xcode.js +370 -0
  156. package/components/xdialog.d.ts +48 -0
  157. package/components/xdialog.js +763 -0
  158. package/components/xdrawer.d.ts +61 -0
  159. package/components/xdrawer.js +654 -0
  160. package/components/xfooter.d.ts +41 -0
  161. package/components/xfooter.js +351 -0
  162. package/components/xform.d.ts +43 -0
  163. package/components/xform.js +456 -0
  164. package/components/xheader.d.ts +68 -0
  165. package/components/xheader.js +1253 -0
  166. package/components/xhero.d.ts +42 -0
  167. package/components/xhero.js +475 -0
  168. package/components/xicon.d.ts +146 -0
  169. package/components/xicon.js +688 -0
  170. package/components/xinput.d.ts +37 -0
  171. package/components/xinput.js +444 -0
  172. package/components/xlightbox.d.ts +48 -0
  173. package/components/xlightbox.js +571 -0
  174. package/components/xlink.d.ts +63 -0
  175. package/components/xlink.js +565 -0
  176. package/components/xmasonry.d.ts +35 -0
  177. package/components/xmasonry.js +666 -0
  178. package/components/xmenu.d.ts +118 -0
  179. package/components/xmenu.js +1005 -0
  180. package/components/xmodal.d.ts +64 -0
  181. package/components/xmodal.js +831 -0
  182. package/components/xplayer.d.ts +57 -0
  183. package/components/xplayer.js +1748 -0
  184. package/components/xpopover.d.ts +54 -0
  185. package/components/xpopover.js +466 -0
  186. package/components/xprogress.d.ts +40 -0
  187. package/components/xprogress.js +345 -0
  188. package/components/xradio.d.ts +50 -0
  189. package/components/xradio.js +474 -0
  190. package/components/xrouter.d.ts +244 -0
  191. package/components/xrouter.js +1841 -0
  192. package/components/xsection.d.ts +34 -0
  193. package/components/xsection.js +253 -0
  194. package/components/xselect.d.ts +46 -0
  195. package/components/xselect.js +463 -0
  196. package/components/xsidepanel.d.ts +56 -0
  197. package/components/xsidepanel.js +728 -0
  198. package/components/xspinner.d.ts +38 -0
  199. package/components/xspinner.js +388 -0
  200. package/components/xstate.d.ts +137 -0
  201. package/components/xstate.js +493 -0
  202. package/components/xstatus.d.ts +41 -0
  203. package/components/xstatus.js +381 -0
  204. package/components/xsummary.d.ts +43 -0
  205. package/components/xsummary.js +293 -0
  206. package/components/xsurfacemanager-controller.d.ts +130 -0
  207. package/components/xsurfacemanager-controller.js +699 -0
  208. package/components/xsurfacemanager.d.ts +452 -0
  209. package/components/xsurfacemanager.js +3775 -0
  210. package/components/xsurfaceoverlay-bridge.d.ts +43 -0
  211. package/components/xsurfaceoverlay-bridge.js +238 -0
  212. package/components/xsurfacewindow.d.ts +50 -0
  213. package/components/xsurfacewindow.js +576 -0
  214. package/components/xtabs.d.ts +73 -0
  215. package/components/xtabs.js +611 -0
  216. package/components/xtend-public-types.d.ts +208 -0
  217. package/components/xtextarea.d.ts +46 -0
  218. package/components/xtextarea.js +451 -0
  219. package/components/xtheme.d.ts +253 -0
  220. package/components/xtheme.js +1438 -0
  221. package/components/xtoast.d.ts +39 -0
  222. package/components/xtoast.js +389 -0
  223. package/components/xtooltip.d.ts +53 -0
  224. package/components/xtooltip.js +432 -0
  225. package/components/xtype.d.ts +42 -0
  226. package/components/xtype.js +244 -0
  227. package/components/xutils.d.ts +164 -0
  228. package/components/xutils.js +496 -0
  229. package/components/xwriter.d.ts +67 -0
  230. package/components/xwriter.js +854 -0
  231. package/design-tokens/themes/enterprise-light.json +40 -0
  232. package/design-tokens/themes/xtend-signature.json +126 -0
  233. package/design-tokens/xtend-design-tokens.d.ts +95 -0
  234. package/design-tokens/xtend-design-tokens.js +395 -0
  235. package/design-tokens/xtheme-token-alias-layer.d.ts +84 -0
  236. package/design-tokens/xtheme-token-alias-layer.js +423 -0
  237. package/docs/.htaccess +51 -0
  238. package/docs/README.md +340 -0
  239. package/docs/XTend-ADR.md +221 -0
  240. package/docs/a11y-keyboard-smokes.md +62 -0
  241. package/docs/about.md +18 -0
  242. package/docs/api.md +157 -0
  243. package/docs/best-practices.md +76 -0
  244. package/docs/component-catalog-coverage.md +58 -0
  245. package/docs/component-lab.md +103 -0
  246. package/docs/component-long-tail-migration.md +41 -0
  247. package/docs/component-platform.md +159 -0
  248. package/docs/component-ux-app-authoring.md +130 -0
  249. package/docs/component-ux-authoring.md +96 -0
  250. package/docs/component-ux-gates.md +45 -0
  251. package/docs/components/x-rmt-lifecycle-demo-build.md +60 -0
  252. package/docs/components/xalert.md +81 -0
  253. package/docs/components/xbutton.md +103 -0
  254. package/docs/components/xcalendar.md +82 -0
  255. package/docs/components/xcards.md +128 -0
  256. package/docs/components/xcheckbox.md +102 -0
  257. package/docs/components/xcode.md +126 -0
  258. package/docs/components/xdialog.md +92 -0
  259. package/docs/components/xdrawer.md +84 -0
  260. package/docs/components/xfooter.md +126 -0
  261. package/docs/components/xform.md +128 -0
  262. package/docs/components/xheader.md +308 -0
  263. package/docs/components/xhero.md +142 -0
  264. package/docs/components/xicon.md +125 -0
  265. package/docs/components/xinput.md +129 -0
  266. package/docs/components/xlightbox.md +98 -0
  267. package/docs/components/xlink.md +109 -0
  268. package/docs/components/xmasonry.md +124 -0
  269. package/docs/components/xmenu.md +158 -0
  270. package/docs/components/xmodal.md +82 -0
  271. package/docs/components/xplayer.md +104 -0
  272. package/docs/components/xpopover.md +67 -0
  273. package/docs/components/xprogress.md +56 -0
  274. package/docs/components/xradio.md +103 -0
  275. package/docs/components/xrouter.md +260 -0
  276. package/docs/components/xsection.md +125 -0
  277. package/docs/components/xselect.md +105 -0
  278. package/docs/components/xsidepanel.md +30 -0
  279. package/docs/components/xspinner.md +102 -0
  280. package/docs/components/xstate.md +148 -0
  281. package/docs/components/xstatus.md +55 -0
  282. package/docs/components/xsummary.md +78 -0
  283. package/docs/components/xsurfacemanager.md +27 -0
  284. package/docs/components/xsurfacewindow.md +21 -0
  285. package/docs/components/xtabs.md +160 -0
  286. package/docs/components/xtextarea.md +98 -0
  287. package/docs/components/xtheme.md +167 -0
  288. package/docs/components/xtoast.md +62 -0
  289. package/docs/components/xtooltip.md +66 -0
  290. package/docs/components/xtype.md +82 -0
  291. package/docs/components/xutils.md +144 -0
  292. package/docs/components/xwriter.md +94 -0
  293. package/docs/components.md +117 -0
  294. package/docs/conditional-network-evidence-ci.md +38 -0
  295. package/docs/conditional-network-evidence.md +50 -0
  296. package/docs/core-migration-guide.md +110 -0
  297. package/docs/design-tokens.md +116 -0
  298. package/docs/docs-rmt-production-hardening.md +31 -0
  299. package/docs/enterprise-adoption.md +411 -0
  300. package/docs/enterprise-component-flex-release-handoff.md +129 -0
  301. package/docs/epic10-platform-gates.md +62 -0
  302. package/docs/epic10-release-handoff.md +81 -0
  303. package/docs/epic11-enterprise-ux-handoff.md +70 -0
  304. package/docs/epic12-rc0-handoff.md +61 -0
  305. package/docs/existing-component-metadata.md +67 -0
  306. package/docs/hydration-performance-closure.md +34 -0
  307. package/docs/hydration-policies.md +71 -0
  308. package/docs/index.php +1625 -0
  309. package/docs/known-residual-triage.md +22 -0
  310. package/docs/manifest-import-policy.md +79 -0
  311. package/docs/manifest.md +106 -0
  312. package/docs/menu.json +1190 -0
  313. package/docs/motion-contrast.md +67 -0
  314. package/docs/package-export-lock.md +44 -0
  315. package/docs/performance-measurements.md +106 -0
  316. package/docs/performance-regression.md +89 -0
  317. package/docs/performance.md +94 -0
  318. package/docs/previews/README.md +17 -0
  319. package/docs/prod-browser-csp-smokes.md +40 -0
  320. package/docs/public-component-types.md +79 -0
  321. package/docs/quick-start-guide.md +152 -0
  322. package/docs/rc0-adoption-guide.md +102 -0
  323. package/docs/rc0-gate-matrix.md +58 -0
  324. package/docs/rc1-gate-matrix-ci-handoff.md +56 -0
  325. package/docs/rc1-migration-notes.md +69 -0
  326. package/docs/rc1-readiness.md +46 -0
  327. package/docs/release-owner-acceptance.md +56 -0
  328. package/docs/release-report-pack-dry-run-evidence.md +39 -0
  329. package/docs/rmt-dsl-authoring-polish.md +122 -0
  330. package/docs/rmt-first-demo-app.md +77 -0
  331. package/docs/rmt-first-xtend-apps.md +105 -0
  332. package/docs/rmt-kernel-panic-recovery-incident-handoff.md +61 -0
  333. package/docs/rmt-kernel-security-hardening-migration.md +50 -0
  334. package/docs/rmt-kernel-trusted-output-authoring.md +69 -0
  335. package/docs/rmt-language-server.md +177 -0
  336. package/docs/rmt-lifecycle-demo.md +25 -0
  337. package/docs/rmt-linter.md +140 -0
  338. package/docs/rmt-production-readiness.md +63 -0
  339. package/docs/rmt-tooling-release-gates.md +77 -0
  340. package/docs/rmt-vnext-authoring.md +60 -0
  341. package/docs/rmt-vnext-cross-surface-events.md +68 -0
  342. package/docs/rmt-vnext-enterprise-mfe-handoff.md +70 -0
  343. package/docs/rmt-vnext-migration-notes.md +62 -0
  344. package/docs/rmt-vnext-release-handoff.md +69 -0
  345. package/docs/rmt-vnext-remote-surfaces.md +90 -0
  346. package/docs/rmt-vnext-surface-registry-enterprise.md +76 -0
  347. package/docs/screenreader-signals.md +56 -0
  348. package/docs/supply-chain-gates.md +100 -0
  349. package/docs/surface-manager-authoring-guide.md +94 -0
  350. package/docs/surface-manager-browser-lab.md +45 -0
  351. package/docs/surface-manager-component-lab.md +43 -0
  352. package/docs/surface-manager-controller.md +66 -0
  353. package/docs/surface-manager-layout-engines.md +32 -0
  354. package/docs/surface-manager-lazy-hydration.md +63 -0
  355. package/docs/surface-manager-migration-guide.md +94 -0
  356. package/docs/surface-manager-native-rmt-surfaces.md +38 -0
  357. package/docs/surface-manager-overlay-bridge.md +53 -0
  358. package/docs/surface-manager-persistence.md +30 -0
  359. package/docs/surface-manager-quality-gates.md +51 -0
  360. package/docs/surface-manager-release-handoff.md +68 -0
  361. package/docs/surface-manager-remote-policy.md +54 -0
  362. package/docs/surface-manager-rmt-authoring.md +86 -0
  363. package/docs/surface-manager-route-lifecycle.md +59 -0
  364. package/docs/surface-manager-runtime-release-handoff.md +69 -0
  365. package/docs/surface-manager-side-panel-runtime.md +36 -0
  366. package/docs/surface-manager-stack-policy.md +39 -0
  367. package/docs/surface-manager-window-runtime.md +47 -0
  368. package/docs/surface-manager-workbench-fixture.md +43 -0
  369. package/docs/third-party-design-authoring.md +406 -0
  370. package/docs/trusted-dom-boundary-browser-proof.md +32 -0
  371. package/docs/trusted-dom-sanitizing.md +110 -0
  372. package/docs/type-exports.md +61 -0
  373. package/docs/typescript-components.md +63 -0
  374. package/docs/utils/fabric-runtime.js +650 -0
  375. package/docs/utils/pageloader.js +2823 -0
  376. package/docs/utils/parsedown.php +298 -0
  377. package/docs/visual-browser-regression.md +83 -0
  378. package/docs/visual-owner-artifacts.md +46 -0
  379. package/docs/visual-snapshot-automation.md +87 -0
  380. package/docs/xtend-api-types.md +55 -0
  381. package/docs/xtend-builder-types.md +55 -0
  382. package/docs/xtend-catalog-types.md +44 -0
  383. package/docs/xtend-fabric-rmt-lane-mapping.md +143 -0
  384. package/docs/xtend-fabric.md +474 -0
  385. package/docs/xtend-loader-types.md +58 -0
  386. package/docs/xtend-loader.md +265 -0
  387. package/docs/xtend-policy-types.md +38 -0
  388. package/docs/xtend-rmt-types.md +39 -0
  389. package/docs/xtend-vendor-types.md +36 -0
  390. package/docs/xtendrmt-app-dsl.md +269 -0
  391. package/docs/xtendrmt-migration-guide.md +235 -0
  392. package/docs/xtendrmt-native-authoring.md +337 -0
  393. package/docs/xtendrmt-overview.md +89 -0
  394. package/docs/xtendrmt-parsedown-docs.rmt +956 -0
  395. package/docs/xtendrmt-parsedown-scheduling.md +301 -0
  396. package/docs/xtendrmt-runtime-bridge.md +155 -0
  397. package/fabric/hydration-policy.d.ts +27 -0
  398. package/fabric/hydration-policy.js +306 -0
  399. package/fabric/package.json +58 -0
  400. package/fabric/rmt-lane-mapping.d.ts +47 -0
  401. package/fabric/rmt-lane-mapping.js +504 -0
  402. package/fabric/xtend-fabric.d.ts +81 -0
  403. package/fabric/xtend-fabric.js +2669 -0
  404. package/fabric/xtend-policy-public-types.d.ts +135 -0
  405. package/package.json +8225 -0
  406. package/security/README.md +54 -0
  407. package/security/manifest-import-policy.d.ts +43 -0
  408. package/security/manifest-import-policy.js +260 -0
  409. package/security/supply-chain-gate-policy.d.ts +45 -0
  410. package/security/supply-chain-gate-policy.js +249 -0
  411. package/security/trusted-dom-policy.d.ts +36 -0
  412. package/security/trusted-dom-policy.js +316 -0
  413. package/tools/package.json +77 -0
  414. package/tools/rmt-editor/vscode/README.md +33 -0
  415. package/tools/rmt-editor/vscode/extension.d.ts +9 -0
  416. package/tools/rmt-editor/vscode/extension.js +55 -0
  417. package/tools/rmt-editor/vscode/language-configuration.json +28 -0
  418. package/tools/rmt-editor/vscode/package.json +83 -0
  419. package/tools/rmt-editor/vscode/snippets/rmt.code-snippets +243 -0
  420. package/tools/rmt-editor/vscode/syntaxes/rmt.tmLanguage.json +13 -0
  421. package/tools/rmt-editor/vscode/xtend-rmt-language-0.0.0-enterprise-readiness.vsix +0 -0
  422. package/tools/rmt-language/code-actions.d.ts +15 -0
  423. package/tools/rmt-language/code-actions.js +566 -0
  424. package/tools/rmt-language/completions.d.ts +22 -0
  425. package/tools/rmt-language/completions.js +475 -0
  426. package/tools/rmt-language/definitions.d.ts +13 -0
  427. package/tools/rmt-language/definitions.js +212 -0
  428. package/tools/rmt-language/diagnostics.d.ts +23 -0
  429. package/tools/rmt-language/diagnostics.js +486 -0
  430. package/tools/rmt-language/format-adapter.d.ts +16 -0
  431. package/tools/rmt-language/format-adapter.js +270 -0
  432. package/tools/rmt-language/hover.d.ts +12 -0
  433. package/tools/rmt-language/hover.js +326 -0
  434. package/tools/rmt-language/kernel-escalation.d.ts +122 -0
  435. package/tools/rmt-language/kernel-escalation.js +427 -0
  436. package/tools/rmt-language/kernel-panic-monitor.d.ts +176 -0
  437. package/tools/rmt-language/kernel-panic-monitor.js +674 -0
  438. package/tools/rmt-language/kernel-policy-parity.d.ts +142 -0
  439. package/tools/rmt-language/kernel-policy-parity.js +629 -0
  440. package/tools/rmt-language/kernel-recovery.d.ts +173 -0
  441. package/tools/rmt-language/kernel-recovery.js +666 -0
  442. package/tools/rmt-language/kernel-scheduler-failure.d.ts +136 -0
  443. package/tools/rmt-language/kernel-scheduler-failure.js +486 -0
  444. package/tools/rmt-language/kernel-security-regression.d.ts +154 -0
  445. package/tools/rmt-language/kernel-security-regression.js +465 -0
  446. package/tools/rmt-language/kernel-trust-authority.d.ts +120 -0
  447. package/tools/rmt-language/kernel-trust-authority.js +549 -0
  448. package/tools/rmt-language/parser.d.ts +14 -0
  449. package/tools/rmt-language/parser.js +111 -0
  450. package/tools/rmt-language/rmt-tooling-public-types.d.ts +179 -0
  451. package/tools/rmt-language/rules/boundary-policy.js +81 -0
  452. package/tools/rmt-language/rules/document-policy.js +65 -0
  453. package/tools/rmt-language/rules/index.js +29 -0
  454. package/tools/rmt-language/rules/route-policy.js +81 -0
  455. package/tools/rmt-language/rules/scheduler-policy.js +66 -0
  456. package/tools/rmt-language/rules/template-policy.js +130 -0
  457. package/tools/rmt-language/semantic-graph.d.ts +18 -0
  458. package/tools/rmt-language/semantic-graph.js +827 -0
  459. package/tools/rmt-language/snippets/README.md +17 -0
  460. package/tools/rmt-language/snippets/index.d.ts +17 -0
  461. package/tools/rmt-language/snippets/index.js +417 -0
  462. package/tools/rmt-language/snippets/rmt.code-snippets +243 -0
  463. package/tools/rmt-language/source-model.d.ts +14 -0
  464. package/tools/rmt-language/source-model.js +731 -0
  465. package/tools/rmt-language/symbols.d.ts +13 -0
  466. package/tools/rmt-language/symbols.js +183 -0
  467. package/tools/rmt-language/vnext-compatibility.d.ts +28 -0
  468. package/tools/rmt-language/vnext-compatibility.js +675 -0
  469. package/tools/rmt-language/vnext-compiler.d.ts +17 -0
  470. package/tools/rmt-language/vnext-compiler.js +716 -0
  471. package/tools/rmt-language/vnext-composition.d.ts +30 -0
  472. package/tools/rmt-language/vnext-composition.js +595 -0
  473. package/tools/rmt-language/vnext-conditions.d.ts +25 -0
  474. package/tools/rmt-language/vnext-conditions.js +474 -0
  475. package/tools/rmt-language/vnext-cross-surface-events.d.ts +30 -0
  476. package/tools/rmt-language/vnext-cross-surface-events.js +607 -0
  477. package/tools/rmt-language/vnext-degradation.d.ts +23 -0
  478. package/tools/rmt-language/vnext-degradation.js +428 -0
  479. package/tools/rmt-language/vnext-enterprise-fixtures.d.ts +28 -0
  480. package/tools/rmt-language/vnext-enterprise-fixtures.js +487 -0
  481. package/tools/rmt-language/vnext-enterprise-registry.d.ts +21 -0
  482. package/tools/rmt-language/vnext-enterprise-registry.js +495 -0
  483. package/tools/rmt-language/vnext-enterprise-release.d.ts +44 -0
  484. package/tools/rmt-language/vnext-enterprise-release.js +472 -0
  485. package/tools/rmt-language/vnext-event-governance.d.ts +29 -0
  486. package/tools/rmt-language/vnext-event-governance.js +488 -0
  487. package/tools/rmt-language/vnext-events.d.ts +44 -0
  488. package/tools/rmt-language/vnext-events.js +680 -0
  489. package/tools/rmt-language/vnext-import-resolver.d.ts +28 -0
  490. package/tools/rmt-language/vnext-import-resolver.js +642 -0
  491. package/tools/rmt-language/vnext-lifecycle.d.ts +22 -0
  492. package/tools/rmt-language/vnext-lifecycle.js +404 -0
  493. package/tools/rmt-language/vnext-parser.d.ts +21 -0
  494. package/tools/rmt-language/vnext-parser.js +1391 -0
  495. package/tools/rmt-language/vnext-regression.d.ts +25 -0
  496. package/tools/rmt-language/vnext-regression.js +394 -0
  497. package/tools/rmt-language/vnext-release.d.ts +29 -0
  498. package/tools/rmt-language/vnext-release.js +293 -0
  499. package/tools/rmt-language/vnext-remote-compatibility.d.ts +33 -0
  500. package/tools/rmt-language/vnext-remote-compatibility.js +892 -0
  501. package/tools/rmt-language/vnext-remote-compiler.d.ts +14 -0
  502. package/tools/rmt-language/vnext-remote-compiler.js +520 -0
  503. package/tools/rmt-language/vnext-remote-manifest.d.ts +33 -0
  504. package/tools/rmt-language/vnext-remote-manifest.js +538 -0
  505. package/tools/rmt-language/vnext-remote-security.d.ts +27 -0
  506. package/tools/rmt-language/vnext-remote-security.js +380 -0
  507. package/tools/rmt-language/vnext-remote-tooling.d.ts +25 -0
  508. package/tools/rmt-language/vnext-remote-tooling.js +805 -0
  509. package/tools/rmt-language/vnext-scheduler.d.ts +24 -0
  510. package/tools/rmt-language/vnext-scheduler.js +469 -0
  511. package/tools/rmt-language/vnext-security.d.ts +28 -0
  512. package/tools/rmt-language/vnext-security.js +597 -0
  513. package/tools/rmt-language/vnext-streaming.d.ts +28 -0
  514. package/tools/rmt-language/vnext-streaming.js +593 -0
  515. package/tools/rmt-language/vnext-surfaces.d.ts +24 -0
  516. package/tools/rmt-language/vnext-surfaces.js +406 -0
  517. package/tools/rmt-language/vnext-tooling.d.ts +25 -0
  518. package/tools/rmt-language/vnext-tooling.js +728 -0
  519. package/tools/rmt-language-server/protocol.d.ts +22 -0
  520. package/tools/rmt-language-server/protocol.js +352 -0
  521. package/tools/rmt-language-server/server.d.ts +15 -0
  522. package/tools/rmt-language-server/server.js +622 -0
  523. package/tools/rmt-linter/cli.d.ts +14 -0
  524. package/tools/rmt-linter/cli.js +450 -0
  525. package/tools/rmt-linter/reporter.d.ts +16 -0
  526. package/tools/rmt-linter/reporter.js +472 -0
  527. package/xtend-builder/README.md +83 -0
  528. package/xtend-builder/a11y/README.md +42 -0
  529. package/xtend-builder/a11y/component-a11y-profile.d.ts +14 -0
  530. package/xtend-builder/a11y/component-a11y-profile.js +314 -0
  531. package/xtend-builder/blueprints/README.md +105 -0
  532. package/xtend-builder/blueprints/component-blueprint.contract.d.ts +16 -0
  533. package/xtend-builder/blueprints/component-blueprint.contract.js +343 -0
  534. package/xtend-builder/builder-public-types.d.ts +234 -0
  535. package/xtend-builder/extensions/README.md +26 -0
  536. package/xtend-builder/extensions/component-extension-points.d.ts +11 -0
  537. package/xtend-builder/extensions/component-extension-points.js +277 -0
  538. package/xtend-builder/generators/README.md +149 -0
  539. package/xtend-builder/generators/component-files.d.ts +5 -0
  540. package/xtend-builder/generators/component-files.js +769 -0
  541. package/xtend-builder/generators/component-plan.d.ts +4 -0
  542. package/xtend-builder/generators/component-plan.js +104 -0
  543. package/xtend-builder/generators/registry.d.ts +6 -0
  544. package/xtend-builder/generators/registry.js +118 -0
  545. package/xtend-builder/generators/rmt-build.js +738 -0
  546. package/xtend-builder/generators/rmt-lifecycle-demo.js +922 -0
  547. package/xtend-builder/lib/cli.d.ts +9 -0
  548. package/xtend-builder/lib/cli.js +543 -0
  549. package/xtend-builder/lib/layout.d.ts +6 -0
  550. package/xtend-builder/lib/layout.js +153 -0
  551. package/xtend-builder/lib/package-resolver.js +25 -0
  552. package/xtend-builder/package.json +90 -0
  553. package/xtend-builder/performance/README.md +31 -0
  554. package/xtend-builder/performance/component-performance-profile.d.ts +11 -0
  555. package/xtend-builder/performance/component-performance-profile.js +347 -0
  556. package/xtend-builder/performance/component-ux-performance-contract.d.ts +27 -0
  557. package/xtend-builder/performance/component-ux-performance-contract.js +424 -0
  558. package/xtend-builder/preview/README.md +61 -0
  559. package/xtend-builder/preview/component-lab-ux-inspector.d.ts +20 -0
  560. package/xtend-builder/preview/component-lab-ux-inspector.js +448 -0
  561. package/xtend-builder/preview/component-lab.d.ts +14 -0
  562. package/xtend-builder/preview/component-lab.js +278 -0
  563. package/xtend-builder/preview/component-preview.d.ts +5 -0
  564. package/xtend-builder/preview/component-preview.js +160 -0
  565. package/xtend-builder/scaffold.config.d.ts +4 -0
  566. package/xtend-builder/scaffold.config.js +2056 -0
  567. package/xtend-builder/scaffold.d.ts +3 -0
  568. package/xtend-builder/scaffold.js +11 -0
  569. package/xtend-builder/templates/README.md +33 -0
  570. package/xtend-builder/templates/component/a11y.template.ts +11 -0
  571. package/xtend-builder/templates/component/component-suite.template.d.ts +2 -0
  572. package/xtend-builder/templates/component/component-suite.template.js +108 -0
  573. package/xtend-builder/templates/component/contract.template.ts +10 -0
  574. package/xtend-builder/templates/component/demo-plan.template.md +73 -0
  575. package/xtend-builder/templates/component/docs.template.md +301 -0
  576. package/xtend-builder/templates/component/fixture-data.template.ts +28 -0
  577. package/xtend-builder/templates/component/fixture.template.html +37 -0
  578. package/xtend-builder/templates/component/manifest-plan.template.json +22 -0
  579. package/xtend-builder/templates/component/performance.template.ts +13 -0
  580. package/xtend-builder/templates/component/rmt.template.ts +12 -0
  581. package/xtend-builder/templates/component/source.template.d.ts +2 -0
  582. package/xtend-builder/templates/component/source.template.js +137 -0
  583. package/xtend-builder/templates/component/source.template.ts +110 -0
  584. package/xtend-builder/templates/component/types.template.d.ts +423 -0
  585. package/xtend-builder/templates/loader.d.ts +4 -0
  586. package/xtend-builder/templates/loader.js +51 -0
  587. package/xtend-builder/templates/registry.d.ts +6 -0
  588. package/xtend-builder/templates/registry.js +119 -0
  589. package/xtend-builder/typing/README.md +130 -0
  590. package/xtend-builder/typing/component-contract-v2.d.ts +15 -0
  591. package/xtend-builder/typing/component-contract-v2.js +248 -0
  592. package/xtend-builder/typing/component-network-contract.d.ts +22 -0
  593. package/xtend-builder/typing/component-network-contract.js +478 -0
  594. package/xtend-builder/typing/component-shell-contract.d.ts +21 -0
  595. package/xtend-builder/typing/component-shell-contract.js +312 -0
  596. package/xtend-builder/typing/component-styling-contract.d.ts +22 -0
  597. package/xtend-builder/typing/component-styling-contract.js +301 -0
  598. package/xtend-builder/typing/component-types.d.ts +10 -0
  599. package/xtend-builder/typing/component-types.js +551 -0
  600. package/xtend-builder/typing/enterprise-component-flex-hardening-contract.d.ts +20 -0
  601. package/xtend-builder/typing/enterprise-component-flex-hardening-contract.js +332 -0
  602. package/xtend-builder/typing/feedback-status-ux-contract.d.ts +25 -0
  603. package/xtend-builder/typing/feedback-status-ux-contract.js +347 -0
  604. package/xtend-builder/typing/form-controls-ux-contract.d.ts +25 -0
  605. package/xtend-builder/typing/form-controls-ux-contract.js +357 -0
  606. package/xtend-builder/typing/layout-display-media-ux-contract.d.ts +25 -0
  607. package/xtend-builder/typing/layout-display-media-ux-contract.js +420 -0
  608. package/xtend-builder/typing/navigation-routing-ux-contract.d.ts +17 -0
  609. package/xtend-builder/typing/navigation-routing-ux-contract.js +297 -0
  610. package/xtend-builder/typing/overlay-interaction-ux-contract.d.ts +25 -0
  611. package/xtend-builder/typing/overlay-interaction-ux-contract.js +383 -0
  612. package/xtend-builder/typing/rmt-dsl-authoring-polish.d.ts +27 -0
  613. package/xtend-builder/typing/rmt-dsl-authoring-polish.js +419 -0
  614. package/xtend-builder/typing/rmt-shell-authoring-contract.d.ts +26 -0
  615. package/xtend-builder/typing/rmt-shell-authoring-contract.js +315 -0
  616. package/xtend-builder/utils/README.md +8 -0
  617. package/xtend-builder/utils/naming.d.ts +7 -0
  618. package/xtend-builder/utils/naming.js +36 -0
  619. package/xtend-builder/utils/validation.d.ts +5 -0
  620. package/xtend-builder/utils/validation.js +95 -0
  621. package/xtend-builder/wiring/README.md +46 -0
  622. package/xtend-builder/wiring/features.d.ts +5 -0
  623. package/xtend-builder/wiring/features.js +165 -0
  624. package/xtend-builder/wiring/hydration.d.ts +4 -0
  625. package/xtend-builder/wiring/hydration.js +44 -0
  626. package/xtend-builder/wiring/manifest.d.ts +5 -0
  627. package/xtend-builder/wiring/manifest.js +48 -0
  628. package/xtend-builder/workflows/README.md +47 -0
  629. package/xtend-builder/workflows/developer-workflow.d.ts +6 -0
  630. package/xtend-builder/workflows/developer-workflow.js +125 -0
  631. package/xtend-builder/writing/manifest-patcher.d.ts +49 -0
  632. package/xtend-builder/writing/manifest-patcher.js +391 -0
  633. package/xtend-builder/writing/write-plan.d.ts +148 -0
  634. package/xtend-builder/writing/write-plan.js +646 -0
  635. package/xtend-dev.d.ts +23 -0
  636. package/xtend-dev.js +4 -0
  637. package/xtend-loader.d.ts +201 -0
  638. package/xtend-loader.js +1704 -0
  639. package/xtend.css +402 -0
  640. package/xtendrmt/package.json +64 -0
  641. package/xtendrmt/rmt-core.d.ts +4452 -0
  642. package/xtendrmt/rmt-core.esm.js +25793 -0
  643. package/xtendrmt/rmt-first-demo-app.js +265 -0
  644. package/xtendrmt/rmt-first-demo-app.rmt +737 -0
  645. package/xtendrmt/rmt-lifecycle-demo.app.js +493 -0
  646. package/xtendrmt/rmt-lifecycle-demo.core.json +810 -0
  647. package/xtendrmt/rmt-lifecycle-demo.rmt +35 -0
  648. package/xtendrmt/rmt-lifecycle-demo.rmt-build.app.js +153 -0
  649. package/xtendrmt/rmt-lifecycle-demo.rmt-build.core.json +810 -0
  650. package/xtendrmt/rmt-lifecycle-demo.rmt-build.scaffold.json +202 -0
  651. package/xtendrmt/rmt-lifecycle-demo.scaffold.json +187 -0
  652. package/xtendrmt/rmt-manifest.json +548 -0
  653. package/xtendrmt/rmt-runtime.browser.js +26183 -0
  654. package/xtendrmt/rmt-runtime.esm.js +26214 -0
  655. package/xtendrmt/rmt-vnext-enterprise-mfe-demo.core.json +849 -0
  656. package/xtendrmt/rmt-vnext-enterprise-mfe-demo.rmt +50 -0
  657. package/xtendrmt/rmt-vnext-reference-demo.core.json +1069 -0
  658. package/xtendrmt/rmt-vnext-reference-demo.rmt +50 -0
  659. package/xtendrmt/rmt.schema.json +3145 -0
  660. package/xtendrmt/surface-workbench.js +316 -0
  661. package/xtendrmt/surface-workbench.rmt +762 -0
  662. package/xtendrmt/xtendrmt-bestcase-demo.core.json +1187 -0
  663. package/xtendrmt/xtendrmt-bestcase-demo.js +1728 -0
  664. package/xtendrmt/xtendrmt-bestcase-demo.rmt +57 -0
@@ -0,0 +1,3775 @@
1
+ import { xstate } from './xstate.js';
2
+ import './xsurfacemanager-controller.js';
3
+ import {
4
+ OVERLAY_LIFECYCLE_EVENTS,
5
+ SURFACE_OVERLAY_SELECTOR,
6
+ applyOverlaySurfaceSnapshot,
7
+ findSurfaceOverlayElement,
8
+ isSurfaceOverlayElement,
9
+ overlaySurfaceId,
10
+ toOverlaySurfaceRecord
11
+ } from './xsurfaceoverlay-bridge.js';
12
+
13
+ const SURFACE_MANAGED_ELEMENT_SELECTOR = `x-surface-window, x-side-panel, ${SURFACE_OVERLAY_SELECTOR}`;
14
+ const SURFACE_MANAGER_PERSISTENCE_SCHEMA = 'xtend.surface.manager-persistence.v1';
15
+ const SURFACE_PERSISTED_SNAPSHOT_SCHEMA = 'xtend.surface.persisted-snapshot.v1';
16
+ const SURFACE_PERSISTENCE_DIAGNOSTIC_SCHEMA = 'xtend.surface.persistence-diagnostic.v1';
17
+ const SURFACE_PERSISTENCE_VERSION = 1;
18
+ const SURFACE_LOADING_POLICY_SCHEMA = 'xtend.surface.loading-policy.v1';
19
+ const SURFACE_LOADING_REPORT_SCHEMA = 'xtend.surface.loading-report.v1';
20
+ const SURFACE_LOADING_DIAGNOSTIC_SCHEMA = 'xtend.surface.loading-diagnostic.v1';
21
+ const SURFACE_LOADING_POLICIES = Object.freeze(['eager', 'visible', 'open', 'idle', 'route']);
22
+ const SURFACE_ROUTE_LIFECYCLE_SCHEMA = 'xtend.surface.route-lifecycle.v1';
23
+ const SURFACE_ROUTE_LIFECYCLE_REPORT_SCHEMA = 'xtend.surface.route-lifecycle-report.v1';
24
+ const SURFACE_ROUTE_LIFECYCLE_DIAGNOSTIC_SCHEMA = 'xtend.surface.route-lifecycle-diagnostic.v1';
25
+ const SURFACE_ROUTE_LIFECYCLE_POLICIES = Object.freeze(['global', 'open-close', 'open-collapse', 'open-minimize', 'open-keep', 'hydrate-only', 'manual']);
26
+ const SURFACE_STACK_POLICY_SCHEMA = 'xtend.surface.stack-policy.v1';
27
+ const SURFACE_STACK_POLICY_REPORT_SCHEMA = 'xtend.surface.stack-policy-report.v1';
28
+ const SURFACE_STACK_POLICY_DIAGNOSTIC_SCHEMA = 'xtend.surface.stack-policy-diagnostic.v1';
29
+ const SURFACE_MODAL_POLICIES = Object.freeze(['topmost', 'none', 'all-modal', 'surface-modal']);
30
+ const SURFACE_LAYOUT_ENGINE_SCHEMA = 'xtend.surface.layout-engine.v1';
31
+ const SURFACE_LAYOUT_ENGINE_REPORT_SCHEMA = 'xtend.surface.layout-engine-report.v1';
32
+ const SURFACE_LAYOUT_ENGINE_DIAGNOSTIC_SCHEMA = 'xtend.surface.layout-engine-diagnostic.v1';
33
+ const SURFACE_LAYOUT_ENGINES = Object.freeze(['freeform', 'docked', 'split', 'tile', 'stacked']);
34
+ const SURFACE_LAYOUT_SURFACE_TYPES = Object.freeze(['window', 'side-panel']);
35
+ const SURFACE_LAYOUT_PLACEMENTS = Object.freeze(['left', 'right', 'top', 'bottom', 'inline', 'center']);
36
+ const SURFACE_REMOTE_POLICY_SCHEMA = 'xtend.surface.remote-policy-bridge.v1';
37
+ const SURFACE_REMOTE_POLICY_REPORT_SCHEMA = 'xtend.surface.remote-policy-report.v1';
38
+ const SURFACE_REMOTE_POLICY_DIAGNOSTIC_SCHEMA = 'xtend.surface.remote-policy-diagnostic.v1';
39
+ const SURFACE_REMOTE_TRUST_BOUNDARY = 'xtend.security.remote-surface.v1';
40
+ const SURFACE_REMOTE_POLICY_MODES = Object.freeze(['strict', 'audit', 'off']);
41
+ const SURFACE_REMOTE_INTEGRITY_ALGORITHMS = Object.freeze(['sha256', 'sha384', 'sha512']);
42
+ const SURFACE_REMOTE_ALLOWED_CAPABILITIES = Object.freeze(['surface.mount', 'surface.focus', 'surface.close', 'surface.snapshot', 'event.emit', 'event.consume']);
43
+ const SURFACE_REMOTE_DECISIONS = Object.freeze(['mounted', 'degraded', 'refused']);
44
+ const SURFACE_STACK_FOCUS_SELECTOR = [
45
+ '[autofocus]',
46
+ '[tabindex]:not([tabindex="-1"])',
47
+ 'button:not([disabled])',
48
+ 'a[href]',
49
+ 'input:not([disabled])',
50
+ 'select:not([disabled])',
51
+ 'textarea:not([disabled])',
52
+ '[part~="surface"]',
53
+ '[role="dialog"]'
54
+ ].join(', ');
55
+ const SURFACE_ROUTE_EVENT_NAMES = Object.freeze([
56
+ 'popstate',
57
+ 'hashchange',
58
+ 'route-changed',
59
+ 'routechange',
60
+ 'xrouter-after-navigate',
61
+ 'xtend-route-changed',
62
+ 'xtend-router:navigate',
63
+ 'xtend-router:after-navigate',
64
+ 'xrouter:navigate',
65
+ 'xrouter:route-change'
66
+ ]);
67
+ const SURFACE_PERSISTENCE_MEMORY = globalThis.__XTendSurfaceManagerPersistenceMemory instanceof Map
68
+ ? globalThis.__XTendSurfaceManagerPersistenceMemory
69
+ : new Map();
70
+
71
+ globalThis.__XTendSurfaceManagerPersistenceMemory = SURFACE_PERSISTENCE_MEMORY;
72
+
73
+ function surfaceControllerApi() {
74
+ return globalThis.XTendSurfaceController || null;
75
+ }
76
+
77
+ function fabricBridge() {
78
+ const candidates = [
79
+ globalThis.xtendFabric,
80
+ globalThis.XTendFabricRuntime,
81
+ globalThis.XTendFabric && globalThis.XTendFabric.runtime
82
+ ];
83
+ return candidates.find((candidate) => candidate && typeof candidate.emitDiagnostic === 'function') || null;
84
+ }
85
+
86
+ function composedSurfaceElements(slot) {
87
+ return slot.assignedElements({ flatten: true })
88
+ .flatMap((element) => {
89
+ if (element.matches && element.matches(SURFACE_MANAGED_ELEMENT_SELECTOR)) return [element];
90
+ return Array.from(element.querySelectorAll ? element.querySelectorAll(SURFACE_MANAGED_ELEMENT_SELECTOR) : []);
91
+ });
92
+ }
93
+
94
+ function cssAttributeValue(value) {
95
+ return String(value).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
96
+ }
97
+
98
+ function surfaceElementSelector(surfaceId) {
99
+ const id = cssAttributeValue(surfaceId);
100
+ const overlayBySurfaceId = SURFACE_OVERLAY_SELECTOR
101
+ .split(',')
102
+ .map((selector) => `${selector.trim()}[surface-id="${id}"]`)
103
+ .join(', ');
104
+ const overlayById = SURFACE_OVERLAY_SELECTOR
105
+ .split(',')
106
+ .map((selector) => `${selector.trim()}[id="${id}"]`)
107
+ .join(', ');
108
+ return `x-surface-window[surface-id="${id}"], x-side-panel[surface-id="${id}"], ${overlayBySurfaceId}, ${overlayById}`;
109
+ }
110
+
111
+ function safeJsonParse(value) {
112
+ try {
113
+ return JSON.parse(value);
114
+ } catch (_error) {
115
+ return null;
116
+ }
117
+ }
118
+
119
+ function createMemoryStorageAdapter() {
120
+ return {
121
+ kind: 'memory',
122
+ getItem(key) {
123
+ return SURFACE_PERSISTENCE_MEMORY.has(key) ? SURFACE_PERSISTENCE_MEMORY.get(key) : null;
124
+ },
125
+ setItem(key, value) {
126
+ SURFACE_PERSISTENCE_MEMORY.set(key, String(value));
127
+ },
128
+ removeItem(key) {
129
+ SURFACE_PERSISTENCE_MEMORY.delete(key);
130
+ }
131
+ };
132
+ }
133
+
134
+ function createWebStorageAdapter(kind) {
135
+ const storageName = kind === 'local' ? 'localStorage' : 'sessionStorage';
136
+ const storage = globalThis && globalThis[storageName];
137
+ if (!storage || typeof storage.getItem !== 'function' || typeof storage.setItem !== 'function') return null;
138
+ return {
139
+ kind,
140
+ getItem(key) {
141
+ return storage.getItem(key);
142
+ },
143
+ setItem(key, value) {
144
+ storage.setItem(key, value);
145
+ },
146
+ removeItem(key) {
147
+ storage.removeItem(key);
148
+ }
149
+ };
150
+ }
151
+
152
+ function normalizePersistenceMode(value, restoreKey) {
153
+ const mode = String(value || '').trim();
154
+ if (['none', 'memory', 'session', 'local'].includes(mode)) return mode;
155
+ return restoreKey ? 'session' : 'none';
156
+ }
157
+
158
+ function normalizeSurfaceLoadingPolicy(value, fallback = 'open') {
159
+ const policy = String(value || '').trim().toLowerCase();
160
+ if (SURFACE_LOADING_POLICIES.includes(policy)) return policy;
161
+ return SURFACE_LOADING_POLICIES.includes(fallback) ? fallback : 'open';
162
+ }
163
+
164
+ function normalizeSurfaceRouteLifecyclePolicy(value, fallback = 'open-close') {
165
+ const policy = String(value || '').trim().toLowerCase();
166
+ if (SURFACE_ROUTE_LIFECYCLE_POLICIES.includes(policy)) return policy;
167
+ return SURFACE_ROUTE_LIFECYCLE_POLICIES.includes(fallback) ? fallback : 'open-close';
168
+ }
169
+
170
+ function normalizeSurfaceModalPolicy(value, fallback = 'topmost') {
171
+ const policy = String(value || '').trim().toLowerCase();
172
+ if (SURFACE_MODAL_POLICIES.includes(policy)) return policy;
173
+ return SURFACE_MODAL_POLICIES.includes(fallback) ? fallback : 'topmost';
174
+ }
175
+
176
+ function normalizeSurfaceLayoutEngine(value, fallback = 'freeform') {
177
+ const engine = String(value || '').trim().toLowerCase();
178
+ if (SURFACE_LAYOUT_ENGINES.includes(engine)) return engine;
179
+ return SURFACE_LAYOUT_ENGINES.includes(fallback) ? fallback : 'freeform';
180
+ }
181
+
182
+ function normalizeSurfaceLayoutPlacement(value, fallback = 'center') {
183
+ const placement = String(value || '').trim().toLowerCase();
184
+ if (SURFACE_LAYOUT_PLACEMENTS.includes(placement)) return placement;
185
+ return SURFACE_LAYOUT_PLACEMENTS.includes(fallback) ? fallback : 'center';
186
+ }
187
+
188
+ function normalizeSurfaceLoadingTimeout(value) {
189
+ const timeout = Number(value);
190
+ if (Number.isFinite(timeout) && timeout >= 0) return timeout;
191
+ return 4000;
192
+ }
193
+
194
+ function normalizeSurfaceLayoutNumber(value, fallback, minimum = 0) {
195
+ const number = Number(value);
196
+ if (Number.isFinite(number)) return Math.max(minimum, number);
197
+ return fallback;
198
+ }
199
+
200
+ function isSurfaceRecordOpen(record = {}) {
201
+ return record.status !== 'closed' && record.status !== 'minimized' && record.collapsed !== true;
202
+ }
203
+
204
+ function surfaceLoaderApi() {
205
+ const loader = globalThis.XTendLoader || {};
206
+ const skeleton = loader.skeletonLoader || globalThis.XTendSkeletonLoader || {};
207
+ return {
208
+ available: Boolean(globalThis.XTendLoader || globalThis.XTendSkeletonLoader),
209
+ ensureRuntimeStyles: typeof loader.ensureRuntimeStyles === 'function' ? loader.ensureRuntimeStyles.bind(loader) : null,
210
+ ensureComponent: typeof loader.ensureComponent === 'function' ? loader.ensureComponent.bind(loader) : null,
211
+ hydrateTree: typeof loader.hydrateTree === 'function' ? loader.hydrateTree.bind(loader) : null,
212
+ showSkeleton: typeof loader.showSkeleton === 'function'
213
+ ? loader.showSkeleton.bind(loader)
214
+ : (typeof skeleton.show === 'function' ? skeleton.show.bind(skeleton) : null),
215
+ hideSkeleton: typeof loader.hideSkeleton === 'function'
216
+ ? loader.hideSkeleton.bind(loader)
217
+ : (typeof skeleton.hide === 'function' ? skeleton.hide.bind(skeleton) : null)
218
+ };
219
+ }
220
+
221
+ function surfaceLoadingNow() {
222
+ const performanceTarget = globalThis.performance;
223
+ if (performanceTarget && typeof performanceTarget.now === 'function') return performanceTarget.now();
224
+ return Date.now();
225
+ }
226
+
227
+ function collectSurfaceHydrationTags(root) {
228
+ if (!root || typeof root.querySelectorAll !== 'function') return [];
229
+ const tags = new Set();
230
+ Array.from(root.querySelectorAll('*')).forEach((element) => {
231
+ if (!element || element.hasAttribute('data-xtend-skeleton-loader')) return;
232
+ const tag = String(element.localName || '').trim().toLowerCase();
233
+ if (tag.includes('-')) tags.add(tag);
234
+ });
235
+ return Array.from(tags);
236
+ }
237
+
238
+ function scheduleSurfaceIdle(callback) {
239
+ if (typeof globalThis.requestIdleCallback === 'function') {
240
+ return globalThis.requestIdleCallback(callback, { timeout: 1000 });
241
+ }
242
+ return globalThis.setTimeout(callback, 120);
243
+ }
244
+
245
+ function clearSurfaceIdle(handle) {
246
+ if (typeof globalThis.cancelIdleCallback === 'function') {
247
+ globalThis.cancelIdleCallback(handle);
248
+ return;
249
+ }
250
+ globalThis.clearTimeout(handle);
251
+ }
252
+
253
+ function normalizeSurfaceRouteToken(value) {
254
+ const raw = String(value || '').trim();
255
+ if (!raw) return '';
256
+ const withoutHash = raw.replace(/^#\/?/, '/');
257
+ const withoutQuery = withoutHash.split('?')[0].split('#')[0];
258
+ return withoutQuery.replace(/^\/+/, '').replace(/\/+$/, '').trim().toLowerCase();
259
+ }
260
+
261
+ function surfaceRouteTokens(value) {
262
+ const token = normalizeSurfaceRouteToken(value);
263
+ if (!token) return [];
264
+ return [token, `/${token}`];
265
+ }
266
+
267
+ function surfaceBooleanAttribute(element, names = []) {
268
+ if (!element) return false;
269
+ return names.some((name) => {
270
+ if (!element.hasAttribute(name)) return false;
271
+ const value = String(element.getAttribute(name) || '').trim().toLowerCase();
272
+ return !['false', '0', 'no', 'off'].includes(value);
273
+ });
274
+ }
275
+
276
+ function surfaceElementContainsTarget(element, target) {
277
+ if (!element || !target) return false;
278
+ if (element === target) return true;
279
+ if (typeof element.contains === 'function' && element.contains(target)) return true;
280
+ const root = typeof target.getRootNode === 'function' ? target.getRootNode() : null;
281
+ if (root && root.host) {
282
+ return root.host === element || (typeof element.contains === 'function' && element.contains(root.host));
283
+ }
284
+ return Boolean(element.shadowRoot && typeof element.shadowRoot.contains === 'function' && element.shadowRoot.contains(target));
285
+ }
286
+
287
+ function surfaceFocusableTarget(element) {
288
+ if (!element) return null;
289
+ const roots = [element.shadowRoot, element].filter(Boolean);
290
+ for (const root of roots) {
291
+ if (typeof root.querySelector !== 'function') continue;
292
+ const target = root.querySelector(SURFACE_STACK_FOCUS_SELECTOR);
293
+ if (target && typeof target.focus === 'function') return target;
294
+ }
295
+ return typeof element.focus === 'function' ? element : null;
296
+ }
297
+
298
+ function snapSurfaceLayoutValue(value, snap = 1) {
299
+ const step = Math.max(1, Number(snap) || 1);
300
+ return Math.round(Number(value || 0) / step) * step;
301
+ }
302
+
303
+ function surfaceLayoutBoundsEqual(left = {}, right = {}) {
304
+ return ['x', 'y', 'width', 'height'].every((key) => Math.round(Number(left[key]) || 0) === Math.round(Number(right[key]) || 0));
305
+ }
306
+
307
+ function normalizeSurfaceRemotePolicyMode(value, fallback = 'strict') {
308
+ const mode = String(value || '').trim().toLowerCase();
309
+ if (SURFACE_REMOTE_POLICY_MODES.includes(mode)) return mode;
310
+ return SURFACE_REMOTE_POLICY_MODES.includes(fallback) ? fallback : 'strict';
311
+ }
312
+
313
+ function normalizeSurfaceRemoteList(value) {
314
+ if (Array.isArray(value)) {
315
+ return value.flatMap((entry) => normalizeSurfaceRemoteList(entry));
316
+ }
317
+ if (value && typeof value === 'object') {
318
+ return normalizeSurfaceRemoteList(value.id || value.name || value.capability || value.event || value.ref || '');
319
+ }
320
+ return String(value || '')
321
+ .split(',')
322
+ .map((entry) => entry.trim())
323
+ .filter(Boolean);
324
+ }
325
+
326
+ function normalizeSurfaceRemoteOwner(owner) {
327
+ if (typeof owner === 'string') {
328
+ return {
329
+ kind: 'team',
330
+ id: owner.trim(),
331
+ known: Boolean(owner.trim())
332
+ };
333
+ }
334
+ const source = owner && typeof owner === 'object' ? owner : {};
335
+ const id = String(source.id || source.team || source.name || '').trim();
336
+ return {
337
+ kind: String(source.kind || source.type || 'team').trim() || 'team',
338
+ id,
339
+ known: Boolean(id || source.known === true)
340
+ };
341
+ }
342
+
343
+ function normalizeSurfaceRemoteCapabilityIds(capabilities) {
344
+ return normalizeSurfaceRemoteList(capabilities)
345
+ .map((capability) => String(capability || '').trim())
346
+ .filter(Boolean);
347
+ }
348
+
349
+ function normalizeSurfaceRemoteOrigin(value) {
350
+ const raw = String(value || '').trim();
351
+ if (!raw) return '';
352
+ try {
353
+ const url = new URL(raw, globalThis.location && globalThis.location.href || 'https://xtend.local/');
354
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') return '';
355
+ return url.origin;
356
+ } catch (_error) {
357
+ return '';
358
+ }
359
+ }
360
+
361
+ function surfaceRemoteRecordSource(input = {}) {
362
+ if (!input || typeof input !== 'object') return {};
363
+ const metadata = input.metadata && typeof input.metadata === 'object' ? input.metadata : {};
364
+ const candidates = [
365
+ input.remoteSurface,
366
+ metadata.remoteSurface,
367
+ input.remotePolicy && input.remotePolicy.remoteSurface,
368
+ input.sourceSurface && input.sourceSurface.remoteSurface,
369
+ input.sourceSurface && input.sourceSurface.metadata && input.sourceSurface.metadata.remoteSurface,
370
+ input
371
+ ];
372
+ return candidates.find((candidate) => candidate && typeof candidate === 'object' && (
373
+ candidate.schema === 'xtend.rmt.vnext-remote-surface.v1'
374
+ || candidate.remote
375
+ || candidate.security
376
+ || candidate.adapterBoundary
377
+ || candidate.manifestId
378
+ )) || {};
379
+ }
380
+
381
+ function isSurfaceRemoteInput(input = {}) {
382
+ const source = surfaceRemoteRecordSource(input);
383
+ return Boolean(source && (
384
+ source.schema === 'xtend.rmt.vnext-remote-surface.v1'
385
+ || source.remote
386
+ || source.security
387
+ || source.adapterBoundary
388
+ || source.kind === 'remote'
389
+ || source.type === 'remote'
390
+ ));
391
+ }
392
+
393
+ function normalizeSurfaceRemoteBinding(entry = {}) {
394
+ if (typeof entry === 'string') {
395
+ return { lane: '', target: entry.trim(), mode: 'mount' };
396
+ }
397
+ const source = entry && typeof entry === 'object' ? entry : {};
398
+ const target = source.target && typeof source.target === 'object'
399
+ ? source.target.ref
400
+ : (source.target || source.shellTarget || source.slot || source.ref || '');
401
+ return {
402
+ lane: String(source.lane || '').trim(),
403
+ target: String(target || '').trim(),
404
+ mode: String(source.mode || 'mount').trim() || 'mount'
405
+ };
406
+ }
407
+
408
+ function normalizeSurfaceRemoteEvent(entry = {}, direction = '') {
409
+ const source = entry && typeof entry === 'object' ? entry : {};
410
+ return {
411
+ event: String(source.event || source.name || '').trim(),
412
+ direction: String(source.direction || direction || '').trim(),
413
+ owner: normalizeSurfaceRemoteOwner(source.owner || ''),
414
+ version: String(source.version || '').trim(),
415
+ payload: source.payload && typeof source.payload === 'object' ? { ...source.payload } : null,
416
+ scopes: normalizeSurfaceRemoteList(source.scopes),
417
+ lane: String(source.lane || '').trim()
418
+ };
419
+ }
420
+
421
+ function normalizeSurfaceRemoteRecord(input = {}, options = {}) {
422
+ const source = surfaceRemoteRecordSource(input);
423
+ const remote = source.remote && typeof source.remote === 'object' ? source.remote : {};
424
+ const security = source.security && typeof source.security === 'object' ? source.security : {};
425
+ const runtime = source.runtime && typeof source.runtime === 'object' ? source.runtime : {};
426
+ const adapterBoundary = source.adapterBoundary && typeof source.adapterBoundary === 'object' ? source.adapterBoundary : {};
427
+ const fallback = source.fallback && typeof source.fallback === 'object'
428
+ ? source.fallback
429
+ : (input.fallback && typeof input.fallback === 'object' ? input.fallback : null);
430
+ const id = String(source.surfaceId || source.id || input.surfaceId || input.id || source.name || '').trim();
431
+ const bindings = (Array.isArray(source.shellBindings) ? source.shellBindings : (Array.isArray(source.exposes) ? source.exposes : []))
432
+ .map(normalizeSurfaceRemoteBinding)
433
+ .filter((binding) => binding.target);
434
+ const emits = Array.isArray(source.events && source.events.emits)
435
+ ? source.events.emits.map((event) => normalizeSurfaceRemoteEvent(event, 'outbound'))
436
+ : [];
437
+ const consumes = Array.isArray(source.events && source.events.consumes)
438
+ ? source.events.consumes.map((event) => normalizeSurfaceRemoteEvent(event, 'inbound'))
439
+ : [];
440
+ return {
441
+ schema: source.schema || 'xtend.rmt.vnext-remote-surface.v1',
442
+ surfaceId: id,
443
+ manifestId: String(source.manifestId || remote.manifestId || '').trim(),
444
+ name: String(source.name || id || remote.id || '').trim(),
445
+ type: String(source.surfaceType || source.type || input.type || 'window').trim() || 'window',
446
+ manager: String(source.manager || input.manager || options.managerId || '').trim(),
447
+ owner: normalizeSurfaceRemoteOwner(source.owner || input.owner || ''),
448
+ remote: {
449
+ id: String(remote.id || remote.remoteId || source.remoteId || '').trim(),
450
+ origin: normalizeSurfaceRemoteOrigin(remote.origin || source.origin || ''),
451
+ versionRange: String(remote.versionRange || remote.version || source.versionRange || source.version || '').trim(),
452
+ integrity: remote.integrity && typeof remote.integrity === 'object' ? { ...remote.integrity } : null
453
+ },
454
+ security: {
455
+ trustBoundary: String(security.trustBoundary || source.trustBoundary || '').trim(),
456
+ capabilityMode: String(security.capabilityMode || 'deny-by-default').trim() || 'deny-by-default',
457
+ sandboxRequired: security.sandboxRequired !== false,
458
+ cspRequired: security.cspRequired !== false
459
+ },
460
+ adapterBoundary: {
461
+ adapterId: String(adapterBoundary.adapterId || '').trim(),
462
+ capabilities: normalizeSurfaceRemoteCapabilityIds(adapterBoundary.capabilities),
463
+ hostOwned: adapterBoundary.hostOwned === true,
464
+ runtimeLoader: adapterBoundary.runtimeLoader === true
465
+ },
466
+ capabilities: normalizeSurfaceRemoteCapabilityIds(source.capabilities || input.remoteCapabilities || []),
467
+ shellBindings: bindings,
468
+ fallback,
469
+ runtime: {
470
+ kernelRemoteExecution: runtime.kernelRemoteExecution === true,
471
+ hostAdapterRequired: runtime.hostAdapterRequired !== false,
472
+ networkRequiredByKernel: runtime.networkRequiredByKernel === true
473
+ },
474
+ events: {
475
+ emits,
476
+ consumes
477
+ },
478
+ status: String(source.status || input.status || 'ready').trim() || 'ready',
479
+ sourceRecord: { ...source }
480
+ };
481
+ }
482
+
483
+ function clonePersistedSurfaceRecord(record) {
484
+ return {
485
+ schema: record.schema,
486
+ id: record.id,
487
+ manager: record.manager,
488
+ type: record.type,
489
+ label: record.label,
490
+ status: record.status,
491
+ active: Boolean(record.active),
492
+ minimized: Boolean(record.minimized),
493
+ maximized: Boolean(record.maximized),
494
+ pinned: Boolean(record.pinned),
495
+ collapsed: Boolean(record.collapsed),
496
+ modal: Boolean(record.modal),
497
+ placement: record.placement || null,
498
+ mode: record.mode || 'floating',
499
+ zIndex: Number(record.zIndex) || 0,
500
+ bounds: { ...(record.bounds || {}) },
501
+ previousBounds: record.previousBounds ? { ...record.previousBounds } : null,
502
+ capabilities: Array.isArray(record.capabilities) ? record.capabilities.slice() : [],
503
+ persistence: { ...(record.persistence || {}) },
504
+ contentRef: record.contentRef || null,
505
+ stateKey: record.stateKey || '',
506
+ metadataKeys: Array.isArray(record.metadataKeys) ? record.metadataKeys.slice() : [],
507
+ lifecycle: { ...(record.lifecycle || {}) }
508
+ };
509
+ }
510
+
511
+ function createPersistableSurfaceSnapshot(snapshot) {
512
+ return {
513
+ schema: 'xtend.surface.snapshot.v1',
514
+ managerId: snapshot.managerId,
515
+ stateKey: snapshot.stateKey,
516
+ activeSurfaceId: snapshot.activeSurfaceId || null,
517
+ version: Number(snapshot.version) || 0,
518
+ surfaceCount: Number(snapshot.surfaceCount) || 0,
519
+ openSurfaceCount: Number(snapshot.openSurfaceCount) || 0,
520
+ surfaces: Array.isArray(snapshot.surfaces) ? snapshot.surfaces.map(clonePersistedSurfaceRecord) : [],
521
+ stack: Array.isArray(snapshot.stack) ? snapshot.stack.slice() : [],
522
+ diagnostics: [],
523
+ updatedAt: snapshot.updatedAt || new Date().toISOString()
524
+ };
525
+ }
526
+
527
+ function migratePersistedSnapshotEnvelope(value) {
528
+ if (!value || typeof value !== 'object') return null;
529
+ if (value.schema === 'xtend.surface.snapshot.v1') {
530
+ return {
531
+ schema: SURFACE_PERSISTED_SNAPSHOT_SCHEMA,
532
+ version: 0,
533
+ migratedFrom: 'xtend.surface.snapshot.v1',
534
+ managerId: value.managerId,
535
+ restoreKey: '',
536
+ stateKey: value.stateKey,
537
+ persistedAt: value.updatedAt || new Date().toISOString(),
538
+ snapshot: value
539
+ };
540
+ }
541
+ if (value.schema !== SURFACE_PERSISTED_SNAPSHOT_SCHEMA || !value.snapshot) return null;
542
+ if (!Number.isFinite(Number(value.version))) {
543
+ return { ...value, version: 1, migratedFrom: value.schema };
544
+ }
545
+ return value;
546
+ }
547
+
548
+ class XSurfaceManager extends HTMLElement {
549
+ static get observedAttributes() {
550
+ return [
551
+ 'layout',
552
+ 'restore-key',
553
+ 'route-aware',
554
+ 'modal-policy',
555
+ 'manager-id',
556
+ 'state-key',
557
+ 'persistence-mode',
558
+ 'restore-policy',
559
+ 'surface-loading-policy',
560
+ 'surface-skeleton',
561
+ 'surface-hydration-timeout',
562
+ 'route-lifecycle-policy',
563
+ 'layout-engine',
564
+ 'surface-layout-gap',
565
+ 'surface-layout-snap',
566
+ 'remote-surface-policy',
567
+ 'remote-origin-allowlist',
568
+ 'remote-capabilities'
569
+ ];
570
+ }
571
+
572
+ static get xtendComponentContract() {
573
+ return {
574
+ schema: 'xtend.component.contract.v2',
575
+ tag: 'x-surface-manager',
576
+ maturity: 'experimental',
577
+ source: {
578
+ strategy: 'xtend.typescript.component-source-strategy.v1',
579
+ state: 'ts-source',
580
+ sourcePath: 'src/components/x-surface-manager/x-surface-manager.ts'
581
+ },
582
+ runtime: {
583
+ format: 'esm',
584
+ artifact: 'components/xsurfacemanager.js',
585
+ declaration: 'components/xsurfacemanager.d.ts',
586
+ localOnly: true,
587
+ cdnAllowed: false
588
+ },
589
+ rmt: {
590
+ adapter: 'xtend.component',
591
+ surfaceContract: 'xtend.surface.manager.v1',
592
+ overlayCompatibility: 'xtend.surface.overlay-stack-bridge.v1',
593
+ kernelBoundary: 'no-rmt-kernel-import-of-xtend-types'
594
+ },
595
+ fabric: {
596
+ api: '@xtend-fabric',
597
+ defaultLane: 'visible',
598
+ diagnosticsLane: 'diagnostics'
599
+ }
600
+ };
601
+ }
602
+
603
+ static get xtendRmtMetadata() {
604
+ return {
605
+ schema: 'xtend.rmt.component-contract.v1',
606
+ adapter: 'xtend.component',
607
+ tag: 'x-surface-manager',
608
+ componentRecordKind: 'custom_element',
609
+ templateMode: 'dom_descriptor',
610
+ eventBindingMode: 'dom-event-to-rmt-command',
611
+ schedules: [
612
+ 'surface.visible.render',
613
+ 'surface.user-blocking.open',
614
+ 'surface.user-blocking.close',
615
+ 'surface.transition.layout',
616
+ 'surface.diagnostics.snapshot',
617
+ 'surface.eager.hydrate',
618
+ 'surface.visible.hydrate',
619
+ 'surface.open.hydrate',
620
+ 'surface.idle.hydrate',
621
+ 'surface.route.hydrate',
622
+ 'surface.route.lifecycle',
623
+ 'surface.route.restore',
624
+ 'surface.route.cleanup',
625
+ 'surface.stack.policy',
626
+ 'surface.layout.engine',
627
+ 'surface.remote.policy',
628
+ 'surface.remote.degrade',
629
+ 'surface.remote.event-governance'
630
+ ],
631
+ hydration: { policy: 'visible', lane: 'visible' },
632
+ surface: {
633
+ schema: 'xtend.surface.manager.v1',
634
+ controller: 'xtend.surface.controller.v1',
635
+ overlayBridge: 'xtend.surface.overlay-stack-bridge.v1',
636
+ snapshot: 'xtend.surface.snapshot.v1',
637
+ persistence: SURFACE_MANAGER_PERSISTENCE_SCHEMA,
638
+ loading: SURFACE_LOADING_POLICY_SCHEMA,
639
+ routeLifecycle: SURFACE_ROUTE_LIFECYCLE_SCHEMA,
640
+ stackPolicy: SURFACE_STACK_POLICY_SCHEMA,
641
+ layoutEngine: SURFACE_LAYOUT_ENGINE_SCHEMA,
642
+ remotePolicy: SURFACE_REMOTE_POLICY_SCHEMA,
643
+ stateKey: 'xtend.surface.registry'
644
+ },
645
+ kernelBoundary: 'no-rmt-kernel-import-of-xtend-types'
646
+ };
647
+ }
648
+
649
+ static get xtendComponentLifecycleTelemetry() {
650
+ return {
651
+ schema: 'xtend.component.lifecycle-telemetry.v1',
652
+ componentRef: 'x-surface-manager',
653
+ operations: ['mount', 'hydrate', 'render', 'update', 'event', 'unmount'],
654
+ snapshotPath: 'snapshot.surfaceManager'
655
+ };
656
+ }
657
+
658
+ static get xtendScaffoldA11yProfile() {
659
+ return {
660
+ schema: 'xtend.a11y.profile.v1',
661
+ componentRef: 'x-surface-manager',
662
+ role: 'application',
663
+ accessibleName: 'required',
664
+ keyboard: ['surface-focus', 'delegated-window-keys'],
665
+ screenreader: {
666
+ signalContract: XSurfaceManager.xtendScreenreaderSignals
667
+ },
668
+ motionContrast: {
669
+ policy: XSurfaceManager.xtendMotionContrastPolicy
670
+ }
671
+ };
672
+ }
673
+
674
+ static get xtendScaffoldPerformanceProfile() {
675
+ return {
676
+ schema: 'xtend.performance.component-profile.v1',
677
+ componentRef: 'x-surface-manager',
678
+ budgetClass: 'interactive-shell',
679
+ lane: 'visible',
680
+ hydrationPolicy: 'visible',
681
+ criticalMeasurements: ['mount', 'register-surface', 'snapshot', 'surface-content-hydrate', 'surface-route-lifecycle', 'surface-stack-policy', 'surface-layout-engine', 'surface-remote-policy'],
682
+ cleanup: ['slotchange', 'surface-window-command', 'surface-panel-command', 'surface-overlay-command', 'route-lifecycle-listeners', 'stack-policy-listeners']
683
+ };
684
+ }
685
+
686
+ static get xtendScreenreaderSignals() {
687
+ return {
688
+ schema: 'xtend.a11y.screenreader-signals.v1',
689
+ componentRef: 'x-surface-manager',
690
+ liveRegion: 'polite',
691
+ signals: ['surface-opened', 'surface-closed', 'surface-focused', 'surface-layout-changed', 'surface-stack-policy-applied', 'surface-layout-engine-applied', 'remote-surface-degraded', 'remote-surface-refused'],
692
+ statusRegions: ['role=status', 'aria-live=polite'],
693
+ errorRegions: [],
694
+ fabric: {
695
+ lane: 'a11y',
696
+ fiberKind: 'a11y.surface',
697
+ scheduleRef: 'a11y.user-blocking.announce'
698
+ }
699
+ };
700
+ }
701
+
702
+ static get xtendMotionContrastPolicy() {
703
+ return {
704
+ schema: 'xtend.a11y.motion-contrast-policy.v1',
705
+ componentRef: 'x-surface-manager',
706
+ motion: {
707
+ schema: 'xtend.a11y.motion-policy.v1',
708
+ mediaQuery: '(prefers-reduced-motion: reduce)',
709
+ reducedMotion: 'required',
710
+ animationPolicy: 'delegated-surface-motion',
711
+ noMotionOnlyState: true
712
+ },
713
+ contrast: {
714
+ schema: 'xtend.a11y.contrast-policy.v1',
715
+ mediaQuery: '(forced-colors: active)',
716
+ highContrast: 'required',
717
+ forcedColorAdjust: 'auto',
718
+ focusVisible: 'required',
719
+ nonColorStatus: 'required'
720
+ }
721
+ };
722
+ }
723
+
724
+ constructor() {
725
+ super();
726
+ this._controller = null;
727
+ this._registeredElements = new Map();
728
+ this._syncingOverlayElements = new WeakSet();
729
+ this._restoringSnapshot = false;
730
+ this._snapshotPersistenceSuspended = false;
731
+ this._surfaceLoadingStates = new Map();
732
+ this._surfaceLoadingPromises = new Map();
733
+ this._surfaceRouteHydrationPending = new Set();
734
+ this._surfaceIdleHandles = new Map();
735
+ this._surfaceRouteLifecycleStates = new Map();
736
+ this._currentSurfaceRoute = null;
737
+ this._lastSurfaceRouteSignalKey = '';
738
+ this._surfaceRouteListenersAttached = false;
739
+ this._surfaceStackPolicyStates = new Map();
740
+ this._surfaceFocusRestoreTargets = new Map();
741
+ this._surfaceStackDocumentState = null;
742
+ this._activeStackModalSurfaceId = null;
743
+ this._stackPolicyListenersAttached = false;
744
+ this._surfaceLayoutStates = new Map();
745
+ this._surfaceLayoutApplying = false;
746
+ this._lastSurfaceLayoutReport = null;
747
+ this._surfaceRemotePolicyStates = new Map();
748
+ this._lastSurfaceRemotePolicyReport = null;
749
+ this._handleSlotChange = this._registerAssignedSurfaces.bind(this);
750
+ this._handleSurfaceCommand = this._onSurfaceCommand.bind(this);
751
+ this._handlePanelCommand = this._onSurfaceCommand.bind(this);
752
+ this._handleOverlayCommand = this._onSurfaceCommand.bind(this);
753
+ this._handleOverlayLifecycle = this._onOverlayLifecycle.bind(this);
754
+ this._handleSurfaceRouteSignal = this._onSurfaceRouteSignal.bind(this);
755
+ this._handleSurfaceStackKeyDown = this._onSurfaceStackKeyDown.bind(this);
756
+ this._handleSurfaceStackFocusIn = this._onSurfaceStackFocusIn.bind(this);
757
+ this.attachShadow({ mode: 'open' });
758
+ this.shadowRoot.innerHTML = `
759
+ <style>
760
+ :host {
761
+ display: block;
762
+ position: relative;
763
+ min-height: var(--surface-manager-min-height, 480px);
764
+ color: var(--surface-manager-color, #111827);
765
+ background: var(--surface-manager-bg, #f8fafc);
766
+ overflow: hidden;
767
+ isolation: isolate;
768
+ }
769
+ .root {
770
+ position: relative;
771
+ min-height: inherit;
772
+ width: 100%;
773
+ height: 100%;
774
+ }
775
+ .workspace,
776
+ .panels,
777
+ .overlays {
778
+ position: absolute;
779
+ inset: 0;
780
+ pointer-events: none;
781
+ }
782
+ .workspace ::slotted(*),
783
+ .panels ::slotted(*),
784
+ .overlays ::slotted(*) {
785
+ pointer-events: auto;
786
+ }
787
+ .status {
788
+ position: absolute;
789
+ width: 1px;
790
+ height: 1px;
791
+ overflow: hidden;
792
+ clip: rect(0 0 0 0);
793
+ clip-path: inset(50%);
794
+ white-space: nowrap;
795
+ }
796
+ @media (forced-colors: active) {
797
+ :host {
798
+ background: Canvas;
799
+ color: CanvasText;
800
+ }
801
+ }
802
+ </style>
803
+ <section class="root" part="root" role="application" aria-label="Surface workspace">
804
+ <div class="workspace" part="workspace"><slot name="windows"></slot></div>
805
+ <div class="panels" part="panels"><slot name="panels"></slot></div>
806
+ <div class="overlays" part="overlays"><slot name="overlays"></slot></div>
807
+ <slot></slot>
808
+ <span class="status" role="status" aria-live="polite"></span>
809
+ </section>
810
+ `;
811
+ this._slots = Array.from(this.shadowRoot.querySelectorAll('slot'));
812
+ this._status = this.shadowRoot.querySelector('.status');
813
+ }
814
+
815
+ connectedCallback() {
816
+ this._ensureController();
817
+ this._slots.forEach((slot) => slot.addEventListener('slotchange', this._handleSlotChange));
818
+ this.addEventListener('surface-window-command', this._handleSurfaceCommand);
819
+ this.addEventListener('surface-panel-command', this._handlePanelCommand);
820
+ this.addEventListener('surface-overlay-command', this._handleOverlayCommand);
821
+ this._addSurfaceRouteListeners();
822
+ this._addSurfaceStackPolicyListeners();
823
+ OVERLAY_LIFECYCLE_EVENTS.forEach((eventName) => {
824
+ this.addEventListener(eventName, this._handleOverlayLifecycle);
825
+ });
826
+ this._snapshotPersistenceSuspended = true;
827
+ this._registerAssignedSurfaces();
828
+ const restoreResult = this.restorePersistedSnapshot({ source: 'connected' });
829
+ this._snapshotPersistenceSuspended = false;
830
+ let snapshot = this._applySnapshot();
831
+ if (this._routeAware() && typeof xstate.get === 'function') {
832
+ const routeState = xstate.get('xtend.router.current') || xstate.get('router-current');
833
+ if (routeState) {
834
+ const routeResult = this.applyRouteLifecycle(routeState, { source: 'connected', force: true });
835
+ if (routeResult && routeResult.snapshot) snapshot = routeResult.snapshot;
836
+ }
837
+ }
838
+ if (!restoreResult.restored) this.persistSnapshot(snapshot, { reason: 'initial-connect' });
839
+ this._dispatchManagerEvent('surface-manager-ready', { result: restoreResult, snapshot });
840
+ }
841
+
842
+ disconnectedCallback() {
843
+ this._slots.forEach((slot) => slot.removeEventListener('slotchange', this._handleSlotChange));
844
+ this.removeEventListener('surface-window-command', this._handleSurfaceCommand);
845
+ this.removeEventListener('surface-panel-command', this._handlePanelCommand);
846
+ this.removeEventListener('surface-overlay-command', this._handleOverlayCommand);
847
+ this._removeSurfaceRouteListeners();
848
+ this._removeSurfaceStackPolicyListeners();
849
+ this._releaseSurfaceStackPolicy({ reason: 'disconnected' });
850
+ this._surfaceIdleHandles.forEach((handle) => clearSurfaceIdle(handle));
851
+ this._surfaceIdleHandles.clear();
852
+ OVERLAY_LIFECYCLE_EVENTS.forEach((eventName) => {
853
+ this.removeEventListener(eventName, this._handleOverlayLifecycle);
854
+ });
855
+ }
856
+
857
+ attributeChangedCallback(name, oldValue, newValue) {
858
+ if (oldValue === newValue || !this.isConnected) return;
859
+ if (name === 'manager-id' || name === 'state-key') {
860
+ this._controller = null;
861
+ this._registeredElements.clear();
862
+ this._ensureController();
863
+ this._registerAssignedSurfaces();
864
+ this.restorePersistedSnapshot({ source: 'manager-attribute-change' });
865
+ }
866
+ if (name === 'restore-key' || name === 'persistence-mode' || name === 'restore-policy') {
867
+ this.restorePersistedSnapshot({ source: 'persistence-attribute-change' });
868
+ }
869
+ if (name === 'surface-loading-policy' || name === 'surface-skeleton' || name === 'surface-hydration-timeout' || name === 'route-lifecycle-policy' || name === 'route-aware' || name === 'modal-policy' || name === 'layout' || name === 'layout-engine' || name === 'surface-layout-gap' || name === 'surface-layout-snap' || name === 'remote-surface-policy' || name === 'remote-origin-allowlist' || name === 'remote-capabilities') {
870
+ this._applySnapshot();
871
+ }
872
+ }
873
+
874
+ get surfaces() {
875
+ return this.snapshot().surfaces;
876
+ }
877
+
878
+ get activeSurfaceId() {
879
+ return this.snapshot().activeSurfaceId;
880
+ }
881
+
882
+ get layoutSnapshot() {
883
+ return this.snapshot();
884
+ }
885
+
886
+ get surfaceController() {
887
+ return this._ensureController();
888
+ }
889
+
890
+ get persistenceSnapshot() {
891
+ return this.snapshotPersistence();
892
+ }
893
+
894
+ get loadingSnapshot() {
895
+ return this.snapshotSurfaceLoading();
896
+ }
897
+
898
+ get routeLifecycleSnapshot() {
899
+ return this.snapshotRouteLifecycle();
900
+ }
901
+
902
+ get stackPolicySnapshot() {
903
+ return this.snapshotStackPolicy();
904
+ }
905
+
906
+ get layoutEngineSnapshot() {
907
+ return this.snapshotSurfaceLayout();
908
+ }
909
+
910
+ get remoteSurfacePolicySnapshot() {
911
+ return this.snapshotRemoteSurfacePolicy();
912
+ }
913
+
914
+ _managerId() {
915
+ return this.getAttribute('manager-id') || this.id || 'xtend.surface.manager';
916
+ }
917
+
918
+ _stateKey() {
919
+ return this.getAttribute('state-key') || 'xtend.surface.registry';
920
+ }
921
+
922
+ _restoreKey() {
923
+ return this.getAttribute('restore-key') || '';
924
+ }
925
+
926
+ _persistenceMode() {
927
+ return normalizePersistenceMode(this.getAttribute('persistence-mode'), this._restoreKey());
928
+ }
929
+
930
+ _restorePolicy() {
931
+ const policy = String(this.getAttribute('restore-policy') || '').trim();
932
+ return ['auto', 'manual', 'reset'].includes(policy) ? policy : 'auto';
933
+ }
934
+
935
+ _surfaceLoadingPolicy() {
936
+ return normalizeSurfaceLoadingPolicy(this.getAttribute('surface-loading-policy'), 'open');
937
+ }
938
+
939
+ _surfaceHydrationTimeout() {
940
+ return normalizeSurfaceLoadingTimeout(this.getAttribute('surface-hydration-timeout'));
941
+ }
942
+
943
+ _routeAware() {
944
+ if (!this.hasAttribute('route-aware')) return false;
945
+ const value = String(this.getAttribute('route-aware') || 'true').trim().toLowerCase();
946
+ return !['false', '0', 'no', 'off'].includes(value);
947
+ }
948
+
949
+ _routeLifecyclePolicy() {
950
+ return normalizeSurfaceRouteLifecyclePolicy(this.getAttribute('route-lifecycle-policy'), 'open-close');
951
+ }
952
+
953
+ _modalPolicy() {
954
+ return normalizeSurfaceModalPolicy(this.getAttribute('modal-policy'), 'topmost');
955
+ }
956
+
957
+ _layoutEngine() {
958
+ return normalizeSurfaceLayoutEngine(this.getAttribute('layout-engine') || this.getAttribute('layout'), 'freeform');
959
+ }
960
+
961
+ _layoutGap() {
962
+ return normalizeSurfaceLayoutNumber(this.getAttribute('surface-layout-gap'), 12, 0);
963
+ }
964
+
965
+ _layoutSnap() {
966
+ return normalizeSurfaceLayoutNumber(this.getAttribute('surface-layout-snap'), 8, 1);
967
+ }
968
+
969
+ _remoteSurfacePolicyMode() {
970
+ return normalizeSurfaceRemotePolicyMode(this.getAttribute('remote-surface-policy'), 'strict');
971
+ }
972
+
973
+ _remoteAllowedOrigins() {
974
+ return normalizeSurfaceRemoteList(
975
+ this.getAttribute('remote-origin-allowlist')
976
+ || this.getAttribute('remote-allowed-origins')
977
+ || ''
978
+ ).map(normalizeSurfaceRemoteOrigin).filter(Boolean);
979
+ }
980
+
981
+ _remoteAllowedCapabilities() {
982
+ const configured = normalizeSurfaceRemoteList(this.getAttribute('remote-capabilities'));
983
+ return configured.length > 0 ? configured : SURFACE_REMOTE_ALLOWED_CAPABILITIES.slice();
984
+ }
985
+
986
+ _surfaceSkeletonEnabled(element) {
987
+ const value = String(
988
+ element && (
989
+ element.getAttribute('data-surface-skeleton')
990
+ || element.getAttribute('data-xtend-surface-skeleton')
991
+ )
992
+ || this.getAttribute('surface-skeleton')
993
+ || 'true'
994
+ ).trim().toLowerCase();
995
+ return !['false', 'off', 'none', '0'].includes(value);
996
+ }
997
+
998
+ _persistenceStorageKey() {
999
+ const restoreKey = this._restoreKey();
1000
+ if (!restoreKey) return '';
1001
+ return `${SURFACE_PERSISTED_SNAPSHOT_SCHEMA}:${this._managerId()}:${restoreKey}`;
1002
+ }
1003
+
1004
+ _persistenceAdapter() {
1005
+ const mode = this._persistenceMode();
1006
+ if (mode === 'none') return null;
1007
+ if (mode === 'memory') return createMemoryStorageAdapter();
1008
+ return createWebStorageAdapter(mode);
1009
+ }
1010
+
1011
+ _createPersistenceDiagnostic(code, message, severity = 'info', detail = {}) {
1012
+ return {
1013
+ schema: SURFACE_PERSISTENCE_DIAGNOSTIC_SCHEMA,
1014
+ code,
1015
+ severity,
1016
+ managerId: this._managerId(),
1017
+ restoreKey: this._restoreKey(),
1018
+ mode: this._persistenceMode(),
1019
+ message,
1020
+ timestamp: new Date().toISOString(),
1021
+ detail
1022
+ };
1023
+ }
1024
+
1025
+ _dispatchPersistenceEvent(type, result) {
1026
+ this.dispatchEvent(new CustomEvent(type, {
1027
+ bubbles: true,
1028
+ composed: true,
1029
+ detail: {
1030
+ managerId: this._managerId(),
1031
+ persistence: this.snapshotPersistence({ includeStoredState: false }),
1032
+ result,
1033
+ snapshot: result && result.snapshot || this.snapshot()
1034
+ }
1035
+ }));
1036
+ }
1037
+
1038
+ _addSurfaceRouteListeners() {
1039
+ if (this._surfaceRouteListenersAttached) return;
1040
+ SURFACE_ROUTE_EVENT_NAMES.forEach((eventName) => {
1041
+ if (typeof globalThis.addEventListener === 'function') {
1042
+ globalThis.addEventListener(eventName, this._handleSurfaceRouteSignal);
1043
+ }
1044
+ if (globalThis.document && typeof globalThis.document.addEventListener === 'function') {
1045
+ globalThis.document.addEventListener(eventName, this._handleSurfaceRouteSignal);
1046
+ }
1047
+ });
1048
+ this._surfaceRouteListenersAttached = true;
1049
+ }
1050
+
1051
+ _removeSurfaceRouteListeners() {
1052
+ if (!this._surfaceRouteListenersAttached) return;
1053
+ SURFACE_ROUTE_EVENT_NAMES.forEach((eventName) => {
1054
+ if (typeof globalThis.removeEventListener === 'function') {
1055
+ globalThis.removeEventListener(eventName, this._handleSurfaceRouteSignal);
1056
+ }
1057
+ if (globalThis.document && typeof globalThis.document.removeEventListener === 'function') {
1058
+ globalThis.document.removeEventListener(eventName, this._handleSurfaceRouteSignal);
1059
+ }
1060
+ });
1061
+ this._surfaceRouteListenersAttached = false;
1062
+ }
1063
+
1064
+ _addSurfaceStackPolicyListeners() {
1065
+ if (this._stackPolicyListenersAttached || !globalThis.document) return;
1066
+ if (typeof globalThis.document.addEventListener === 'function') {
1067
+ globalThis.document.addEventListener('keydown', this._handleSurfaceStackKeyDown, true);
1068
+ globalThis.document.addEventListener('focusin', this._handleSurfaceStackFocusIn, true);
1069
+ }
1070
+ this._stackPolicyListenersAttached = true;
1071
+ }
1072
+
1073
+ _removeSurfaceStackPolicyListeners() {
1074
+ if (!this._stackPolicyListenersAttached || !globalThis.document) return;
1075
+ if (typeof globalThis.document.removeEventListener === 'function') {
1076
+ globalThis.document.removeEventListener('keydown', this._handleSurfaceStackKeyDown, true);
1077
+ globalThis.document.removeEventListener('focusin', this._handleSurfaceStackFocusIn, true);
1078
+ }
1079
+ this._stackPolicyListenersAttached = false;
1080
+ }
1081
+
1082
+ _createSurfaceLoadingDiagnostic(code, message, severity = 'info', detail = {}) {
1083
+ return {
1084
+ schema: SURFACE_LOADING_DIAGNOSTIC_SCHEMA,
1085
+ code,
1086
+ severity,
1087
+ managerId: this._managerId(),
1088
+ policy: this._surfaceLoadingPolicy(),
1089
+ timeoutMs: this._surfaceHydrationTimeout(),
1090
+ message,
1091
+ timestamp: new Date().toISOString(),
1092
+ detail
1093
+ };
1094
+ }
1095
+
1096
+ _createSurfaceRouteLifecycleDiagnostic(code, message, severity = 'info', detail = {}) {
1097
+ return {
1098
+ schema: SURFACE_ROUTE_LIFECYCLE_DIAGNOSTIC_SCHEMA,
1099
+ code,
1100
+ severity,
1101
+ managerId: this._managerId(),
1102
+ routeAware: this._routeAware(),
1103
+ policy: this._routeLifecyclePolicy(),
1104
+ message,
1105
+ timestamp: new Date().toISOString(),
1106
+ detail
1107
+ };
1108
+ }
1109
+
1110
+ _createSurfaceStackPolicyDiagnostic(code, message, severity = 'info', detail = {}) {
1111
+ return {
1112
+ schema: SURFACE_STACK_POLICY_DIAGNOSTIC_SCHEMA,
1113
+ code,
1114
+ severity,
1115
+ managerId: this._managerId(),
1116
+ modalPolicy: this._modalPolicy(),
1117
+ message,
1118
+ timestamp: new Date().toISOString(),
1119
+ detail
1120
+ };
1121
+ }
1122
+
1123
+ _createSurfaceLayoutEngineDiagnostic(code, message, severity = 'info', detail = {}) {
1124
+ return {
1125
+ schema: SURFACE_LAYOUT_ENGINE_DIAGNOSTIC_SCHEMA,
1126
+ code,
1127
+ severity,
1128
+ managerId: this._managerId(),
1129
+ engine: this._layoutEngine(),
1130
+ message,
1131
+ timestamp: new Date().toISOString(),
1132
+ detail
1133
+ };
1134
+ }
1135
+
1136
+ _createSurfaceRemotePolicyDiagnostic(code, message, severity = 'info', detail = {}) {
1137
+ return {
1138
+ schema: SURFACE_REMOTE_POLICY_DIAGNOSTIC_SCHEMA,
1139
+ code,
1140
+ severity,
1141
+ managerId: this._managerId(),
1142
+ policy: this._remoteSurfacePolicyMode(),
1143
+ trustBoundary: SURFACE_REMOTE_TRUST_BOUNDARY,
1144
+ message,
1145
+ timestamp: new Date().toISOString(),
1146
+ detail
1147
+ };
1148
+ }
1149
+
1150
+ _dispatchSurfaceLoadingEvent(type, result) {
1151
+ this.dispatchEvent(new CustomEvent(type, {
1152
+ bubbles: true,
1153
+ composed: true,
1154
+ detail: {
1155
+ managerId: this._managerId(),
1156
+ result,
1157
+ loading: this.snapshotSurfaceLoading(),
1158
+ snapshot: this.snapshot()
1159
+ }
1160
+ }));
1161
+ }
1162
+
1163
+ _dispatchSurfaceStackPolicyEvent(type, result) {
1164
+ this.dispatchEvent(new CustomEvent(type, {
1165
+ bubbles: true,
1166
+ composed: true,
1167
+ detail: {
1168
+ managerId: this._managerId(),
1169
+ result,
1170
+ stackPolicy: this.snapshotStackPolicy(),
1171
+ snapshot: result && result.snapshot || this.snapshot()
1172
+ }
1173
+ }));
1174
+ }
1175
+
1176
+ _dispatchSurfaceLayoutEngineEvent(type, result) {
1177
+ this.dispatchEvent(new CustomEvent(type, {
1178
+ bubbles: true,
1179
+ composed: true,
1180
+ detail: {
1181
+ managerId: this._managerId(),
1182
+ result,
1183
+ layout: this.snapshotSurfaceLayout(),
1184
+ snapshot: result && result.snapshot || this.snapshot()
1185
+ }
1186
+ }));
1187
+ }
1188
+
1189
+ _dispatchSurfaceRemotePolicyEvent(type, result) {
1190
+ this.dispatchEvent(new CustomEvent(type, {
1191
+ bubbles: true,
1192
+ composed: true,
1193
+ detail: {
1194
+ managerId: this._managerId(),
1195
+ result,
1196
+ remotePolicy: this.snapshotRemoteSurfacePolicy(),
1197
+ snapshot: result && result.snapshot || this.snapshot()
1198
+ }
1199
+ }));
1200
+ }
1201
+
1202
+ _dispatchSurfaceRouteLifecycleEvent(type, result) {
1203
+ this.dispatchEvent(new CustomEvent(type, {
1204
+ bubbles: true,
1205
+ composed: true,
1206
+ detail: {
1207
+ managerId: this._managerId(),
1208
+ result,
1209
+ routeLifecycle: this.snapshotRouteLifecycle(),
1210
+ snapshot: this.snapshot()
1211
+ }
1212
+ }));
1213
+ }
1214
+
1215
+ _createPersistedEnvelope(snapshot, reason = 'snapshot') {
1216
+ return {
1217
+ schema: SURFACE_PERSISTED_SNAPSHOT_SCHEMA,
1218
+ version: SURFACE_PERSISTENCE_VERSION,
1219
+ managerId: this._managerId(),
1220
+ restoreKey: this._restoreKey(),
1221
+ stateKey: this._stateKey(),
1222
+ mode: this._persistenceMode(),
1223
+ reason,
1224
+ persistedAt: new Date().toISOString(),
1225
+ snapshot: createPersistableSurfaceSnapshot(snapshot)
1226
+ };
1227
+ }
1228
+
1229
+ _validatePersistedEnvelope(envelope) {
1230
+ const migrated = migratePersistedSnapshotEnvelope(envelope);
1231
+ if (!migrated) {
1232
+ return {
1233
+ ok: false,
1234
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.invalid-snapshot', 'Persisted surface snapshot envelope is invalid.', 'warning')
1235
+ };
1236
+ }
1237
+ if (migrated.version > SURFACE_PERSISTENCE_VERSION) {
1238
+ return {
1239
+ ok: false,
1240
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.unsupported-version', 'Persisted surface snapshot version is newer than this runtime.', 'warning', {
1241
+ expectedVersion: SURFACE_PERSISTENCE_VERSION,
1242
+ actualVersion: migrated.version
1243
+ })
1244
+ };
1245
+ }
1246
+ if (migrated.managerId && migrated.managerId !== this._managerId()) {
1247
+ return {
1248
+ ok: false,
1249
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.manager-mismatch', 'Persisted surface snapshot belongs to another manager.', 'warning', {
1250
+ expectedManager: this._managerId(),
1251
+ actualManager: migrated.managerId
1252
+ })
1253
+ };
1254
+ }
1255
+ if (migrated.restoreKey && migrated.restoreKey !== this._restoreKey()) {
1256
+ return {
1257
+ ok: false,
1258
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.restore-key-mismatch', 'Persisted surface snapshot belongs to another restore-key.', 'warning', {
1259
+ expectedRestoreKey: this._restoreKey(),
1260
+ actualRestoreKey: migrated.restoreKey
1261
+ })
1262
+ };
1263
+ }
1264
+ if (!migrated.snapshot || migrated.snapshot.schema !== 'xtend.surface.snapshot.v1' || !Array.isArray(migrated.snapshot.surfaces)) {
1265
+ return {
1266
+ ok: false,
1267
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.invalid-snapshot', 'Persisted surface snapshot payload is invalid.', 'warning')
1268
+ };
1269
+ }
1270
+ return { ok: true, envelope: migrated, diagnostic: null };
1271
+ }
1272
+
1273
+ _readPersistedEnvelope() {
1274
+ const mode = this._persistenceMode();
1275
+ const key = this._persistenceStorageKey();
1276
+ if (mode === 'none' || !key) {
1277
+ return {
1278
+ ok: false,
1279
+ skipped: true,
1280
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.disabled', 'Surface persistence is disabled.', 'info')
1281
+ };
1282
+ }
1283
+ const adapter = this._persistenceAdapter();
1284
+ if (!adapter) {
1285
+ return {
1286
+ ok: false,
1287
+ skipped: true,
1288
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.storage-unavailable', 'Surface persistence storage is unavailable.', 'warning', { mode })
1289
+ };
1290
+ }
1291
+ try {
1292
+ const raw = adapter.getItem(key);
1293
+ if (!raw) {
1294
+ return {
1295
+ ok: false,
1296
+ skipped: true,
1297
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.empty', 'No persisted surface snapshot exists.', 'info', { key })
1298
+ };
1299
+ }
1300
+ const parsed = safeJsonParse(raw);
1301
+ const validation = this._validatePersistedEnvelope(parsed);
1302
+ return validation.ok
1303
+ ? { ok: true, envelope: validation.envelope, diagnostic: null }
1304
+ : { ok: false, skipped: true, diagnostic: validation.diagnostic };
1305
+ } catch (error) {
1306
+ return {
1307
+ ok: false,
1308
+ skipped: true,
1309
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.read-failed', 'Persisted surface snapshot could not be read.', 'warning', {
1310
+ key,
1311
+ error: error && error.message || String(error)
1312
+ })
1313
+ };
1314
+ }
1315
+ }
1316
+
1317
+ _ensureController() {
1318
+ if (this._controller) return this._controller;
1319
+ const api = surfaceControllerApi();
1320
+ if (!api || typeof api.createSurfaceController !== 'function') {
1321
+ throw new Error('x-surface-manager requires components/xsurfacemanager-controller.js');
1322
+ }
1323
+ this._controller = api.createSurfaceController({
1324
+ managerId: this._managerId(),
1325
+ stateKey: this._stateKey(),
1326
+ xstate,
1327
+ fabric: fabricBridge()
1328
+ });
1329
+ return this._controller;
1330
+ }
1331
+
1332
+ _resolveSurfaceElement(surfaceRef) {
1333
+ if (surfaceRef instanceof HTMLElement) return surfaceRef;
1334
+ const surfaceId = typeof surfaceRef === 'string'
1335
+ ? surfaceRef
1336
+ : (surfaceRef && (surfaceRef.id || surfaceRef.surfaceId));
1337
+ if (!surfaceId) return null;
1338
+ return this._registeredElements.get(surfaceId) || this.querySelector(surfaceElementSelector(surfaceId));
1339
+ }
1340
+
1341
+ _resolveSurfaceRecord(surfaceRef, element = null) {
1342
+ if (surfaceRef && typeof surfaceRef === 'object' && !(surfaceRef instanceof HTMLElement) && surfaceRef.id) {
1343
+ return surfaceRef;
1344
+ }
1345
+ const surfaceId = typeof surfaceRef === 'string'
1346
+ ? surfaceRef
1347
+ : (element && (element.getAttribute('surface-id') || element.id));
1348
+ if (!surfaceId) return null;
1349
+ return this.snapshot().surfaces.find((record) => record.id === surfaceId) || null;
1350
+ }
1351
+
1352
+ _resolveSurfaceLoadingPolicy(element, record = {}) {
1353
+ const policy = element && (
1354
+ element.getAttribute('data-surface-hydration-policy')
1355
+ || element.getAttribute('data-xtend-surface-loading-policy')
1356
+ || element.getAttribute('hydration-policy')
1357
+ );
1358
+ if (policy) return normalizeSurfaceLoadingPolicy(policy, this._surfaceLoadingPolicy());
1359
+ const content = element && typeof element.querySelector === 'function'
1360
+ ? element.querySelector('[data-surface-hydration-policy], [data-xtend-surface-loading-policy], [hydration-policy]')
1361
+ : null;
1362
+ if (content) {
1363
+ return normalizeSurfaceLoadingPolicy(
1364
+ content.getAttribute('data-surface-hydration-policy')
1365
+ || content.getAttribute('data-xtend-surface-loading-policy')
1366
+ || content.getAttribute('hydration-policy'),
1367
+ this._surfaceLoadingPolicy()
1368
+ );
1369
+ }
1370
+ const recordPolicy = record && record.lifecycle && record.lifecycle.hydrationPolicy
1371
+ || record && record.persistence && record.persistence.hydrationPolicy
1372
+ || record && record.hydrationPolicy;
1373
+ return normalizeSurfaceLoadingPolicy(recordPolicy, this._surfaceLoadingPolicy());
1374
+ }
1375
+
1376
+ _readSurfaceRouteContent(element) {
1377
+ if (!element || typeof element.querySelector !== 'function') return '';
1378
+ const content = element.querySelector('[data-surface-route], [data-rmt-route], [data-route-bound], [route-ref]');
1379
+ if (!content) return '';
1380
+ return content.getAttribute('data-surface-route')
1381
+ || content.getAttribute('data-rmt-route')
1382
+ || content.getAttribute('data-route-bound')
1383
+ || content.getAttribute('route-ref')
1384
+ || '';
1385
+ }
1386
+
1387
+ _resolveSurfaceRouteConfig(element, record = {}) {
1388
+ const surfaceId = record.id || element && (element.getAttribute('surface-id') || element.id) || '';
1389
+ const routeRef = element && (
1390
+ element.getAttribute('data-surface-route')
1391
+ || element.getAttribute('data-rmt-route')
1392
+ || element.getAttribute('route-ref')
1393
+ || element.getAttribute('data-route-bound')
1394
+ )
1395
+ || this._readSurfaceRouteContent(element)
1396
+ || record.route
1397
+ || record.routeRef
1398
+ || record.lifecycle && (record.lifecycle.route || record.lifecycle.routeRef)
1399
+ || '';
1400
+ const routeScope = element && (
1401
+ element.getAttribute('data-surface-route-scope')
1402
+ || element.getAttribute('route-scope')
1403
+ )
1404
+ || record.routeScope
1405
+ || record.lifecycle && record.lifecycle.routeScope
1406
+ || '';
1407
+ const explicitGlobal = surfaceBooleanAttribute(element, [
1408
+ 'data-surface-global',
1409
+ 'data-surface-route-global',
1410
+ 'data-surface-route-persistent'
1411
+ ]);
1412
+ const policyValue = element && (
1413
+ element.getAttribute('data-surface-route-policy')
1414
+ || element.getAttribute('route-policy')
1415
+ )
1416
+ || record.routePolicy
1417
+ || record.lifecycle && record.lifecycle.routePolicy
1418
+ || '';
1419
+ const policy = explicitGlobal || !routeRef
1420
+ ? 'global'
1421
+ : normalizeSurfaceRouteLifecyclePolicy(policyValue, this._routeLifecyclePolicy());
1422
+ const exact = surfaceBooleanAttribute(element, ['data-surface-route-exact', 'route-exact']);
1423
+ const normalizedRouteRef = normalizeSurfaceRouteToken(routeRef);
1424
+ const normalizedRouteScope = normalizeSurfaceRouteToken(routeScope);
1425
+ const existing = this._surfaceRouteLifecycleStates.get(surfaceId) || {};
1426
+ const config = {
1427
+ schema: SURFACE_ROUTE_LIFECYCLE_SCHEMA,
1428
+ surfaceId,
1429
+ routeRef: normalizedRouteRef,
1430
+ routeScope: normalizedRouteScope,
1431
+ policy,
1432
+ exact,
1433
+ global: policy === 'global',
1434
+ persistent: explicitGlobal || policy === 'global',
1435
+ matched: existing.matched === true,
1436
+ activeRoute: existing.activeRoute || null,
1437
+ lastAction: existing.lastAction || null,
1438
+ lastRoute: existing.lastRoute || null,
1439
+ diagnostic: existing.diagnostic || null
1440
+ };
1441
+ if (surfaceId) this._surfaceRouteLifecycleStates.set(surfaceId, config);
1442
+ return config;
1443
+ }
1444
+
1445
+ _normalizeRouteLifecycleInput(input = null) {
1446
+ const detail = input && input.detail && typeof input.detail === 'object'
1447
+ ? input.detail
1448
+ : (input && typeof input === 'object' && !input.type ? input : {});
1449
+ const rawPath = typeof input === 'string'
1450
+ ? input
1451
+ : (detail.path || detail.route || detail.href || detail.to || detail.url || '');
1452
+ const fallbackPath = globalThis.location
1453
+ ? (globalThis.location.hash || globalThis.location.pathname || '')
1454
+ : '';
1455
+ const path = rawPath || fallbackPath;
1456
+ const routeId = detail.routeId || detail.id || detail.name || null;
1457
+ const metadata = detail.metadata && typeof detail.metadata === 'object' ? detail.metadata : {};
1458
+ const routeScope = metadata.surfaceScope || metadata.routeScope || detail.routeScope || detail.scope || null;
1459
+ const tokens = new Set([
1460
+ ...surfaceRouteTokens(path),
1461
+ ...surfaceRouteTokens(routeId),
1462
+ ...surfaceRouteTokens(detail.component),
1463
+ ...surfaceRouteTokens(routeScope),
1464
+ ...surfaceRouteTokens(metadata.id),
1465
+ ...surfaceRouteTokens(metadata.route),
1466
+ ...surfaceRouteTokens(metadata.surfaceRoute)
1467
+ ]);
1468
+ return {
1469
+ schema: SURFACE_ROUTE_LIFECYCLE_SCHEMA,
1470
+ source: input && input.type || detail.source || 'manual',
1471
+ path,
1472
+ routeId,
1473
+ component: detail.component || null,
1474
+ metadata,
1475
+ mode: detail.mode || null,
1476
+ normalizedPath: normalizeSurfaceRouteToken(path),
1477
+ routeScope: normalizeSurfaceRouteToken(routeScope),
1478
+ tokens: Array.from(tokens).filter(Boolean),
1479
+ timestamp: new Date().toISOString()
1480
+ };
1481
+ }
1482
+
1483
+ _surfaceRouteMatches(config, route) {
1484
+ if (!config || config.global || !route) return false;
1485
+ const refs = [config.routeRef, config.routeScope].filter(Boolean);
1486
+ if (refs.length === 0) return false;
1487
+ const routeTokens = new Set(route.tokens || []);
1488
+ if (route.normalizedPath) routeTokens.add(route.normalizedPath);
1489
+ if (route.routeScope) routeTokens.add(route.routeScope);
1490
+ return refs.some((ref) => {
1491
+ if (ref === '*') return true;
1492
+ return Array.from(routeTokens).some((token) => (
1493
+ config.exact
1494
+ ? token === ref
1495
+ : token === ref || token.startsWith(`${ref}/`) || ref.startsWith(`${token}/`)
1496
+ ));
1497
+ });
1498
+ }
1499
+
1500
+ _recordRouteLifecycleState(surfaceId, patch = {}) {
1501
+ const state = this._surfaceRouteLifecycleStates.get(surfaceId) || {
1502
+ schema: SURFACE_ROUTE_LIFECYCLE_SCHEMA,
1503
+ surfaceId,
1504
+ policy: 'global',
1505
+ routeRef: '',
1506
+ routeScope: '',
1507
+ global: true,
1508
+ matched: false
1509
+ };
1510
+ Object.assign(state, patch);
1511
+ this._surfaceRouteLifecycleStates.set(surfaceId, state);
1512
+ return state;
1513
+ }
1514
+
1515
+ _ensureSurfaceLoadingState(surfaceId, element = null, record = null, policy = '') {
1516
+ const id = String(surfaceId || '').trim();
1517
+ if (!id) return null;
1518
+ const existing = this._surfaceLoadingStates.get(id) || {
1519
+ schema: SURFACE_LOADING_POLICY_SCHEMA,
1520
+ surfaceId: id,
1521
+ status: 'pending',
1522
+ policy: this._surfaceLoadingPolicy(),
1523
+ skeleton: false,
1524
+ hydrated: false,
1525
+ pendingRoute: false,
1526
+ tags: [],
1527
+ unresolvedTags: [],
1528
+ diagnostics: [],
1529
+ startedAt: null,
1530
+ hydratedAt: null,
1531
+ durationMs: 0
1532
+ };
1533
+ existing.policy = policy || existing.policy;
1534
+ existing.surfaceType = record && record.type || existing.surfaceType || null;
1535
+ existing.label = record && record.label || existing.label || id;
1536
+ existing.contentRef = record && record.contentRef || existing.contentRef || null;
1537
+ existing.elementTag = element && element.localName || existing.elementTag || null;
1538
+ this._surfaceLoadingStates.set(id, existing);
1539
+ return existing;
1540
+ }
1541
+
1542
+ _showSurfaceSkeleton(element, record = {}, options = {}) {
1543
+ if (!element || !this._surfaceSkeletonEnabled(element)) return null;
1544
+ const loader = surfaceLoaderApi();
1545
+ const policy = options.policy || this._resolveSurfaceLoadingPolicy(element, record);
1546
+ const surfaceId = record.id || element.getAttribute('surface-id') || element.id;
1547
+ const state = this._ensureSurfaceLoadingState(surfaceId, element, record, policy);
1548
+ const schedule = `surface.${policy}.hydrate`;
1549
+ const minHeight = element.getAttribute('data-surface-skeleton-min-height')
1550
+ || element.getAttribute('initial-height')
1551
+ || (record.bounds && record.bounds.height ? `${record.bounds.height}px` : '')
1552
+ || (record.type === 'side-panel' ? '16rem' : '14rem');
1553
+
1554
+ if (loader.ensureRuntimeStyles) loader.ensureRuntimeStyles({ source: 'x-surface-manager.surface-loading' });
1555
+
1556
+ if (!loader.showSkeleton) {
1557
+ const diagnostic = this._createSurfaceLoadingDiagnostic(
1558
+ 'xtend.surface.loading.skeleton-loader-missing',
1559
+ 'XTend SkeletonLoader is unavailable; surface content hydration is left to the host.',
1560
+ 'warning',
1561
+ { surfaceId, policy }
1562
+ );
1563
+ if (state) state.diagnostics.push(diagnostic);
1564
+ return null;
1565
+ }
1566
+
1567
+ element.setAttribute('data-xtend-surface-content-ready', 'false');
1568
+ element.setAttribute('data-xtend-surface-loading-policy', policy);
1569
+ element.setAttribute('data-xtend-surface-loading-schema', SURFACE_LOADING_POLICY_SCHEMA);
1570
+ element.setAttribute('aria-busy', 'true');
1571
+
1572
+ const skeleton = loader.showSkeleton(element, {
1573
+ source: 'x-surface-manager',
1574
+ schedule,
1575
+ label: `${record.label || surfaceId || 'Surface'} wird geladen`,
1576
+ minHeight,
1577
+ lines: record.type === 'side-panel' ? 5 : 6,
1578
+ variant: element.getAttribute('data-surface-skeleton-variant') || this.getAttribute('surface-skeleton') || 'block'
1579
+ });
1580
+ element.setAttribute('data-xtend-surface-skeleton', 'active');
1581
+ if (state) {
1582
+ state.status = state.status === 'hydrated' ? 'hydrated' : 'skeleton';
1583
+ state.skeleton = Boolean(skeleton);
1584
+ state.schedule = schedule;
1585
+ }
1586
+ return skeleton;
1587
+ }
1588
+
1589
+ _hideSurfaceSkeleton(element, options = {}) {
1590
+ if (!element) return 0;
1591
+ const loader = surfaceLoaderApi();
1592
+ const removed = loader.hideSkeleton ? loader.hideSkeleton(element, options) : 0;
1593
+ element.removeAttribute('data-xtend-surface-skeleton');
1594
+ element.removeAttribute('data-xtend-surface-loading-error');
1595
+ element.setAttribute('data-xtend-surface-content-ready', 'true');
1596
+ element.removeAttribute('aria-busy');
1597
+ return removed;
1598
+ }
1599
+
1600
+ _isSurfaceVisible(element, record = {}) {
1601
+ if (!element || !isSurfaceRecordOpen(record)) return false;
1602
+ if (typeof element.getClientRects === 'function' && element.getClientRects().length > 0) return true;
1603
+ return element.hasAttribute('open') || element.getAttribute('data-xtend-surface-content-ready') === 'false';
1604
+ }
1605
+
1606
+ _prepareSurfaceLoading(element, record = {}, options = {}) {
1607
+ if (!element || !record || !record.id || !this._surfaceSkeletonEnabled(element)) return null;
1608
+ const policy = this._resolveSurfaceLoadingPolicy(element, record);
1609
+ const state = this._ensureSurfaceLoadingState(record.id, element, record, policy);
1610
+ if (!state || state.hydrated === true || this._surfaceLoadingPromises.has(record.id)) return state;
1611
+ this._showSurfaceSkeleton(element, record, { policy, reason: options.reason || 'snapshot' });
1612
+ this._scheduleSurfaceHydration(element, record, policy, options);
1613
+ return state;
1614
+ }
1615
+
1616
+ _scheduleSurfaceHydration(element, record = {}, policy = 'open', options = {}) {
1617
+ if (!record.id || !element) return null;
1618
+ const state = this._ensureSurfaceLoadingState(record.id, element, record, policy);
1619
+ if (!state || state.hydrated === true || this._surfaceLoadingPromises.has(record.id)) return state;
1620
+
1621
+ const hydrate = (reason = `surface.${policy}.hydrate`) => {
1622
+ this.hydrateSurfaceContent(record.id, { ...options, policy, reason });
1623
+ };
1624
+
1625
+ if (policy === 'eager') {
1626
+ hydrate('surface.eager.hydrate');
1627
+ return state;
1628
+ }
1629
+
1630
+ if (policy === 'idle') {
1631
+ if (!this._surfaceIdleHandles.has(record.id)) {
1632
+ state.status = 'scheduled';
1633
+ const handle = scheduleSurfaceIdle(() => {
1634
+ this._surfaceIdleHandles.delete(record.id);
1635
+ hydrate('surface.idle.hydrate');
1636
+ });
1637
+ this._surfaceIdleHandles.set(record.id, handle);
1638
+ }
1639
+ return state;
1640
+ }
1641
+
1642
+ if (policy === 'route') {
1643
+ state.status = 'scheduled';
1644
+ state.pendingRoute = true;
1645
+ this._surfaceRouteHydrationPending.add(record.id);
1646
+ return state;
1647
+ }
1648
+
1649
+ if (policy === 'visible') {
1650
+ if (this._isSurfaceVisible(element, record)) {
1651
+ hydrate('surface.visible.hydrate');
1652
+ } else {
1653
+ state.status = 'scheduled';
1654
+ }
1655
+ return state;
1656
+ }
1657
+
1658
+ if (isSurfaceRecordOpen(record)) {
1659
+ hydrate('surface.open.hydrate');
1660
+ } else {
1661
+ state.status = 'scheduled';
1662
+ }
1663
+ return state;
1664
+ }
1665
+
1666
+ _registerAssignedSurfaces() {
1667
+ const surfaceElements = this._slots.flatMap((slot) => composedSurfaceElements(slot));
1668
+ surfaceElements.forEach((element) => this.registerSurface(element));
1669
+ }
1670
+
1671
+ registerSurface(surface) {
1672
+ const controller = this._ensureController();
1673
+ const element = surface instanceof HTMLElement ? surface : null;
1674
+ let record = surface;
1675
+ if (element && isSurfaceOverlayElement(element)) {
1676
+ record = toOverlaySurfaceRecord(element, this._managerId());
1677
+ } else if (element && typeof element.toSurfaceRecord === 'function') {
1678
+ record = element.toSurfaceRecord(this._managerId());
1679
+ }
1680
+ if (!element && isSurfaceRemoteInput(record)) {
1681
+ return this.registerRemoteSurface(record, { source: 'registerSurface' });
1682
+ }
1683
+ const result = controller.registerSurface(record);
1684
+
1685
+ let snapshot = null;
1686
+ if (element) {
1687
+ this._registeredElements.set(record.id, element);
1688
+ element.surfaceManager = this;
1689
+ this._prepareSurfaceLoading(element, record, { reason: 'registerSurface' });
1690
+ if (element.hasAttribute('open')) {
1691
+ this.openSurface(record.id);
1692
+ } else {
1693
+ snapshot = this._applySnapshot();
1694
+ }
1695
+ } else {
1696
+ snapshot = this._applySnapshot();
1697
+ }
1698
+
1699
+ if (snapshot) this.persistSnapshot(snapshot, { reason: 'registerSurface' });
1700
+ this._dispatchManagerEvent('surface-registered', { result, snapshot: snapshot || this.snapshot() });
1701
+ return result;
1702
+ }
1703
+
1704
+ openSurface(id, input) {
1705
+ return this._commit('openSurface', 'surface-opened', id, input);
1706
+ }
1707
+
1708
+ closeSurface(id, reason) {
1709
+ return this._commit('closeSurface', 'surface-closed', id, reason);
1710
+ }
1711
+
1712
+ focusSurface(id) {
1713
+ return this._commit('focusSurface', 'surface-focused', id);
1714
+ }
1715
+
1716
+ updateSurface(id, patch) {
1717
+ return this._commit('updateSurface', 'surface-updated', id, patch);
1718
+ }
1719
+
1720
+ moveSurface(id, bounds) {
1721
+ return this._commit('moveSurface', 'surface-layout-changed', id, bounds);
1722
+ }
1723
+
1724
+ resizeSurface(id, bounds) {
1725
+ return this._commit('resizeSurface', 'surface-layout-changed', id, bounds);
1726
+ }
1727
+
1728
+ minimizeSurface(id) {
1729
+ return this._commit('minimizeSurface', 'surface-layout-changed', id);
1730
+ }
1731
+
1732
+ maximizeSurface(id) {
1733
+ return this._commit('maximizeSurface', 'surface-layout-changed', id);
1734
+ }
1735
+
1736
+ restoreSurface(id) {
1737
+ return this._commit('restoreSurface', 'surface-layout-changed', id);
1738
+ }
1739
+
1740
+ pinSurface(id, pinned = true) {
1741
+ return this.updateSurface(id, { pinned: Boolean(pinned), mode: pinned ? 'pinned' : 'docked' });
1742
+ }
1743
+
1744
+ collapseSurface(id) {
1745
+ return this.updateSurface(id, { collapsed: true, mode: 'collapsed' });
1746
+ }
1747
+
1748
+ expandSurface(id, mode = 'docked') {
1749
+ return this.updateSurface(id, { collapsed: false, mode });
1750
+ }
1751
+
1752
+ dockSurface(id, placement = 'right', mode = 'docked') {
1753
+ const result = this.updateSurface(id, { placement, mode, collapsed: false, pinned: mode === 'pinned' });
1754
+ if (result && result.ok !== false) {
1755
+ this.applyLayoutEngine(this._layoutEngine() === 'freeform' ? 'docked' : this._layoutEngine(), { source: 'dockSurface', surfaceId: id });
1756
+ }
1757
+ return result;
1758
+ }
1759
+
1760
+ undockSurface(id, bounds = {}) {
1761
+ const fallbackBounds = bounds && typeof bounds === 'object' ? bounds : {};
1762
+ const result = this.updateSurface(id, {
1763
+ placement: '',
1764
+ mode: 'floating',
1765
+ collapsed: false,
1766
+ pinned: false,
1767
+ bounds: fallbackBounds
1768
+ });
1769
+ if (result && result.ok !== false) {
1770
+ this.applyLayoutEngine('freeform', { source: 'undockSurface', surfaceId: id, force: true });
1771
+ }
1772
+ return result;
1773
+ }
1774
+
1775
+ applyLayoutEngine(engine = this._layoutEngine(), options = {}) {
1776
+ const snapshot = this.snapshot();
1777
+ const layoutResult = this._applyLayoutEngineSnapshot(snapshot, {
1778
+ ...options,
1779
+ engine,
1780
+ source: options.source || 'manual',
1781
+ commit: true,
1782
+ force: true
1783
+ });
1784
+ const appliedSnapshot = this._applySnapshot({ skipLayoutEngine: true });
1785
+ const result = {
1786
+ ...layoutResult,
1787
+ snapshot: appliedSnapshot
1788
+ };
1789
+ this.persistSnapshot(appliedSnapshot, { reason: 'layout-engine' });
1790
+ this._dispatchSurfaceLayoutEngineEvent('surface-layout-engine-applied', result);
1791
+ return result;
1792
+ }
1793
+
1794
+ _lookupEnterpriseSurface(remoteRecord = {}, options = {}) {
1795
+ const registry = options.enterpriseRegistry || this.enterpriseSurfaceRegistry || globalThis.XTendEnterpriseSurfaceRegistry || globalThis.XTendSurfaceRegistry || null;
1796
+ if (!registry) return null;
1797
+ const keys = [
1798
+ remoteRecord.enterpriseSurfaceId,
1799
+ remoteRecord.surfaceId,
1800
+ remoteRecord.name,
1801
+ remoteRecord.manifestId,
1802
+ remoteRecord.remote && remoteRecord.remote.id
1803
+ ].filter(Boolean);
1804
+ if (typeof registry.lookup === 'function') {
1805
+ for (const key of keys) {
1806
+ const entry = registry.lookup(key);
1807
+ if (entry) return entry;
1808
+ }
1809
+ }
1810
+ if (typeof registry.get === 'function') {
1811
+ for (const key of keys) {
1812
+ const entry = registry.get(key);
1813
+ if (entry) return entry;
1814
+ }
1815
+ }
1816
+ const surfaces = Array.isArray(registry.surfaces)
1817
+ ? registry.surfaces
1818
+ : (Array.isArray(registry) ? registry : []);
1819
+ return surfaces.find((entry) => {
1820
+ const remote = entry && entry.remote || {};
1821
+ return keys.includes(entry && entry.enterpriseSurfaceId)
1822
+ || keys.includes(entry && entry.surfaceId)
1823
+ || keys.includes(entry && entry.name)
1824
+ || keys.includes(remote.manifestId)
1825
+ || keys.includes(remote.remoteId)
1826
+ || keys.includes(remote.id);
1827
+ }) || null;
1828
+ }
1829
+
1830
+ _lookupRemoteDegradation(remoteRecord = {}, options = {}) {
1831
+ const report = options.degradationReport || this.remoteDegradationReport || null;
1832
+ const surfaces = Array.isArray(report && report.surfaces) ? report.surfaces : [];
1833
+ const keys = [
1834
+ remoteRecord.enterpriseSurfaceId,
1835
+ remoteRecord.surfaceId,
1836
+ remoteRecord.name,
1837
+ remoteRecord.manifestId,
1838
+ remoteRecord.remote && remoteRecord.remote.id
1839
+ ].filter(Boolean);
1840
+ return surfaces.find((entry) => (
1841
+ keys.includes(entry.enterpriseSurfaceId)
1842
+ || keys.includes(entry.surfaceId)
1843
+ || keys.includes(entry.name)
1844
+ || keys.includes(entry.remoteId)
1845
+ )) || null;
1846
+ }
1847
+
1848
+ _mergeEnterpriseRemoteSurface(remoteRecord, enterpriseSurface) {
1849
+ if (!enterpriseSurface || typeof enterpriseSurface !== 'object') return remoteRecord;
1850
+ const remote = enterpriseSurface.remote || {};
1851
+ const version = enterpriseSurface.version || {};
1852
+ return {
1853
+ ...remoteRecord,
1854
+ enterpriseSurfaceId: enterpriseSurface.enterpriseSurfaceId || remoteRecord.enterpriseSurfaceId || null,
1855
+ owner: remoteRecord.owner && remoteRecord.owner.known ? remoteRecord.owner : normalizeSurfaceRemoteOwner(enterpriseSurface.owner),
1856
+ remote: {
1857
+ ...remoteRecord.remote,
1858
+ id: remoteRecord.remote.id || remote.remoteId || remote.id || '',
1859
+ origin: remoteRecord.remote.origin || normalizeSurfaceRemoteOrigin(remote.origin || ''),
1860
+ versionRange: remoteRecord.remote.versionRange || version.range || version.expected || version.active || '',
1861
+ integrity: remoteRecord.remote.integrity || remote.integrity || null
1862
+ },
1863
+ security: {
1864
+ ...remoteRecord.security,
1865
+ trustBoundary: remoteRecord.security.trustBoundary || remote.trustBoundary || ''
1866
+ },
1867
+ shellBindings: remoteRecord.shellBindings.length > 0
1868
+ ? remoteRecord.shellBindings
1869
+ : (Array.isArray(enterpriseSurface.shellTargets) ? enterpriseSurface.shellTargets.map(normalizeSurfaceRemoteBinding) : []),
1870
+ capabilities: remoteRecord.capabilities.length > 0
1871
+ ? remoteRecord.capabilities
1872
+ : normalizeSurfaceRemoteCapabilityIds(enterpriseSurface.capabilities),
1873
+ fallback: remoteRecord.fallback || enterpriseSurface.fallback || null,
1874
+ status: enterpriseSurface.status || remoteRecord.status
1875
+ };
1876
+ }
1877
+
1878
+ _createRemotePolicyDecision(surfaceInput = {}, options = {}) {
1879
+ const mode = normalizeSurfaceRemotePolicyMode(options.policy || this._remoteSurfacePolicyMode(), 'strict');
1880
+ let remoteRecord = normalizeSurfaceRemoteRecord(surfaceInput, {
1881
+ managerId: this._managerId()
1882
+ });
1883
+ const enterpriseSurface = this._lookupEnterpriseSurface(remoteRecord, options);
1884
+ remoteRecord = this._mergeEnterpriseRemoteSurface(remoteRecord, enterpriseSurface);
1885
+ const degradationSurface = this._lookupRemoteDegradation(remoteRecord, options);
1886
+ const allowedOrigins = normalizeSurfaceRemoteList(options.allowedOrigins || this._remoteAllowedOrigins())
1887
+ .map(normalizeSurfaceRemoteOrigin)
1888
+ .filter(Boolean);
1889
+ const allowedCapabilities = normalizeSurfaceRemoteCapabilityIds(options.allowedCapabilities || this._remoteAllowedCapabilities());
1890
+ const diagnostics = [];
1891
+ const pushDiagnostic = (code, message, severity = 'error', detail = {}) => {
1892
+ diagnostics.push(this._createSurfaceRemotePolicyDiagnostic(code, message, mode === 'audit' && severity === 'error' ? 'warning' : severity, {
1893
+ surfaceId: remoteRecord.surfaceId,
1894
+ manifestId: remoteRecord.manifestId,
1895
+ remoteId: remoteRecord.remote.id,
1896
+ ...detail
1897
+ }));
1898
+ };
1899
+
1900
+ if (mode === 'off') {
1901
+ pushDiagnostic('xtend.surface.remote-policy.disabled', 'Remote surface policy bridge is disabled by host policy.', 'warning');
1902
+ }
1903
+ if (!remoteRecord.surfaceId) {
1904
+ pushDiagnostic('xtend.surface.remote-policy.surface-id-missing', 'Remote surface records require a stable surface id.', 'error');
1905
+ }
1906
+ if (!remoteRecord.owner.known) {
1907
+ pushDiagnostic('xtend.surface.remote-policy.owner-missing', 'Remote surface records require an explicit owner.', 'error');
1908
+ }
1909
+ if (!remoteRecord.remote.id) {
1910
+ pushDiagnostic('xtend.surface.remote-policy.remote-id-missing', 'Remote surface records require a remote id.', 'error');
1911
+ }
1912
+ if (!remoteRecord.remote.versionRange) {
1913
+ pushDiagnostic('xtend.surface.remote-policy.version-missing', 'Remote surface records require a version or version range.', 'error');
1914
+ }
1915
+ if (!remoteRecord.remote.origin || !allowedOrigins.includes(remoteRecord.remote.origin)) {
1916
+ pushDiagnostic('xtend.surface.remote-policy.origin-not-allowed', 'Remote surface origin is not allowed by the host policy.', 'error', {
1917
+ origin: remoteRecord.remote.origin,
1918
+ allowedOrigins
1919
+ });
1920
+ }
1921
+
1922
+ const integrity = remoteRecord.remote.integrity || {};
1923
+ if (!integrity.algorithm || !integrity.digest || !SURFACE_REMOTE_INTEGRITY_ALGORITHMS.includes(integrity.algorithm)) {
1924
+ pushDiagnostic('xtend.surface.remote-policy.integrity-missing', 'Remote surface records require allowed manifest integrity.', 'error', {
1925
+ allowedAlgorithms: SURFACE_REMOTE_INTEGRITY_ALGORITHMS.slice()
1926
+ });
1927
+ }
1928
+ if (remoteRecord.security.trustBoundary !== SURFACE_REMOTE_TRUST_BOUNDARY) {
1929
+ pushDiagnostic('xtend.surface.remote-policy.trust-boundary-refused', 'Remote surface trust boundary is missing or unsupported.', 'error', {
1930
+ actualTrustBoundary: remoteRecord.security.trustBoundary,
1931
+ expectedTrustBoundary: SURFACE_REMOTE_TRUST_BOUNDARY
1932
+ });
1933
+ }
1934
+ if (remoteRecord.security.capabilityMode !== 'deny-by-default') {
1935
+ pushDiagnostic('xtend.surface.remote-policy.capability-mode-refused', 'Remote surface capabilities must use deny-by-default mode.', 'error', {
1936
+ capabilityMode: remoteRecord.security.capabilityMode
1937
+ });
1938
+ }
1939
+ if (!remoteRecord.security.sandboxRequired || !remoteRecord.security.cspRequired) {
1940
+ pushDiagnostic('xtend.surface.remote-policy.sandbox-required', 'Remote surface host policy requires sandbox and CSP controls.', 'error', {
1941
+ sandboxRequired: remoteRecord.security.sandboxRequired,
1942
+ cspRequired: remoteRecord.security.cspRequired
1943
+ });
1944
+ }
1945
+ if (!remoteRecord.adapterBoundary.hostOwned || remoteRecord.adapterBoundary.runtimeLoader) {
1946
+ pushDiagnostic('xtend.surface.remote-policy.adapter-boundary-refused', 'Remote surface adapter boundary must be host-owned and runtime-loader-free.', 'error', {
1947
+ adapterBoundary: remoteRecord.adapterBoundary
1948
+ });
1949
+ }
1950
+ if (remoteRecord.runtime.kernelRemoteExecution || remoteRecord.runtime.networkRequiredByKernel) {
1951
+ pushDiagnostic('xtend.surface.remote-policy.kernel-runtime-refused', 'Remote surface records must not require remote runtime execution in the RMT kernel.', 'error', {
1952
+ runtime: remoteRecord.runtime
1953
+ });
1954
+ }
1955
+
1956
+ const requiredCapabilities = remoteRecord.capabilities.filter(Boolean);
1957
+ const adapterCapabilities = remoteRecord.adapterBoundary.capabilities;
1958
+ const refusedCapabilities = requiredCapabilities.filter((capability) => (
1959
+ !allowedCapabilities.includes(capability) || !adapterCapabilities.includes(capability)
1960
+ ));
1961
+ if (refusedCapabilities.length > 0) {
1962
+ pushDiagnostic('xtend.surface.remote-policy.capability-refused', 'Remote surface capabilities exceed the host or adapter boundary.', 'error', {
1963
+ refusedCapabilities,
1964
+ allowedCapabilities,
1965
+ adapterCapabilities
1966
+ });
1967
+ }
1968
+ if (!requiredCapabilities.includes('surface.mount')) {
1969
+ pushDiagnostic('xtend.surface.remote-policy.mount-capability-missing', 'Remote surface records must explicitly request surface.mount.', 'error', {
1970
+ capabilities: requiredCapabilities
1971
+ });
1972
+ }
1973
+
1974
+ const events = remoteRecord.events.emits.concat(remoteRecord.events.consumes);
1975
+ events.forEach((eventRecord) => {
1976
+ const scopes = normalizeSurfaceRemoteList(eventRecord.scopes || eventRecord.lane);
1977
+ const hasGlobalScope = scopes.some((scope) => ['*', 'global', 'window', 'document'].includes(String(scope).trim().toLowerCase()));
1978
+ if (!eventRecord.event || !eventRecord.payload || !eventRecord.payload.schema) {
1979
+ pushDiagnostic('xtend.surface.remote-policy.event-payload-missing', 'Remote surface events require explicit payload schemas.', 'error', {
1980
+ event: eventRecord.event,
1981
+ direction: eventRecord.direction
1982
+ });
1983
+ }
1984
+ if (hasGlobalScope) {
1985
+ pushDiagnostic('xtend.surface.remote-policy.event-scope-refused', 'Remote surface events must not bind to an implicit global event bus.', 'error', {
1986
+ event: eventRecord.event,
1987
+ scopes
1988
+ });
1989
+ }
1990
+ });
1991
+
1992
+ if (degradationSurface && degradationSurface.state === 'blocked') {
1993
+ pushDiagnostic('xtend.surface.remote-policy.degradation-blocked', 'Remote surface is blocked by the degradation report.', 'error', {
1994
+ degradationState: degradationSurface.state
1995
+ });
1996
+ }
1997
+
1998
+ const hasErrors = diagnostics.some((diagnostic) => diagnostic.severity === 'error');
1999
+ const fallbackRef = remoteRecord.fallback && remoteRecord.fallback.ref || '';
2000
+ const decision = mode === 'off' || !hasErrors
2001
+ ? 'mounted'
2002
+ : (fallbackRef ? 'degraded' : 'refused');
2003
+ if (hasErrors && !fallbackRef) {
2004
+ pushDiagnostic('xtend.surface.remote-policy.fallback-missing', 'Remote surface policy violations require an explicit fallback surface.', 'error');
2005
+ }
2006
+
2007
+ return {
2008
+ schema: SURFACE_REMOTE_POLICY_SCHEMA,
2009
+ surfaceId: remoteRecord.surfaceId || null,
2010
+ remoteSurface: remoteRecord,
2011
+ decision,
2012
+ ok: decision !== 'refused',
2013
+ mounted: decision === 'mounted',
2014
+ degraded: decision === 'degraded',
2015
+ refused: decision === 'refused',
2016
+ policyMode: mode,
2017
+ trustBoundary: SURFACE_REMOTE_TRUST_BOUNDARY,
2018
+ ownerId: remoteRecord.owner.id || null,
2019
+ origin: remoteRecord.remote.origin || null,
2020
+ fallbackRef: fallbackRef || null,
2021
+ enterpriseSurfaceId: remoteRecord.enterpriseSurfaceId || null,
2022
+ enterpriseRegistryHit: Boolean(enterpriseSurface),
2023
+ degradationState: degradationSurface && degradationSurface.state || null,
2024
+ allowedOrigins,
2025
+ allowedCapabilities,
2026
+ diagnostics,
2027
+ kernelBoundary: {
2028
+ remoteRuntimeExecution: false,
2029
+ hostAdapterRequired: true,
2030
+ networkRequiredByKernel: false
2031
+ },
2032
+ createsSecondRegistry: false
2033
+ };
2034
+ }
2035
+
2036
+ _createRemoteSurfaceControllerRecord(decision) {
2037
+ const remoteRecord = decision.remoteSurface || {};
2038
+ const source = remoteRecord.sourceRecord || {};
2039
+ const binding = remoteRecord.shellBindings && remoteRecord.shellBindings[0] || null;
2040
+ const target = binding && binding.target || '';
2041
+ const inferredType = remoteRecord.type === 'remote'
2042
+ ? (target.includes('sidebar') || target.includes('panel') ? 'side-panel' : 'window')
2043
+ : remoteRecord.type;
2044
+ const supportedType = ['window', 'side-panel', 'modal', 'dialog', 'drawer', 'popover', 'tooltip'].includes(inferredType)
2045
+ ? inferredType
2046
+ : 'window';
2047
+ const fallbackRef = decision.fallbackRef || '';
2048
+ const contentRef = decision.degraded
2049
+ ? fallbackRef
2050
+ : (remoteRecord.remote && remoteRecord.remote.id || remoteRecord.name || remoteRecord.surfaceId);
2051
+ return {
2052
+ schema: 'xtend.surface.record.v1',
2053
+ id: remoteRecord.surfaceId,
2054
+ manager: this._managerId(),
2055
+ type: supportedType,
2056
+ label: source.label || remoteRecord.name || remoteRecord.surfaceId,
2057
+ stateKey: source.stateKey || `xtend.surface.${remoteRecord.surfaceId}.state`,
2058
+ defaultOpen: source.defaultOpen === true || source.open === true,
2059
+ open: source.defaultOpen === true || source.open === true,
2060
+ active: source.active === true,
2061
+ bounds: source.bounds || source.initialBounds || {},
2062
+ placement: source.placement || (supportedType === 'side-panel' ? 'right' : ''),
2063
+ mode: source.mode || (supportedType === 'side-panel' ? 'docked' : 'floating'),
2064
+ capabilities: ['open', 'focus', 'close', 'snapshot', 'resize', 'restore'],
2065
+ persistence: source.persistence || {},
2066
+ contentRef,
2067
+ route: source.route || source.routeRef || '',
2068
+ schedule: source.schedule || source.scheduleRef || '',
2069
+ metadata: {
2070
+ ...(source.metadata && typeof source.metadata === 'object' ? source.metadata : {}),
2071
+ remoteSurface: remoteRecord.sourceRecord || remoteRecord,
2072
+ remotePolicy: {
2073
+ schema: SURFACE_REMOTE_POLICY_SCHEMA,
2074
+ decision: decision.decision,
2075
+ policyMode: decision.policyMode,
2076
+ fallbackRef: decision.fallbackRef,
2077
+ trustBoundary: decision.trustBoundary,
2078
+ kernelRemoteExecution: false
2079
+ },
2080
+ remotePolicyDecision: decision.decision,
2081
+ rmtKernelRemoteExecution: false
2082
+ }
2083
+ };
2084
+ }
2085
+
2086
+ _applyRemoteSurfacePolicyDom(element, decision) {
2087
+ if (!element || !decision) return;
2088
+ element.setAttribute('data-surface-remote-policy-schema', SURFACE_REMOTE_POLICY_SCHEMA);
2089
+ element.setAttribute('data-surface-remote-decision', decision.decision);
2090
+ element.setAttribute('data-surface-remote-trust-boundary', decision.trustBoundary);
2091
+ element.setAttribute('data-surface-remote-kernel-runtime', 'false');
2092
+ element.setAttribute('data-surface-remote-owner', decision.ownerId || '');
2093
+ element.setAttribute('data-surface-remote-origin', decision.origin || '');
2094
+ element.toggleAttribute('data-surface-remote-degraded', decision.degraded === true);
2095
+ element.toggleAttribute('data-surface-remote-mounted', decision.mounted === true);
2096
+ }
2097
+
2098
+ evaluateRemoteSurfacePolicy(surfaceInput = {}, options = {}) {
2099
+ return this._createRemotePolicyDecision(surfaceInput, options);
2100
+ }
2101
+
2102
+ registerRemoteSurface(remoteSurface = {}, options = {}) {
2103
+ return this.applyRemoteSurfacePolicy(remoteSurface, {
2104
+ ...options,
2105
+ source: options.source || 'registerRemoteSurface',
2106
+ commit: true
2107
+ });
2108
+ }
2109
+
2110
+ applyRemoteSurfacePolicy(surfaceInput = {}, options = {}) {
2111
+ const decision = this._createRemotePolicyDecision(surfaceInput, options);
2112
+ const eventType = decision.refused
2113
+ ? 'remote-surface-refused'
2114
+ : (decision.degraded ? 'remote-surface-degraded' : 'remote-surface-mounted');
2115
+ let controllerResult = null;
2116
+ let snapshot = this.snapshot();
2117
+
2118
+ if (decision.ok && options.commit !== false) {
2119
+ const controller = this._ensureController();
2120
+ const controllerRecord = this._createRemoteSurfaceControllerRecord(decision);
2121
+ controllerResult = controller.registerSurface(controllerRecord);
2122
+ snapshot = this._applySnapshot();
2123
+ this.persistSnapshot(snapshot, { reason: decision.degraded ? 'remote-surface-degraded' : 'remote-surface-mounted' });
2124
+ this._dispatchManagerEvent('surface-registered', { result: controllerResult, snapshot });
2125
+ }
2126
+
2127
+ const result = {
2128
+ ...decision,
2129
+ schema: SURFACE_REMOTE_POLICY_REPORT_SCHEMA,
2130
+ operation: 'applyRemoteSurfacePolicy',
2131
+ source: options.source || 'manual',
2132
+ controllerResult,
2133
+ snapshot
2134
+ };
2135
+ if (decision.surfaceId) this._surfaceRemotePolicyStates.set(decision.surfaceId, result);
2136
+ this._lastSurfaceRemotePolicyReport = result;
2137
+ if (typeof xstate.set === 'function') {
2138
+ xstate.set('xtend.surface.remotePolicy', this.snapshotRemoteSurfacePolicy());
2139
+ }
2140
+ this._dispatchSurfaceRemotePolicyEvent(eventType, result);
2141
+ return result;
2142
+ }
2143
+
2144
+ governRemoteSurfaceEvent(eventInput = {}, payload = {}, options = {}) {
2145
+ const eventRecord = normalizeSurfaceRemoteEvent(eventInput, options.direction || '');
2146
+ const scopes = normalizeSurfaceRemoteList(eventRecord.scopes || eventRecord.lane);
2147
+ const diagnostics = [];
2148
+ const pushDiagnostic = (code, message, severity = 'error', detail = {}) => {
2149
+ diagnostics.push(this._createSurfaceRemotePolicyDiagnostic(code, message, severity, {
2150
+ event: eventRecord.event,
2151
+ direction: eventRecord.direction,
2152
+ ...detail
2153
+ }));
2154
+ };
2155
+ if (!eventRecord.event) {
2156
+ pushDiagnostic('xtend.surface.remote-policy.event-missing', 'Remote surface event governance requires an event name.');
2157
+ }
2158
+ if (!eventRecord.payload || !eventRecord.payload.schema) {
2159
+ pushDiagnostic('xtend.surface.remote-policy.event-payload-missing', 'Remote surface event governance requires a payload schema.');
2160
+ }
2161
+ if (scopes.some((scope) => ['*', 'global', 'window', 'document'].includes(String(scope).trim().toLowerCase()))) {
2162
+ pushDiagnostic('xtend.surface.remote-policy.event-scope-refused', 'Remote surface events must not use an implicit global event bus.', 'error', { scopes });
2163
+ }
2164
+ const governanceReport = options.eventGovernanceReport || this.remoteEventGovernanceReport || null;
2165
+ if (governanceReport && governanceReport.status === 'blocked') {
2166
+ pushDiagnostic('xtend.surface.remote-policy.event-governance-blocked', 'Remote surface event governance report is blocked.', 'error', {
2167
+ governanceStatus: governanceReport.status
2168
+ });
2169
+ }
2170
+ const ok = !diagnostics.some((diagnostic) => diagnostic.severity === 'error');
2171
+ const result = {
2172
+ schema: SURFACE_REMOTE_POLICY_REPORT_SCHEMA,
2173
+ policySchema: SURFACE_REMOTE_POLICY_SCHEMA,
2174
+ ok,
2175
+ governed: ok,
2176
+ refused: !ok,
2177
+ event: eventRecord.event,
2178
+ direction: eventRecord.direction,
2179
+ payloadSchema: eventRecord.payload && eventRecord.payload.schema || null,
2180
+ scopes,
2181
+ payload: payload && typeof payload === 'object' ? { ...payload } : {},
2182
+ diagnostics,
2183
+ implicitGlobalEventBus: false,
2184
+ runtimeDelivery: false,
2185
+ source: options.source || 'manual',
2186
+ snapshot: this.snapshot()
2187
+ };
2188
+ this._dispatchSurfaceRemotePolicyEvent(ok ? 'remote-surface-event-governed' : 'remote-surface-event-refused', result);
2189
+ return result;
2190
+ }
2191
+
2192
+ snapshotRemoteSurfacePolicy() {
2193
+ const surfaces = Array.from(this._surfaceRemotePolicyStates.values()).map((entry) => ({
2194
+ schema: SURFACE_REMOTE_POLICY_SCHEMA,
2195
+ surfaceId: entry.surfaceId,
2196
+ decision: entry.decision,
2197
+ mounted: entry.mounted === true,
2198
+ degraded: entry.degraded === true,
2199
+ refused: entry.refused === true,
2200
+ ownerId: entry.ownerId || null,
2201
+ origin: entry.origin || null,
2202
+ trustBoundary: entry.trustBoundary,
2203
+ fallbackRef: entry.fallbackRef || null,
2204
+ enterpriseSurfaceId: entry.enterpriseSurfaceId || null,
2205
+ enterpriseRegistryHit: entry.enterpriseRegistryHit === true,
2206
+ degradationState: entry.degradationState || null,
2207
+ diagnosticCount: Array.isArray(entry.diagnostics) ? entry.diagnostics.length : 0,
2208
+ kernelRemoteExecution: false
2209
+ }));
2210
+ const diagnostics = Array.from(this._surfaceRemotePolicyStates.values())
2211
+ .flatMap((entry) => Array.isArray(entry.diagnostics) ? entry.diagnostics : []);
2212
+ return {
2213
+ schema: SURFACE_REMOTE_POLICY_REPORT_SCHEMA,
2214
+ policySchema: SURFACE_REMOTE_POLICY_SCHEMA,
2215
+ diagnosticSchema: SURFACE_REMOTE_POLICY_DIAGNOSTIC_SCHEMA,
2216
+ managerId: this._managerId(),
2217
+ stateKey: this._stateKey(),
2218
+ policyMode: this._remoteSurfacePolicyMode(),
2219
+ trustBoundary: SURFACE_REMOTE_TRUST_BOUNDARY,
2220
+ allowedOrigins: this._remoteAllowedOrigins(),
2221
+ allowedCapabilities: this._remoteAllowedCapabilities(),
2222
+ surfaceCount: surfaces.length,
2223
+ mountedCount: surfaces.filter((surface) => surface.mounted).length,
2224
+ degradedCount: surfaces.filter((surface) => surface.degraded).length,
2225
+ refusedCount: surfaces.filter((surface) => surface.refused).length,
2226
+ decisions: SURFACE_REMOTE_DECISIONS.slice(),
2227
+ surfaces,
2228
+ diagnostics,
2229
+ hostDecisionBoundary: true,
2230
+ eventGovernance: true,
2231
+ rmtKernelRemoteExecution: false,
2232
+ createsSecondRegistry: false
2233
+ };
2234
+ }
2235
+
2236
+ snapshot() {
2237
+ return this._ensureController().snapshot();
2238
+ }
2239
+
2240
+ snapshotSurfaceLoading() {
2241
+ const snapshot = this.snapshot();
2242
+ const surfaces = snapshot.surfaces.map((record) => {
2243
+ const element = this._registeredElements.get(record.id) || this.querySelector(surfaceElementSelector(record.id));
2244
+ const policy = element ? this._resolveSurfaceLoadingPolicy(element, record) : this._surfaceLoadingPolicy();
2245
+ const state = this._ensureSurfaceLoadingState(record.id, element, record, policy);
2246
+ return {
2247
+ surfaceId: record.id,
2248
+ label: record.label,
2249
+ type: record.type,
2250
+ status: state.status,
2251
+ policy: state.policy,
2252
+ hydrated: state.hydrated === true,
2253
+ skeleton: state.skeleton === true,
2254
+ pendingRoute: state.pendingRoute === true,
2255
+ contentReady: element ? element.getAttribute('data-xtend-surface-content-ready') === 'true' : false,
2256
+ tags: Array.isArray(state.tags) ? state.tags.slice() : [],
2257
+ unresolvedTags: Array.isArray(state.unresolvedTags) ? state.unresolvedTags.slice() : [],
2258
+ durationMs: Number(state.durationMs) || 0,
2259
+ diagnosticCount: Array.isArray(state.diagnostics) ? state.diagnostics.length : 0
2260
+ };
2261
+ });
2262
+ return {
2263
+ schema: SURFACE_LOADING_REPORT_SCHEMA,
2264
+ policySchema: SURFACE_LOADING_POLICY_SCHEMA,
2265
+ managerId: this._managerId(),
2266
+ stateKey: this._stateKey(),
2267
+ defaultPolicy: this._surfaceLoadingPolicy(),
2268
+ timeoutMs: this._surfaceHydrationTimeout(),
2269
+ surfaceCount: surfaces.length,
2270
+ skeletonCount: surfaces.filter((surface) => surface.skeleton).length,
2271
+ hydratedCount: surfaces.filter((surface) => surface.hydrated).length,
2272
+ pendingCount: surfaces.filter((surface) => !surface.hydrated).length,
2273
+ routePendingCount: surfaces.filter((surface) => surface.pendingRoute).length,
2274
+ surfaces,
2275
+ shellFirst: true,
2276
+ protectsUnstyledContent: true,
2277
+ usesXTendLoader: Boolean(globalThis.XTendLoader),
2278
+ createsSecondRegistry: false
2279
+ };
2280
+ }
2281
+
2282
+ snapshotRouteLifecycle() {
2283
+ const snapshot = this.snapshot();
2284
+ const surfaces = snapshot.surfaces.map((record) => {
2285
+ const element = this._registeredElements.get(record.id) || this.querySelector(surfaceElementSelector(record.id));
2286
+ const config = this._resolveSurfaceRouteConfig(element, record);
2287
+ const state = this._surfaceRouteLifecycleStates.get(record.id) || config;
2288
+ return {
2289
+ surfaceId: record.id,
2290
+ label: record.label,
2291
+ type: record.type,
2292
+ status: record.status,
2293
+ routeRef: config.routeRef,
2294
+ routeScope: config.routeScope,
2295
+ policy: config.policy,
2296
+ global: config.global === true,
2297
+ persistent: config.persistent === true,
2298
+ matched: state.matched === true,
2299
+ activeRoute: state.activeRoute || null,
2300
+ lastRoute: state.lastRoute || null,
2301
+ lastAction: state.lastAction || null,
2302
+ diagnostic: state.diagnostic || null
2303
+ };
2304
+ });
2305
+ return {
2306
+ schema: SURFACE_ROUTE_LIFECYCLE_REPORT_SCHEMA,
2307
+ policySchema: SURFACE_ROUTE_LIFECYCLE_SCHEMA,
2308
+ managerId: this._managerId(),
2309
+ stateKey: this._stateKey(),
2310
+ routeAware: this._routeAware(),
2311
+ defaultPolicy: this._routeLifecyclePolicy(),
2312
+ currentRoute: this._currentSurfaceRoute,
2313
+ surfaceCount: surfaces.length,
2314
+ routeBoundCount: surfaces.filter((surface) => !surface.global).length,
2315
+ globalCount: surfaces.filter((surface) => surface.global).length,
2316
+ matchedCount: surfaces.filter((surface) => surface.matched).length,
2317
+ surfaces,
2318
+ controllerRemainsRegistryTruth: true,
2319
+ createsSecondRegistry: false,
2320
+ xrouterOwnsRouteState: true
2321
+ };
2322
+ }
2323
+
2324
+ _surfaceLayoutViewport() {
2325
+ const rect = typeof this.getBoundingClientRect === 'function' ? this.getBoundingClientRect() : null;
2326
+ const width = Math.round(
2327
+ rect && rect.width
2328
+ || this.clientWidth
2329
+ || this.offsetWidth
2330
+ || 1024
2331
+ );
2332
+ const height = Math.round(
2333
+ rect && rect.height
2334
+ || this.clientHeight
2335
+ || this.offsetHeight
2336
+ || 720
2337
+ );
2338
+ return {
2339
+ width: Math.max(320, width),
2340
+ height: Math.max(240, height),
2341
+ compact: width <= 720 || height <= 420
2342
+ };
2343
+ }
2344
+
2345
+ _isLayoutManagedSurface(record = {}) {
2346
+ return SURFACE_LAYOUT_SURFACE_TYPES.includes(record.type) && this._isSurfaceOpenForStack(record);
2347
+ }
2348
+
2349
+ _normalizeLayoutBounds(bounds = {}, viewport = this._surfaceLayoutViewport(), options = {}) {
2350
+ const gap = options.gap === undefined ? this._layoutGap() : options.gap;
2351
+ const snap = options.snap === undefined ? this._layoutSnap() : options.snap;
2352
+ const minWidth = Math.max(160, Number(bounds.minWidth) || 240);
2353
+ const minHeight = Math.max(120, Number(bounds.minHeight) || 160);
2354
+ const maxWidth = Math.max(minWidth, viewport.width - (gap * 2));
2355
+ const maxHeight = Math.max(minHeight, viewport.height - (gap * 2));
2356
+ const width = Math.min(maxWidth, Math.max(minWidth, Number(bounds.width) || minWidth));
2357
+ const height = Math.min(maxHeight, Math.max(minHeight, Number(bounds.height) || minHeight));
2358
+ const x = Math.min(Math.max(gap, snapSurfaceLayoutValue(bounds.x, snap)), Math.max(gap, viewport.width - width - gap));
2359
+ const y = Math.min(Math.max(gap, snapSurfaceLayoutValue(bounds.y, snap)), Math.max(gap, viewport.height - height - gap));
2360
+ return {
2361
+ x: Math.round(x),
2362
+ y: Math.round(y),
2363
+ width: Math.round(width),
2364
+ height: Math.round(height),
2365
+ minWidth,
2366
+ minHeight
2367
+ };
2368
+ }
2369
+
2370
+ _surfaceLayoutDockedRecords(records = []) {
2371
+ return records.filter((record) => {
2372
+ if (!this._isLayoutManagedSurface(record)) return false;
2373
+ const mode = String(record.mode || '').toLowerCase();
2374
+ const placement = normalizeSurfaceLayoutPlacement(record.placement, record.type === 'side-panel' ? 'right' : 'center');
2375
+ return record.type === 'side-panel' || ['docked', 'pinned', 'collapsed'].includes(mode) || ['left', 'right', 'top', 'bottom'].includes(placement);
2376
+ });
2377
+ }
2378
+
2379
+ _applyDockedSurfaceLayout(records, viewport, options = {}) {
2380
+ const gap = options.gap === undefined ? this._layoutGap() : options.gap;
2381
+ const compact = viewport.compact || options.compact === true;
2382
+ const area = { x: gap, y: gap, width: viewport.width - (gap * 2), height: viewport.height - (gap * 2) };
2383
+ const entries = [];
2384
+ const docked = compact ? [] : this._surfaceLayoutDockedRecords(records);
2385
+ const dockedIds = new Set(docked.map((record) => record.id));
2386
+
2387
+ docked.forEach((record) => {
2388
+ const placement = normalizeSurfaceLayoutPlacement(record.placement, record.type === 'side-panel' ? 'right' : 'center');
2389
+ const collapsed = record.collapsed || record.mode === 'collapsed';
2390
+ const width = Math.min(area.width, Math.max(collapsed ? 48 : 220, Number(record.bounds && record.bounds.width) || 320));
2391
+ const height = Math.min(area.height, Math.max(collapsed ? 48 : 180, Number(record.bounds && record.bounds.height) || 320));
2392
+ let bounds = null;
2393
+ if (placement === 'left') {
2394
+ bounds = { x: area.x, y: area.y, width, height: area.height };
2395
+ area.x += width + gap;
2396
+ area.width -= width + gap;
2397
+ } else if (placement === 'right' || placement === 'inline') {
2398
+ bounds = { x: area.x + area.width - width, y: area.y, width, height: area.height };
2399
+ area.width -= width + gap;
2400
+ } else if (placement === 'top') {
2401
+ bounds = { x: area.x, y: area.y, width: area.width, height };
2402
+ area.y += height + gap;
2403
+ area.height -= height + gap;
2404
+ } else if (placement === 'bottom') {
2405
+ bounds = { x: area.x, y: area.y + area.height - height, width: area.width, height };
2406
+ area.height -= height + gap;
2407
+ }
2408
+ if (bounds) {
2409
+ entries.push(this._createSurfaceLayoutEntry(record, 'docked', placement, bounds, {
2410
+ zone: `dock-${placement}`,
2411
+ mode: collapsed ? 'collapsed' : (record.mode || 'docked')
2412
+ }));
2413
+ }
2414
+ });
2415
+
2416
+ const mainRecords = records.filter((record) => this._isLayoutManagedSurface(record) && !dockedIds.has(record.id));
2417
+ const mainBounds = {
2418
+ x: area.x,
2419
+ y: area.y,
2420
+ width: Math.max(160, area.width),
2421
+ height: Math.max(120, area.height)
2422
+ };
2423
+ entries.push(...this._layoutRecordsInArea(mainRecords, mainBounds, compact ? 'stacked' : 'tile', {
2424
+ ...options,
2425
+ zone: compact ? 'compact-stack' : 'workspace'
2426
+ }));
2427
+ return entries;
2428
+ }
2429
+
2430
+ _layoutRecordsInArea(records = [], area = {}, engine = 'tile', options = {}) {
2431
+ const visible = records.filter((record) => this._isLayoutManagedSurface(record));
2432
+ if (visible.length === 0) return [];
2433
+ const gap = options.gap === undefined ? this._layoutGap() : options.gap;
2434
+ const bounds = {
2435
+ x: Math.round(area.x || gap),
2436
+ y: Math.round(area.y || gap),
2437
+ width: Math.max(160, Math.round(area.width || 640)),
2438
+ height: Math.max(120, Math.round(area.height || 420))
2439
+ };
2440
+
2441
+ if (engine === 'split') {
2442
+ const vertical = options.direction === 'vertical';
2443
+ return visible.map((record, index) => {
2444
+ const size = vertical
2445
+ ? Math.floor((bounds.height - gap * (visible.length - 1)) / visible.length)
2446
+ : Math.floor((bounds.width - gap * (visible.length - 1)) / visible.length);
2447
+ const entryBounds = vertical
2448
+ ? { x: bounds.x, y: bounds.y + index * (size + gap), width: bounds.width, height: size }
2449
+ : { x: bounds.x + index * (size + gap), y: bounds.y, width: size, height: bounds.height };
2450
+ return this._createSurfaceLayoutEntry(record, 'split', options.zone || 'split-pane', entryBounds, {
2451
+ zone: options.zone || 'split-pane',
2452
+ mode: record.mode === 'floating' ? 'floating' : 'docked'
2453
+ });
2454
+ });
2455
+ }
2456
+
2457
+ if (engine === 'stacked') {
2458
+ const offset = Math.max(16, gap * 2);
2459
+ return visible.map((record, index) => {
2460
+ const entryBounds = {
2461
+ x: bounds.x + index * offset,
2462
+ y: bounds.y + index * offset,
2463
+ width: Math.max(240, bounds.width - visible.length * offset),
2464
+ height: Math.max(180, bounds.height - visible.length * offset)
2465
+ };
2466
+ return this._createSurfaceLayoutEntry(record, 'stacked', options.zone || 'stack', entryBounds, {
2467
+ zone: options.zone || 'stack',
2468
+ mode: record.mode || 'floating'
2469
+ });
2470
+ });
2471
+ }
2472
+
2473
+ const columns = Math.max(1, Math.ceil(Math.sqrt(visible.length)));
2474
+ const rows = Math.max(1, Math.ceil(visible.length / columns));
2475
+ const cellWidth = Math.floor((bounds.width - gap * (columns - 1)) / columns);
2476
+ const cellHeight = Math.floor((bounds.height - gap * (rows - 1)) / rows);
2477
+ return visible.map((record, index) => {
2478
+ const column = index % columns;
2479
+ const row = Math.floor(index / columns);
2480
+ const entryBounds = {
2481
+ x: bounds.x + column * (cellWidth + gap),
2482
+ y: bounds.y + row * (cellHeight + gap),
2483
+ width: cellWidth,
2484
+ height: cellHeight
2485
+ };
2486
+ return this._createSurfaceLayoutEntry(record, 'tile', options.zone || 'tile-cell', entryBounds, {
2487
+ zone: options.zone || 'tile-cell',
2488
+ mode: record.mode === 'floating' ? 'floating' : 'docked'
2489
+ });
2490
+ });
2491
+ }
2492
+
2493
+ _createFreeformLayoutEntries(records, viewport, options = {}) {
2494
+ const occupied = [];
2495
+ return records
2496
+ .filter((record) => this._isLayoutManagedSurface(record))
2497
+ .map((record) => {
2498
+ let bounds = this._normalizeLayoutBounds(record.bounds || {}, viewport, options);
2499
+ let guard = 0;
2500
+ while (occupied.some((item) => Math.abs(item.x - bounds.x) < 12 && Math.abs(item.y - bounds.y) < 12) && guard < 8) {
2501
+ bounds = this._normalizeLayoutBounds({
2502
+ ...bounds,
2503
+ x: bounds.x + this._layoutSnap() * 2,
2504
+ y: bounds.y + this._layoutSnap() * 2
2505
+ }, viewport, options);
2506
+ guard += 1;
2507
+ }
2508
+ occupied.push(bounds);
2509
+ return this._createSurfaceLayoutEntry(record, 'freeform', 'floating', bounds, {
2510
+ zone: 'freeform',
2511
+ mode: record.mode || 'floating',
2512
+ collisionAdjusted: guard > 0
2513
+ });
2514
+ });
2515
+ }
2516
+
2517
+ _createSurfaceLayoutEntry(record, engine, placement, bounds, options = {}) {
2518
+ const viewport = options.viewport || this._surfaceLayoutViewport();
2519
+ const normalizedBounds = this._normalizeLayoutBounds({
2520
+ ...record.bounds,
2521
+ ...bounds
2522
+ }, viewport, options);
2523
+ const nextMode = options.mode || record.mode || (engine === 'freeform' ? 'floating' : 'docked');
2524
+ const nextPlacement = placement === 'floating' ? '' : normalizeSurfaceLayoutPlacement(placement, record.placement || 'center');
2525
+ const changed = !surfaceLayoutBoundsEqual(record.bounds || {}, normalizedBounds)
2526
+ || (nextMode && record.mode !== nextMode)
2527
+ || (nextPlacement !== undefined && String(record.placement || '') !== String(nextPlacement || ''));
2528
+ return {
2529
+ schema: SURFACE_LAYOUT_ENGINE_SCHEMA,
2530
+ surfaceId: record.id,
2531
+ type: record.type,
2532
+ status: record.status,
2533
+ engine,
2534
+ zone: options.zone || placement || 'workspace',
2535
+ placement: nextPlacement,
2536
+ mode: nextMode,
2537
+ bounds: normalizedBounds,
2538
+ changed,
2539
+ snapshotCompatible: true,
2540
+ responsiveFallback: options.responsiveFallback || null,
2541
+ collisionAdjusted: options.collisionAdjusted === true,
2542
+ viewportConstrained: !surfaceLayoutBoundsEqual(record.bounds || {}, normalizedBounds)
2543
+ };
2544
+ }
2545
+
2546
+ _createSurfaceLayoutModel(snapshot = this.snapshot(), options = {}) {
2547
+ const requestedEngine = normalizeSurfaceLayoutEngine(options.engine || this._layoutEngine(), 'freeform');
2548
+ const viewport = this._surfaceLayoutViewport();
2549
+ const compact = viewport.compact;
2550
+ const engine = compact && requestedEngine !== 'freeform' ? 'stacked' : requestedEngine;
2551
+ const records = this._stackOrderedRecords(snapshot);
2552
+ let surfaces = [];
2553
+ if (engine === 'docked') {
2554
+ surfaces = this._applyDockedSurfaceLayout(records, viewport, { ...options, compact });
2555
+ } else if (engine === 'split') {
2556
+ const workspace = { x: this._layoutGap(), y: this._layoutGap(), width: viewport.width - this._layoutGap() * 2, height: viewport.height - this._layoutGap() * 2 };
2557
+ surfaces = this._layoutRecordsInArea(records, workspace, 'split', { ...options, zone: 'split-pane' });
2558
+ } else if (engine === 'tile') {
2559
+ const workspace = { x: this._layoutGap(), y: this._layoutGap(), width: viewport.width - this._layoutGap() * 2, height: viewport.height - this._layoutGap() * 2 };
2560
+ surfaces = this._layoutRecordsInArea(records, workspace, 'tile', { ...options, zone: 'tile-cell' });
2561
+ } else if (engine === 'stacked') {
2562
+ const workspace = { x: this._layoutGap(), y: this._layoutGap(), width: viewport.width - this._layoutGap() * 2, height: viewport.height - this._layoutGap() * 2 };
2563
+ surfaces = this._layoutRecordsInArea(records, workspace, 'stacked', {
2564
+ ...options,
2565
+ zone: compact ? 'compact-stack' : 'stack',
2566
+ responsiveFallback: compact && requestedEngine !== 'stacked' ? requestedEngine : null
2567
+ });
2568
+ } else {
2569
+ surfaces = this._createFreeformLayoutEntries(records, viewport, options);
2570
+ }
2571
+ const diagnostics = [];
2572
+ if (compact && requestedEngine !== engine) {
2573
+ diagnostics.push(this._createSurfaceLayoutEngineDiagnostic(
2574
+ 'xtend.surface.layout-engine.responsive-fallback',
2575
+ 'Surface layout engine switched to stacked mode for a compact viewport.',
2576
+ 'info',
2577
+ { requestedEngine, engine, viewport }
2578
+ ));
2579
+ }
2580
+ return {
2581
+ schema: SURFACE_LAYOUT_ENGINE_REPORT_SCHEMA,
2582
+ policySchema: SURFACE_LAYOUT_ENGINE_SCHEMA,
2583
+ managerId: this._managerId(),
2584
+ stateKey: this._stateKey(),
2585
+ engine,
2586
+ requestedEngine,
2587
+ viewport,
2588
+ gap: this._layoutGap(),
2589
+ snap: this._layoutSnap(),
2590
+ surfaceCount: surfaces.length,
2591
+ changedCount: surfaces.filter((surface) => surface.changed).length,
2592
+ responsiveFallback: compact && requestedEngine !== engine,
2593
+ surfaces,
2594
+ diagnostics,
2595
+ snapshotCompatible: true,
2596
+ controllerRemainsRegistryTruth: true,
2597
+ createsSecondRegistry: false
2598
+ };
2599
+ }
2600
+
2601
+ _applyLayoutEntryToElement(element, entry) {
2602
+ if (!element || !entry) return;
2603
+ element.setAttribute('data-surface-layout-engine', entry.engine);
2604
+ element.setAttribute('data-surface-layout-zone', entry.zone);
2605
+ element.setAttribute('data-surface-layout-snapshot-compatible', 'true');
2606
+ element.style.setProperty('--surface-layout-x', `${entry.bounds.x}px`);
2607
+ element.style.setProperty('--surface-layout-y', `${entry.bounds.y}px`);
2608
+ element.style.setProperty('--surface-layout-width', `${entry.bounds.width}px`);
2609
+ element.style.setProperty('--surface-layout-height', `${entry.bounds.height}px`);
2610
+ }
2611
+
2612
+ _applySurfaceLayoutDom(report) {
2613
+ if (!report || !Array.isArray(report.surfaces)) return;
2614
+ report.surfaces.forEach((entry) => {
2615
+ const element = this._resolveStackElement(entry.surfaceId);
2616
+ this._applyLayoutEntryToElement(element, entry);
2617
+ });
2618
+ }
2619
+
2620
+ _applyLayoutEngineSnapshot(snapshot = this.snapshot(), options = {}) {
2621
+ if (this._surfaceLayoutApplying) {
2622
+ return this._lastSurfaceLayoutReport || this._createSurfaceLayoutModel(snapshot, options);
2623
+ }
2624
+ const engine = normalizeSurfaceLayoutEngine(options.engine || this._layoutEngine(), 'freeform');
2625
+ const shouldCommit = options.commit === true && (options.force === true || engine !== 'freeform' || this.hasAttribute('layout-engine'));
2626
+ const controller = this._ensureController();
2627
+ const report = this._createSurfaceLayoutModel(snapshot, { ...options, engine });
2628
+ this._surfaceLayoutApplying = true;
2629
+ try {
2630
+ if (shouldCommit) {
2631
+ report.surfaces.filter((entry) => entry.changed).forEach((entry) => {
2632
+ controller.updateSurface(entry.surfaceId, {
2633
+ bounds: entry.bounds,
2634
+ mode: entry.mode,
2635
+ placement: entry.placement,
2636
+ collapsed: entry.mode === 'collapsed',
2637
+ pinned: entry.mode === 'pinned'
2638
+ });
2639
+ });
2640
+ }
2641
+ } finally {
2642
+ this._surfaceLayoutApplying = false;
2643
+ }
2644
+ const nextSnapshot = shouldCommit && report.changedCount > 0 ? this.snapshot() : snapshot;
2645
+ const result = {
2646
+ ...report,
2647
+ ok: true,
2648
+ source: options.source || 'snapshot',
2649
+ committed: shouldCommit,
2650
+ snapshot: nextSnapshot
2651
+ };
2652
+ this._lastSurfaceLayoutReport = result;
2653
+ report.surfaces.forEach((entry) => this._surfaceLayoutStates.set(entry.surfaceId, entry));
2654
+ this._applySurfaceLayoutDom(result);
2655
+ if (typeof xstate.set === 'function') {
2656
+ xstate.set('xtend.surface.layoutEngine', this.snapshotSurfaceLayout());
2657
+ }
2658
+ return result;
2659
+ }
2660
+
2661
+ snapshotSurfaceLayout() {
2662
+ const snapshot = this.snapshot();
2663
+ const report = this._createSurfaceLayoutModel(snapshot, { engine: this._layoutEngine() });
2664
+ return {
2665
+ ...report,
2666
+ lastAppliedAt: this._lastSurfaceLayoutReport && this._lastSurfaceLayoutReport.source || null
2667
+ };
2668
+ }
2669
+
2670
+ _stackOrderedRecords(snapshot = this.snapshot()) {
2671
+ const surfaces = Array.isArray(snapshot && snapshot.surfaces) ? snapshot.surfaces : [];
2672
+ const byId = new Map(surfaces.map((record) => [record.id, record]));
2673
+ const orderedIds = Array.isArray(snapshot && snapshot.stack)
2674
+ ? snapshot.stack.filter((surfaceId) => byId.has(surfaceId))
2675
+ : [];
2676
+ const ordered = orderedIds.map((surfaceId) => byId.get(surfaceId));
2677
+ surfaces
2678
+ .filter((record) => !orderedIds.includes(record.id))
2679
+ .sort((left, right) => (Number(left.zIndex) || 0) - (Number(right.zIndex) || 0))
2680
+ .forEach((record) => ordered.push(record));
2681
+ return ordered;
2682
+ }
2683
+
2684
+ _isSurfaceOpenForStack(record = {}) {
2685
+ return record.status !== 'closed' && record.status !== 'minimized' && record.collapsed !== true;
2686
+ }
2687
+
2688
+ _recordWantsModal(record = {}, policy = this._modalPolicy()) {
2689
+ if (policy === 'none') return false;
2690
+ if (policy === 'all-modal') return this._isSurfaceOpenForStack(record);
2691
+ return Boolean(record.modal || record.type === 'modal' || record.type === 'dialog');
2692
+ }
2693
+
2694
+ _resolveStackElement(surfaceId) {
2695
+ return this._registeredElements.get(surfaceId) || this.querySelector(surfaceElementSelector(surfaceId));
2696
+ }
2697
+
2698
+ _createStackPolicyModel(snapshot = this.snapshot()) {
2699
+ const modalPolicy = this._modalPolicy();
2700
+ const orderedRecords = this._stackOrderedRecords(snapshot);
2701
+ const openRecords = orderedRecords.filter((record) => this._isSurfaceOpenForStack(record));
2702
+ const topmostRecord = openRecords[openRecords.length - 1] || null;
2703
+ const modalCandidates = modalPolicy === 'none'
2704
+ ? []
2705
+ : openRecords.filter((record) => this._recordWantsModal(record, modalPolicy));
2706
+ const activeModalRecord = modalPolicy === 'none'
2707
+ ? null
2708
+ : (modalPolicy === 'all-modal' ? topmostRecord : modalCandidates[modalCandidates.length - 1] || null);
2709
+ const activeModalSurfaceId = activeModalRecord && activeModalRecord.id || null;
2710
+ const closeableRecords = openRecords
2711
+ .slice()
2712
+ .reverse()
2713
+ .filter((record) => Array.isArray(record.capabilities) && record.capabilities.includes('close'));
2714
+ const escapeTargetRecord = activeModalRecord || closeableRecords[0] || topmostRecord || null;
2715
+ const maxStackZ = Math.max(0, ...orderedRecords.map((record) => Number(record.zIndex) || 0));
2716
+ const diagnostics = [];
2717
+
2718
+ if (activeModalRecord && topmostRecord && activeModalRecord.id !== topmostRecord.id) {
2719
+ diagnostics.push(this._createSurfaceStackPolicyDiagnostic(
2720
+ 'xtend.surface.stack-policy.modal-before-nonmodal',
2721
+ 'A modal surface is active below a non-modal surface; the manager promotes modal layer semantics without changing the controller registry.',
2722
+ 'info',
2723
+ {
2724
+ activeModalSurfaceId: activeModalRecord.id,
2725
+ topmostSurfaceId: topmostRecord.id
2726
+ }
2727
+ ));
2728
+ }
2729
+
2730
+ const surfaces = orderedRecords.map((record, index) => {
2731
+ const open = this._isSurfaceOpenForStack(record);
2732
+ const element = this._resolveStackElement(record.id);
2733
+ const wantsModal = this._recordWantsModal(record, modalPolicy);
2734
+ const activeModal = record.id === activeModalSurfaceId;
2735
+ const inert = Boolean(activeModalSurfaceId && open && !activeModal);
2736
+ const baseZIndex = Number(record.zIndex) || index + 1;
2737
+ const effectiveZIndex = activeModal ? Math.max(baseZIndex, maxStackZ + 2) : baseZIndex;
2738
+ const focusTarget = surfaceFocusableTarget(element);
2739
+ const missingLabel = open && wantsModal && !String(record.label || '').trim();
2740
+
2741
+ if (missingLabel) {
2742
+ diagnostics.push(this._createSurfaceStackPolicyDiagnostic(
2743
+ 'xtend.surface.stack-policy.missing-label',
2744
+ 'A modal surface is missing a stable label.',
2745
+ 'warning',
2746
+ { surfaceId: record.id, type: record.type }
2747
+ ));
2748
+ }
2749
+ if (activeModal && !focusTarget) {
2750
+ diagnostics.push(this._createSurfaceStackPolicyDiagnostic(
2751
+ 'xtend.surface.stack-policy.focus-target-missing',
2752
+ 'The active modal surface has no focusable target.',
2753
+ 'warning',
2754
+ { surfaceId: record.id, type: record.type }
2755
+ ));
2756
+ }
2757
+
2758
+ return {
2759
+ schema: SURFACE_STACK_POLICY_SCHEMA,
2760
+ surfaceId: record.id,
2761
+ label: record.label,
2762
+ type: record.type,
2763
+ status: record.status,
2764
+ open,
2765
+ modal: wantsModal,
2766
+ activeModal,
2767
+ inert,
2768
+ ariaHidden: inert || record.status === 'closed',
2769
+ ariaModal: activeModal,
2770
+ focusable: Boolean(focusTarget),
2771
+ escapeTarget: escapeTargetRecord && escapeTargetRecord.id === record.id,
2772
+ topmost: topmostRecord && topmostRecord.id === record.id,
2773
+ stackIndex: index,
2774
+ zIndex: effectiveZIndex,
2775
+ layerToken: activeModal ? 'surface.modal.active' : `surface.stack.${index + 1}`
2776
+ };
2777
+ });
2778
+
2779
+ return {
2780
+ modalPolicy,
2781
+ orderedRecords,
2782
+ openRecords,
2783
+ topmostRecord,
2784
+ activeModalRecord,
2785
+ escapeTargetRecord,
2786
+ surfaces,
2787
+ diagnostics
2788
+ };
2789
+ }
2790
+
2791
+ snapshotStackPolicy() {
2792
+ const snapshot = this.snapshot();
2793
+ const model = this._createStackPolicyModel(snapshot);
2794
+ return {
2795
+ schema: SURFACE_STACK_POLICY_REPORT_SCHEMA,
2796
+ policySchema: SURFACE_STACK_POLICY_SCHEMA,
2797
+ managerId: this._managerId(),
2798
+ stateKey: this._stateKey(),
2799
+ modalPolicy: model.modalPolicy,
2800
+ surfaceCount: model.surfaces.length,
2801
+ openSurfaceCount: model.openRecords.length,
2802
+ modalSurfaceCount: model.surfaces.filter((surface) => surface.modal && surface.open).length,
2803
+ inertSurfaceCount: model.surfaces.filter((surface) => surface.inert).length,
2804
+ topmostSurfaceId: model.topmostRecord && model.topmostRecord.id || null,
2805
+ activeModalSurfaceId: model.activeModalRecord && model.activeModalRecord.id || null,
2806
+ escapeTargetSurfaceId: model.escapeTargetRecord && model.escapeTargetRecord.id || null,
2807
+ scrollLocked: Boolean(this._surfaceStackDocumentState),
2808
+ focusRestoreTargetCount: this._surfaceFocusRestoreTargets.size,
2809
+ diagnostics: model.diagnostics,
2810
+ surfaces: model.surfaces,
2811
+ overlayCompatibilityPreserved: true,
2812
+ controllerRemainsRegistryTruth: true,
2813
+ createsSecondRegistry: false
2814
+ };
2815
+ }
2816
+
2817
+ applyStackPolicy(options = {}) {
2818
+ const snapshot = this.snapshot();
2819
+ return this._applyStackPolicy(snapshot, { ...options, source: options.source || 'manual' });
2820
+ }
2821
+
2822
+ _applyStackPolicy(snapshot = this.snapshot(), options = {}) {
2823
+ const model = this._createStackPolicyModel(snapshot);
2824
+ const previousModalSurfaceId = this._activeStackModalSurfaceId;
2825
+ const activeModalSurfaceId = model.activeModalRecord && model.activeModalRecord.id || null;
2826
+
2827
+ if (activeModalSurfaceId && previousModalSurfaceId !== activeModalSurfaceId) {
2828
+ this._captureStackFocusRestoreTarget(activeModalSurfaceId);
2829
+ }
2830
+
2831
+ model.surfaces.forEach((entry) => {
2832
+ const element = this._resolveStackElement(entry.surfaceId);
2833
+ if (!element) return;
2834
+ this._surfaceStackPolicyStates.set(entry.surfaceId, entry);
2835
+ this._applySurfaceStackEntry(element, entry);
2836
+ });
2837
+
2838
+ this._lockSurfaceScroll(Boolean(activeModalSurfaceId));
2839
+ this._activeStackModalSurfaceId = activeModalSurfaceId;
2840
+
2841
+ if (activeModalSurfaceId && options.focus !== false) {
2842
+ this._ensureStackFocusWithinSurface(activeModalSurfaceId, options);
2843
+ } else if (!activeModalSurfaceId && previousModalSurfaceId) {
2844
+ this._restoreStackFocus(previousModalSurfaceId);
2845
+ }
2846
+
2847
+ const report = {
2848
+ schema: SURFACE_STACK_POLICY_REPORT_SCHEMA,
2849
+ ok: true,
2850
+ source: options.source || 'snapshot',
2851
+ modalPolicy: model.modalPolicy,
2852
+ topmostSurfaceId: model.topmostRecord && model.topmostRecord.id || null,
2853
+ activeModalSurfaceId,
2854
+ escapeTargetSurfaceId: model.escapeTargetRecord && model.escapeTargetRecord.id || null,
2855
+ inertSurfaceCount: model.surfaces.filter((surface) => surface.inert).length,
2856
+ diagnostics: model.diagnostics,
2857
+ snapshot
2858
+ };
2859
+ if (typeof xstate.set === 'function') {
2860
+ xstate.set('xtend.surface.stackPolicy', this.snapshotStackPolicy());
2861
+ }
2862
+ if (options.dispatch !== false) {
2863
+ this._dispatchSurfaceStackPolicyEvent('surface-stack-policy-applied', report);
2864
+ }
2865
+ return report;
2866
+ }
2867
+
2868
+ _applySurfaceStackEntry(element, entry) {
2869
+ element.style.setProperty('--surface-layer-z', String(entry.zIndex));
2870
+ element.style.setProperty('--surface-stack-z', String(entry.zIndex));
2871
+ if (element.localName === 'x-surface-window') {
2872
+ element.style.setProperty('--surface-window-z', String(entry.zIndex));
2873
+ }
2874
+ if (element.localName === 'x-side-panel') {
2875
+ element.style.setProperty('--side-panel-z', String(entry.zIndex));
2876
+ }
2877
+ if (isSurfaceOverlayElement(element)) {
2878
+ element.style.setProperty('--surface-overlay-z', String(entry.zIndex));
2879
+ element.style.setProperty('--surface-overlay-backdrop-z', String(Math.max(1, entry.zIndex - 1)));
2880
+ }
2881
+
2882
+ element.setAttribute('data-surface-layer-token', entry.layerToken);
2883
+ element.setAttribute('data-surface-stack-index', String(entry.stackIndex));
2884
+ element.toggleAttribute('data-surface-stack-topmost', entry.topmost === true);
2885
+ element.toggleAttribute('data-surface-stack-escape-target', entry.escapeTarget === true);
2886
+ element.toggleAttribute('data-surface-modal-active', entry.activeModal === true);
2887
+ element.toggleAttribute('data-surface-focus-trap', entry.activeModal === true);
2888
+ this._setSurfaceAriaModal(element, entry.activeModal);
2889
+ this._setSurfaceInert(element, entry.inert);
2890
+ }
2891
+
2892
+ _setSurfaceAriaModal(element, modal) {
2893
+ if (!element) return;
2894
+ if (modal) {
2895
+ element.setAttribute('aria-modal', 'true');
2896
+ element.setAttribute('data-surface-aria-modal-by-manager', 'true');
2897
+ } else if (element.getAttribute('data-surface-aria-modal-by-manager') === 'true') {
2898
+ element.removeAttribute('aria-modal');
2899
+ element.removeAttribute('data-surface-aria-modal-by-manager');
2900
+ }
2901
+
2902
+ if (!element.shadowRoot || isSurfaceOverlayElement(element)) return;
2903
+ const surface = element.shadowRoot.querySelector('[part~="surface"]');
2904
+ if (!surface) return;
2905
+ surface.setAttribute('aria-modal', modal ? 'true' : 'false');
2906
+ surface.setAttribute('data-surface-aria-modal-by-manager', 'true');
2907
+ }
2908
+
2909
+ _setSurfaceInert(element, inert) {
2910
+ if (!element) return;
2911
+ if (inert) {
2912
+ element.setAttribute('data-surface-inert', 'manager');
2913
+ element.setAttribute('data-surface-aria-hidden-by-manager', 'true');
2914
+ element.setAttribute('aria-hidden', 'true');
2915
+ element.setAttribute('inert', '');
2916
+ try {
2917
+ element.inert = true;
2918
+ } catch (_error) {
2919
+ // Attribute fallback is enough for browsers without an inert property.
2920
+ }
2921
+ return;
2922
+ }
2923
+
2924
+ if (element.getAttribute('data-surface-inert') === 'manager') {
2925
+ element.removeAttribute('data-surface-inert');
2926
+ element.removeAttribute('inert');
2927
+ try {
2928
+ element.inert = false;
2929
+ } catch (_error) {
2930
+ // Attribute fallback already removed.
2931
+ }
2932
+ }
2933
+ if (element.getAttribute('data-surface-aria-hidden-by-manager') === 'true') {
2934
+ element.removeAttribute('aria-hidden');
2935
+ element.removeAttribute('data-surface-aria-hidden-by-manager');
2936
+ }
2937
+ }
2938
+
2939
+ _captureStackFocusRestoreTarget(surfaceId) {
2940
+ if (!globalThis.document) return null;
2941
+ const activeElement = globalThis.document.activeElement;
2942
+ const surfaceElement = this._resolveStackElement(surfaceId);
2943
+ if (
2944
+ activeElement
2945
+ && activeElement !== globalThis.document.body
2946
+ && activeElement !== globalThis.document.documentElement
2947
+ && !surfaceElementContainsTarget(surfaceElement, activeElement)
2948
+ && typeof activeElement.focus === 'function'
2949
+ ) {
2950
+ this._surfaceFocusRestoreTargets.set(surfaceId, activeElement);
2951
+ return activeElement;
2952
+ }
2953
+ return null;
2954
+ }
2955
+
2956
+ _ensureStackFocusWithinSurface(surfaceId, options = {}) {
2957
+ if (!globalThis.document) return false;
2958
+ const element = this._resolveStackElement(surfaceId);
2959
+ if (!element) return false;
2960
+ const activeElement = globalThis.document.activeElement;
2961
+ if (surfaceElementContainsTarget(element, activeElement)) return true;
2962
+ const focusTarget = surfaceFocusableTarget(element);
2963
+ if (!focusTarget) return false;
2964
+ queueMicrotask(() => {
2965
+ try {
2966
+ focusTarget.focus({ preventScroll: true });
2967
+ this._dispatchSurfaceStackPolicyEvent('surface-stack-policy-focus', {
2968
+ ok: true,
2969
+ surfaceId,
2970
+ source: options.source || 'stack-policy',
2971
+ snapshot: this.snapshot()
2972
+ });
2973
+ } catch (error) {
2974
+ this._dispatchSurfaceStackPolicyEvent('surface-stack-policy-error', {
2975
+ ok: false,
2976
+ surfaceId,
2977
+ diagnostic: this._createSurfaceStackPolicyDiagnostic(
2978
+ 'xtend.surface.stack-policy.focus-failed',
2979
+ 'The active modal surface could not receive focus.',
2980
+ 'warning',
2981
+ { surfaceId, error: error && error.message || String(error) }
2982
+ ),
2983
+ snapshot: this.snapshot()
2984
+ });
2985
+ }
2986
+ });
2987
+ return true;
2988
+ }
2989
+
2990
+ _restoreStackFocus(surfaceId) {
2991
+ const target = this._surfaceFocusRestoreTargets.get(surfaceId);
2992
+ this._surfaceFocusRestoreTargets.delete(surfaceId);
2993
+ if (!target || !target.isConnected || typeof target.focus !== 'function') return false;
2994
+ queueMicrotask(() => {
2995
+ try {
2996
+ target.focus({ preventScroll: true });
2997
+ this._dispatchSurfaceStackPolicyEvent('surface-stack-policy-focus-restored', {
2998
+ ok: true,
2999
+ surfaceId,
3000
+ snapshot: this.snapshot()
3001
+ });
3002
+ } catch (_error) {
3003
+ // Focus restore is best-effort; the stack report keeps the policy state authoritative.
3004
+ }
3005
+ });
3006
+ return true;
3007
+ }
3008
+
3009
+ _lockSurfaceScroll(lock) {
3010
+ const doc = globalThis.document;
3011
+ if (!doc || !doc.documentElement || !doc.body) return;
3012
+ if (lock && !this._surfaceStackDocumentState) {
3013
+ this._surfaceStackDocumentState = {
3014
+ bodyOverflow: doc.body.style.overflow,
3015
+ documentOverflow: doc.documentElement.style.overflow
3016
+ };
3017
+ doc.documentElement.setAttribute('data-xtend-surface-scroll-lock', 'true');
3018
+ doc.body.setAttribute('data-xtend-surface-scroll-lock', 'true');
3019
+ doc.documentElement.style.overflow = 'hidden';
3020
+ doc.body.style.overflow = 'hidden';
3021
+ return;
3022
+ }
3023
+ if (!lock && this._surfaceStackDocumentState) {
3024
+ doc.documentElement.style.overflow = this._surfaceStackDocumentState.documentOverflow || '';
3025
+ doc.body.style.overflow = this._surfaceStackDocumentState.bodyOverflow || '';
3026
+ doc.documentElement.removeAttribute('data-xtend-surface-scroll-lock');
3027
+ doc.body.removeAttribute('data-xtend-surface-scroll-lock');
3028
+ this._surfaceStackDocumentState = null;
3029
+ }
3030
+ }
3031
+
3032
+ _releaseSurfaceStackPolicy() {
3033
+ const elements = new Set([
3034
+ ...this._registeredElements.values(),
3035
+ ...Array.from(this.querySelectorAll ? this.querySelectorAll(SURFACE_MANAGED_ELEMENT_SELECTOR) : [])
3036
+ ]);
3037
+ elements.forEach((element) => {
3038
+ this._setSurfaceInert(element, false);
3039
+ element.removeAttribute('data-surface-layer-token');
3040
+ element.removeAttribute('data-surface-stack-index');
3041
+ element.removeAttribute('data-surface-stack-topmost');
3042
+ element.removeAttribute('data-surface-stack-escape-target');
3043
+ element.removeAttribute('data-surface-modal-active');
3044
+ element.removeAttribute('data-surface-focus-trap');
3045
+ if (element.getAttribute('data-surface-aria-modal-by-manager') === 'true') {
3046
+ element.removeAttribute('aria-modal');
3047
+ element.removeAttribute('data-surface-aria-modal-by-manager');
3048
+ }
3049
+ });
3050
+ this._lockSurfaceScroll(false);
3051
+ this._surfaceStackPolicyStates.clear();
3052
+ this._activeStackModalSurfaceId = null;
3053
+ }
3054
+
3055
+ applyRouteLifecycle(routeInput = null, options = {}) {
3056
+ if (!this._routeAware() && options.force !== true) {
3057
+ const diagnostic = this._createSurfaceRouteLifecycleDiagnostic(
3058
+ 'xtend.surface.route-lifecycle.disabled',
3059
+ 'Surface route lifecycle is disabled because route-aware is not enabled.',
3060
+ 'info'
3061
+ );
3062
+ const result = { ok: false, skipped: true, diagnostic, route: this._normalizeRouteLifecycleInput(routeInput), actions: [] };
3063
+ this._dispatchSurfaceRouteLifecycleEvent('surface-route-lifecycle-skipped', result);
3064
+ return result;
3065
+ }
3066
+
3067
+ const route = this._normalizeRouteLifecycleInput(routeInput);
3068
+ this._currentSurfaceRoute = route;
3069
+ const before = this.snapshot();
3070
+ const actions = [];
3071
+ let matchedCount = 0;
3072
+ let globalCount = 0;
3073
+
3074
+ before.surfaces.forEach((record) => {
3075
+ const element = this._registeredElements.get(record.id) || this.querySelector(surfaceElementSelector(record.id));
3076
+ const config = this._resolveSurfaceRouteConfig(element, record);
3077
+ if (config.global) {
3078
+ globalCount += 1;
3079
+ this._recordRouteLifecycleState(record.id, {
3080
+ ...config,
3081
+ matched: false,
3082
+ activeRoute: null,
3083
+ lastRoute: route.path,
3084
+ lastAction: 'global-keep'
3085
+ });
3086
+ actions.push({ surfaceId: record.id, policy: config.policy, action: 'global-keep', matched: false, ok: true });
3087
+ return;
3088
+ }
3089
+
3090
+ const matched = this._surfaceRouteMatches(config, route);
3091
+ if (matched) matchedCount += 1;
3092
+ const action = matched
3093
+ ? this._applyMatchedSurfaceRouteLifecycle(record, config, route, options)
3094
+ : this._applyUnmatchedSurfaceRouteLifecycle(record, config, route, options);
3095
+ this._recordRouteLifecycleState(record.id, {
3096
+ ...config,
3097
+ matched,
3098
+ activeRoute: matched ? route.path : null,
3099
+ lastRoute: route.path,
3100
+ lastAction: action.action,
3101
+ diagnostic: action.diagnostic || null
3102
+ });
3103
+ actions.push(action);
3104
+ });
3105
+
3106
+ const snapshot = this._applySnapshot();
3107
+ this.persistSnapshot(snapshot, { reason: 'route-lifecycle' });
3108
+ const result = {
3109
+ schema: SURFACE_ROUTE_LIFECYCLE_REPORT_SCHEMA,
3110
+ ok: true,
3111
+ skipped: false,
3112
+ route,
3113
+ matchedCount,
3114
+ globalCount,
3115
+ actionCount: actions.length,
3116
+ actions,
3117
+ snapshot
3118
+ };
3119
+ if (typeof xstate.set === 'function') {
3120
+ xstate.set('xtend.surface.routeLifecycle', this.snapshotRouteLifecycle());
3121
+ }
3122
+ this._dispatchSurfaceRouteLifecycleEvent('surface-route-lifecycle-applied', result);
3123
+ return result;
3124
+ }
3125
+
3126
+ _applyMatchedSurfaceRouteLifecycle(record, config, route, options = {}) {
3127
+ if (config.policy === 'manual') return { surfaceId: record.id, policy: config.policy, action: 'manual-skip', matched: true, ok: true };
3128
+ if (config.policy === 'hydrate-only') {
3129
+ this.hydrateSurfaceContent(record.id, { policy: 'route', reason: 'surface.route.lifecycle', timeoutMs: options.timeoutMs });
3130
+ return { surfaceId: record.id, policy: config.policy, action: 'route-hydrate', matched: true, ok: true };
3131
+ }
3132
+
3133
+ let result = null;
3134
+ let action = 'route-keep-open';
3135
+ if (record.status === 'closed') {
3136
+ result = this.openSurface(record.id, { source: 'route-lifecycle', route: route.path });
3137
+ action = 'route-open';
3138
+ } else if (record.status === 'minimized' || record.minimized || record.maximized) {
3139
+ result = this.restoreSurface(record.id);
3140
+ action = 'route-restore';
3141
+ } else if (record.collapsed) {
3142
+ result = this.expandSurface(record.id, record.pinned ? 'pinned' : (record.mode === 'collapsed' ? 'docked' : record.mode));
3143
+ action = 'route-expand';
3144
+ }
3145
+
3146
+ this.hydrateSurfaceContent(record.id, { policy: 'route', reason: 'surface.route.lifecycle', timeoutMs: options.timeoutMs });
3147
+ return {
3148
+ surfaceId: record.id,
3149
+ policy: config.policy,
3150
+ action,
3151
+ matched: true,
3152
+ ok: result ? result.ok !== false : true,
3153
+ result: result || null
3154
+ };
3155
+ }
3156
+
3157
+ _applyUnmatchedSurfaceRouteLifecycle(record, config, route) {
3158
+ if (config.policy === 'manual') return { surfaceId: record.id, policy: config.policy, action: 'manual-skip', matched: false, ok: true };
3159
+ if (config.policy === 'open-keep' || config.policy === 'hydrate-only') {
3160
+ return { surfaceId: record.id, policy: config.policy, action: 'route-keep', matched: false, ok: true };
3161
+ }
3162
+ if (record.status === 'closed') {
3163
+ return { surfaceId: record.id, policy: config.policy, action: 'route-already-closed', matched: false, ok: true };
3164
+ }
3165
+
3166
+ let result = null;
3167
+ let action = 'route-keep';
3168
+ if (config.policy === 'open-collapse') {
3169
+ if (record.type === 'side-panel' || record.type === 'drawer') {
3170
+ result = this.collapseSurface(record.id);
3171
+ action = 'route-collapse';
3172
+ } else {
3173
+ result = this.minimizeSurface(record.id);
3174
+ action = 'route-minimize';
3175
+ }
3176
+ } else if (config.policy === 'open-minimize') {
3177
+ if (record.capabilities && record.capabilities.includes('minimize')) {
3178
+ result = this.minimizeSurface(record.id);
3179
+ action = 'route-minimize';
3180
+ } else {
3181
+ result = this.collapseSurface(record.id);
3182
+ action = 'route-collapse';
3183
+ }
3184
+ } else {
3185
+ result = this.closeSurface(record.id, 'route-lifecycle');
3186
+ action = 'route-close';
3187
+ }
3188
+
3189
+ return {
3190
+ surfaceId: record.id,
3191
+ policy: config.policy,
3192
+ action,
3193
+ matched: false,
3194
+ ok: result ? result.ok !== false : true,
3195
+ result: result || null
3196
+ };
3197
+ }
3198
+
3199
+ hydrateSurfaceContent(surfaceRef, options = {}) {
3200
+ const element = this._resolveSurfaceElement(surfaceRef);
3201
+ const record = this._resolveSurfaceRecord(surfaceRef, element);
3202
+ const surfaceId = record && record.id || element && (element.getAttribute('surface-id') || element.id);
3203
+ if (!element || !surfaceId) {
3204
+ const diagnostic = this._createSurfaceLoadingDiagnostic(
3205
+ 'xtend.surface.loading.surface-not-found',
3206
+ 'Surface content cannot be hydrated because the surface element was not found.',
3207
+ 'warning',
3208
+ { surfaceRef }
3209
+ );
3210
+ const result = { ok: false, hydrated: false, skipped: true, diagnostic, surfaceId: surfaceId || null };
3211
+ this._dispatchSurfaceLoadingEvent('surface-content-hydration-skipped', result);
3212
+ return Promise.resolve(result);
3213
+ }
3214
+
3215
+ const policy = normalizeSurfaceLoadingPolicy(options.policy, this._resolveSurfaceLoadingPolicy(element, record || {}));
3216
+ const state = this._ensureSurfaceLoadingState(surfaceId, element, record || {}, policy);
3217
+ if (state && state.hydrated === true && options.force !== true) {
3218
+ const result = { ok: true, hydrated: true, skipped: true, surfaceId, policy, state };
3219
+ this._dispatchSurfaceLoadingEvent('surface-content-hydration-skipped', result);
3220
+ return Promise.resolve(result);
3221
+ }
3222
+ if (this._surfaceLoadingPromises.has(surfaceId)) return this._surfaceLoadingPromises.get(surfaceId);
3223
+
3224
+ this._showSurfaceSkeleton(element, record || {}, { policy, reason: options.reason || 'manual' });
3225
+ const promise = this._runSurfaceHydration(element, record || { id: surfaceId }, policy, options)
3226
+ .finally(() => {
3227
+ this._surfaceLoadingPromises.delete(surfaceId);
3228
+ });
3229
+ this._surfaceLoadingPromises.set(surfaceId, promise);
3230
+ return promise;
3231
+ }
3232
+
3233
+ _runSurfaceHydration(element, record = {}, policy = 'open', options = {}) {
3234
+ const loader = surfaceLoaderApi();
3235
+ const surfaceId = record.id || element.getAttribute('surface-id') || element.id;
3236
+ const state = this._ensureSurfaceLoadingState(surfaceId, element, record, policy);
3237
+ const startedAt = surfaceLoadingNow();
3238
+ const schedule = `surface.${policy}.hydrate`;
3239
+ if (state) {
3240
+ state.status = 'hydrating';
3241
+ state.startedAt = startedAt;
3242
+ state.policy = policy;
3243
+ state.pendingRoute = false;
3244
+ state.tags = collectSurfaceHydrationTags(element);
3245
+ state.unresolvedTags = [];
3246
+ }
3247
+ this._surfaceRouteHydrationPending.delete(surfaceId);
3248
+ this._dispatchSurfaceLoadingEvent('surface-content-loading', { ok: true, surfaceId, policy, schedule, state });
3249
+
3250
+ const timeoutMs = normalizeSurfaceLoadingTimeout(options.timeoutMs !== undefined ? options.timeoutMs : this._surfaceHydrationTimeout());
3251
+ let timedOut = false;
3252
+ const task = (async () => {
3253
+ if (loader.ensureRuntimeStyles) loader.ensureRuntimeStyles({ source: 'x-surface-manager.surface-hydration' });
3254
+ const tags = collectSurfaceHydrationTags(element);
3255
+ if (state) state.tags = tags;
3256
+ if (loader.ensureComponent) {
3257
+ await Promise.all(tags.map((tag) => loader.ensureComponent(tag, {
3258
+ source: 'x-surface-manager',
3259
+ reason: options.reason || 'surface-content-hydration',
3260
+ schedule,
3261
+ skipBootWait: true
3262
+ })));
3263
+ }
3264
+ const hydration = loader.hydrateTree
3265
+ ? await loader.hydrateTree(element, {
3266
+ source: 'x-surface-manager',
3267
+ reason: options.reason || 'surface-content-hydration',
3268
+ schedule,
3269
+ skipBootWait: true
3270
+ })
3271
+ : { schema: 'xtend.surface.loading.no-loader-hydration.v1', tags, hydrated: 0 };
3272
+ const unresolvedTags = tags.filter((tag) => (
3273
+ globalThis.customElements
3274
+ && typeof globalThis.customElements.get === 'function'
3275
+ && !globalThis.customElements.get(tag)
3276
+ ));
3277
+ if (unresolvedTags.length > 0 && options.allowUnresolved !== true) {
3278
+ throw new Error(`Unresolved surface content components: ${unresolvedTags.join(', ')}`);
3279
+ }
3280
+ if (timedOut) {
3281
+ throw new Error(`Surface content hydration timed out after ${timeoutMs}ms`);
3282
+ }
3283
+ this._hideSurfaceSkeleton(element);
3284
+ const finishedAt = surfaceLoadingNow();
3285
+ if (state) {
3286
+ state.status = 'hydrated';
3287
+ state.hydrated = true;
3288
+ state.skeleton = false;
3289
+ state.hydratedAt = new Date().toISOString();
3290
+ state.durationMs = Math.max(0, finishedAt - startedAt);
3291
+ state.unresolvedTags = [];
3292
+ }
3293
+ const result = {
3294
+ ok: true,
3295
+ hydrated: true,
3296
+ skipped: false,
3297
+ surfaceId,
3298
+ policy,
3299
+ schedule,
3300
+ durationMs: state && state.durationMs || 0,
3301
+ hydration,
3302
+ tags
3303
+ };
3304
+ this._dispatchSurfaceLoadingEvent('surface-content-hydrated', result);
3305
+ return result;
3306
+ })();
3307
+
3308
+ const guardedTask = timeoutMs > 0
3309
+ ? Promise.race([
3310
+ task,
3311
+ new Promise((_, reject) => {
3312
+ globalThis.setTimeout(() => {
3313
+ timedOut = true;
3314
+ reject(new Error(`Surface content hydration timed out after ${timeoutMs}ms`));
3315
+ }, timeoutMs);
3316
+ })
3317
+ ])
3318
+ : task;
3319
+
3320
+ return guardedTask.catch((error) => {
3321
+ const tags = collectSurfaceHydrationTags(element);
3322
+ const unresolvedTags = tags.filter((tag) => (
3323
+ globalThis.customElements
3324
+ && typeof globalThis.customElements.get === 'function'
3325
+ && !globalThis.customElements.get(tag)
3326
+ ));
3327
+ const diagnostic = this._createSurfaceLoadingDiagnostic(
3328
+ 'xtend.surface.loading.hydration-failed',
3329
+ 'Surface content hydration failed; the skeleton remains active to avoid unstyled pop-in.',
3330
+ 'warning',
3331
+ {
3332
+ surfaceId,
3333
+ policy,
3334
+ schedule,
3335
+ error: error && error.message || String(error),
3336
+ unresolvedTags
3337
+ }
3338
+ );
3339
+ if (state) {
3340
+ state.status = 'error';
3341
+ state.hydrated = false;
3342
+ state.skeleton = true;
3343
+ state.unresolvedTags = unresolvedTags;
3344
+ state.diagnostics.push(diagnostic);
3345
+ state.durationMs = Math.max(0, surfaceLoadingNow() - startedAt);
3346
+ }
3347
+ element.setAttribute('data-xtend-surface-content-ready', 'false');
3348
+ element.setAttribute('data-xtend-surface-loading-error', diagnostic.code);
3349
+ const result = { ok: false, hydrated: false, skipped: false, surfaceId, policy, schedule, diagnostic, tags, unresolvedTags };
3350
+ this._dispatchSurfaceLoadingEvent('surface-content-hydration-error', result);
3351
+ return result;
3352
+ });
3353
+ }
3354
+
3355
+ snapshotPersistence(options = {}) {
3356
+ const mode = this._persistenceMode();
3357
+ const key = this._persistenceStorageKey();
3358
+ const adapter = this._persistenceAdapter();
3359
+ let hasSnapshot = false;
3360
+ if (options.includeStoredState !== false && adapter && key) {
3361
+ try {
3362
+ hasSnapshot = Boolean(adapter.getItem(key));
3363
+ } catch (_error) {
3364
+ hasSnapshot = false;
3365
+ }
3366
+ }
3367
+ return {
3368
+ schema: SURFACE_MANAGER_PERSISTENCE_SCHEMA,
3369
+ version: SURFACE_PERSISTENCE_VERSION,
3370
+ managerId: this._managerId(),
3371
+ restoreKey: this._restoreKey(),
3372
+ stateKey: this._stateKey(),
3373
+ mode,
3374
+ policy: this._restorePolicy(),
3375
+ key,
3376
+ storageAvailable: mode === 'none' ? false : Boolean(adapter),
3377
+ hasSnapshot,
3378
+ noContentPayload: true,
3379
+ createsSecondRegistry: false
3380
+ };
3381
+ }
3382
+
3383
+ persistSnapshot(snapshot = this.snapshot(), options = {}) {
3384
+ const mode = this._persistenceMode();
3385
+ const key = this._persistenceStorageKey();
3386
+ const reason = options.reason || 'snapshot';
3387
+ if (this._snapshotPersistenceSuspended && options.force !== true) {
3388
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.suspended', 'Surface persistence is temporarily suspended.', 'info', { reason });
3389
+ return { ok: false, persisted: false, skipped: true, diagnostic, snapshot };
3390
+ }
3391
+ if (mode === 'none' || !key) {
3392
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.disabled', 'Surface persistence is disabled.', 'info', { reason });
3393
+ return { ok: false, persisted: false, skipped: true, diagnostic, snapshot };
3394
+ }
3395
+ const adapter = this._persistenceAdapter();
3396
+ if (!adapter) {
3397
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.storage-unavailable', 'Surface persistence storage is unavailable.', 'warning', { mode, reason });
3398
+ const result = { ok: false, persisted: false, skipped: true, diagnostic, snapshot };
3399
+ this._dispatchPersistenceEvent('surface-persistence-error', result);
3400
+ return result;
3401
+ }
3402
+ try {
3403
+ const envelope = this._createPersistedEnvelope(snapshot, reason);
3404
+ adapter.setItem(key, JSON.stringify(envelope));
3405
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.saved', 'Surface snapshot persisted.', 'info', {
3406
+ key,
3407
+ mode,
3408
+ surfaceCount: envelope.snapshot.surfaces.length,
3409
+ reason
3410
+ });
3411
+ const result = { ok: true, persisted: true, skipped: false, key, mode, envelope, diagnostic, snapshot: envelope.snapshot };
3412
+ this._dispatchPersistenceEvent('surface-snapshot-persisted', result);
3413
+ return result;
3414
+ } catch (error) {
3415
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.write-failed', 'Surface snapshot could not be persisted.', 'warning', {
3416
+ key,
3417
+ mode,
3418
+ reason,
3419
+ error: error && error.message || String(error)
3420
+ });
3421
+ const result = { ok: false, persisted: false, skipped: true, diagnostic, snapshot };
3422
+ this._dispatchPersistenceEvent('surface-persistence-error', result);
3423
+ return result;
3424
+ }
3425
+ }
3426
+
3427
+ restorePersistedSnapshot(options = {}) {
3428
+ if (options.source === 'connected' && this._restorePolicy() !== 'auto') {
3429
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.restore-skipped', 'Automatic surface restore is disabled by policy.', 'info', {
3430
+ policy: this._restorePolicy()
3431
+ });
3432
+ return { ok: false, restored: false, skipped: true, diagnostic, snapshot: this.snapshot() };
3433
+ }
3434
+ const readResult = options.envelope
3435
+ ? this._validatePersistedEnvelope(options.envelope)
3436
+ : this._readPersistedEnvelope();
3437
+ if (!readResult.ok) {
3438
+ const result = {
3439
+ ok: false,
3440
+ restored: false,
3441
+ skipped: true,
3442
+ diagnostic: readResult.diagnostic,
3443
+ snapshot: this.snapshot()
3444
+ };
3445
+ if (readResult.diagnostic && readResult.diagnostic.severity !== 'info') {
3446
+ this._dispatchPersistenceEvent('surface-restore-skipped', result);
3447
+ }
3448
+ return result;
3449
+ }
3450
+ const envelope = readResult.envelope;
3451
+ const restored = this._applyPersistedSurfaceSnapshot(envelope.snapshot, options);
3452
+ const result = {
3453
+ ok: restored.restoredCount > 0,
3454
+ restored: restored.restoredCount > 0,
3455
+ skipped: restored.restoredCount === 0,
3456
+ envelope,
3457
+ diagnostic: restored.diagnostic,
3458
+ restoredCount: restored.restoredCount,
3459
+ skippedCount: restored.skippedCount,
3460
+ snapshot: restored.snapshot
3461
+ };
3462
+ this._dispatchPersistenceEvent(result.restored ? 'surface-snapshot-restored' : 'surface-restore-skipped', result);
3463
+ if (result.restored) this.persistSnapshot(restored.snapshot, { reason: 'restore', force: true });
3464
+ return result;
3465
+ }
3466
+
3467
+ clearPersistedSnapshot(options = {}) {
3468
+ const mode = this._persistenceMode();
3469
+ const key = this._persistenceStorageKey();
3470
+ const adapter = this._persistenceAdapter();
3471
+ if (!adapter || !key || mode === 'none') {
3472
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.disabled', 'Surface persistence is disabled.', 'info', { reason: options.reason || 'clear' });
3473
+ return { ok: false, cleared: false, skipped: true, diagnostic };
3474
+ }
3475
+ try {
3476
+ adapter.removeItem(key);
3477
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.cleared', 'Persisted surface snapshot cleared.', 'info', { key, mode });
3478
+ const result = { ok: true, cleared: true, skipped: false, key, mode, diagnostic, snapshot: this.snapshot() };
3479
+ this._dispatchPersistenceEvent('surface-snapshot-cleared', result);
3480
+ return result;
3481
+ } catch (error) {
3482
+ const diagnostic = this._createPersistenceDiagnostic('xtend.surface.persistence.clear-failed', 'Persisted surface snapshot could not be cleared.', 'warning', {
3483
+ key,
3484
+ mode,
3485
+ error: error && error.message || String(error)
3486
+ });
3487
+ const result = { ok: false, cleared: false, skipped: true, diagnostic, snapshot: this.snapshot() };
3488
+ this._dispatchPersistenceEvent('surface-persistence-error', result);
3489
+ return result;
3490
+ }
3491
+ }
3492
+
3493
+ resetSurfaceLayout(options = {}) {
3494
+ const clearResult = this.clearPersistedSnapshot({ reason: 'reset', ...options });
3495
+ const wasSuspended = this._snapshotPersistenceSuspended;
3496
+ this._snapshotPersistenceSuspended = true;
3497
+ if (this._controller && typeof this._controller.dispose === 'function') this._controller.dispose();
3498
+ this._controller = null;
3499
+ this._registeredElements.clear();
3500
+ this._surfaceLoadingStates.clear();
3501
+ this._surfaceLoadingPromises.clear();
3502
+ this._surfaceRouteHydrationPending.clear();
3503
+ this._surfaceRouteLifecycleStates.clear();
3504
+ this._surfaceLayoutStates.clear();
3505
+ this._lastSurfaceLayoutReport = null;
3506
+ this._surfaceRemotePolicyStates.clear();
3507
+ this._lastSurfaceRemotePolicyReport = null;
3508
+ this._currentSurfaceRoute = null;
3509
+ this._lastSurfaceRouteSignalKey = '';
3510
+ this._surfaceIdleHandles.forEach((handle) => clearSurfaceIdle(handle));
3511
+ this._surfaceIdleHandles.clear();
3512
+ this._ensureController();
3513
+ this._registerAssignedSurfaces();
3514
+ this._snapshotPersistenceSuspended = wasSuspended;
3515
+ const snapshot = this._applySnapshot();
3516
+ const persistResult = this.persistSnapshot(snapshot, { reason: 'reset' });
3517
+ const result = {
3518
+ ok: true,
3519
+ reset: true,
3520
+ clearResult,
3521
+ persistResult,
3522
+ snapshot,
3523
+ diagnostic: this._createPersistenceDiagnostic('xtend.surface.persistence.reset', 'Surface layout reset to declared defaults.', 'info')
3524
+ };
3525
+ this._dispatchPersistenceEvent('surface-snapshot-reset', result);
3526
+ return result;
3527
+ }
3528
+
3529
+ _commit(method, eventName, id, payload) {
3530
+ const controller = this._ensureController();
3531
+ if (method === 'openSurface' || method === 'focusSurface') {
3532
+ this._captureStackFocusRestoreTarget(id);
3533
+ }
3534
+ const result = controller[method](id, payload);
3535
+ const snapshot = this._applySnapshot();
3536
+ this.persistSnapshot(snapshot, { reason: method });
3537
+ this._dispatchManagerEvent(eventName, { result, snapshot });
3538
+ return result;
3539
+ }
3540
+
3541
+ _applyPersistedSurfaceSnapshot(snapshot, options = {}) {
3542
+ const controller = this._ensureController();
3543
+ const surfaces = Array.isArray(snapshot && snapshot.surfaces) ? snapshot.surfaces : [];
3544
+ const byId = new Map(surfaces.map((record) => [record.id, record]));
3545
+ const stack = Array.isArray(snapshot && snapshot.stack) && snapshot.stack.length > 0
3546
+ ? snapshot.stack.filter((id) => byId.has(id))
3547
+ : surfaces.slice().sort((left, right) => (left.zIndex || 0) - (right.zIndex || 0)).map((record) => record.id);
3548
+ const wasSuspended = this._snapshotPersistenceSuspended;
3549
+ const wasRestoring = this._restoringSnapshot;
3550
+ let restoredCount = 0;
3551
+ let skippedCount = 0;
3552
+
3553
+ this._snapshotPersistenceSuspended = true;
3554
+ this._restoringSnapshot = true;
3555
+ try {
3556
+ surfaces.forEach((record) => {
3557
+ const patchResult = controller.updateSurface(record.id, {
3558
+ label: record.label,
3559
+ capabilities: record.capabilities,
3560
+ bounds: record.bounds,
3561
+ placement: record.placement,
3562
+ mode: record.mode,
3563
+ pinned: record.pinned,
3564
+ collapsed: record.collapsed,
3565
+ modal: record.modal
3566
+ });
3567
+ if (!patchResult || patchResult.ok === false) {
3568
+ skippedCount += 1;
3569
+ return;
3570
+ }
3571
+ if (record.status === 'closed') {
3572
+ controller.closeSurface(record.id, 'snapshot-restore');
3573
+ } else {
3574
+ controller.openSurface(record.id, { bounds: record.bounds });
3575
+ if (record.status === 'minimized' || record.minimized) controller.minimizeSurface(record.id);
3576
+ if (record.maximized) controller.maximizeSurface(record.id);
3577
+ }
3578
+ restoredCount += 1;
3579
+ });
3580
+ stack.forEach((surfaceId) => {
3581
+ const record = byId.get(surfaceId);
3582
+ if (record && record.status !== 'closed' && record.status !== 'minimized') controller.focusSurface(surfaceId);
3583
+ });
3584
+ if (snapshot.activeSurfaceId && byId.has(snapshot.activeSurfaceId)) {
3585
+ const activeRecord = byId.get(snapshot.activeSurfaceId);
3586
+ if (activeRecord.status !== 'closed' && activeRecord.status !== 'minimized') controller.focusSurface(snapshot.activeSurfaceId);
3587
+ }
3588
+ } finally {
3589
+ this._snapshotPersistenceSuspended = wasSuspended;
3590
+ this._restoringSnapshot = wasRestoring;
3591
+ }
3592
+
3593
+ const appliedSnapshot = this._applySnapshot();
3594
+ const diagnostic = this._createPersistenceDiagnostic(
3595
+ restoredCount > 0 ? 'xtend.surface.persistence.restored' : 'xtend.surface.persistence.restore-skipped',
3596
+ restoredCount > 0 ? 'Surface snapshot restored.' : 'Surface snapshot restore skipped.',
3597
+ restoredCount > 0 ? 'info' : 'warning',
3598
+ {
3599
+ source: options.source || 'manual',
3600
+ restoredCount,
3601
+ skippedCount,
3602
+ stackDepth: stack.length,
3603
+ activeSurfaceId: snapshot.activeSurfaceId || null
3604
+ }
3605
+ );
3606
+ return { restoredCount, skippedCount, snapshot: appliedSnapshot, diagnostic };
3607
+ }
3608
+
3609
+ _applySnapshot(options = {}) {
3610
+ let snapshot = this.snapshot();
3611
+ if (options.skipLayoutEngine !== true) {
3612
+ const layoutResult = this._applyLayoutEngineSnapshot(snapshot, {
3613
+ source: 'applySnapshot',
3614
+ commit: true,
3615
+ dispatch: false
3616
+ });
3617
+ snapshot = layoutResult && layoutResult.snapshot || snapshot;
3618
+ }
3619
+ snapshot.surfaces.forEach((record) => {
3620
+ const element = this._registeredElements.get(record.id)
3621
+ || this.querySelector(surfaceElementSelector(record.id));
3622
+ if (element && isSurfaceOverlayElement(element)) {
3623
+ this._syncingOverlayElements.add(element);
3624
+ try {
3625
+ applyOverlaySurfaceSnapshot(element, record);
3626
+ } finally {
3627
+ queueMicrotask(() => this._syncingOverlayElements.delete(element));
3628
+ }
3629
+ } else if (element && typeof element.applySurfaceSnapshot === 'function') {
3630
+ element.applySurfaceSnapshot(record);
3631
+ }
3632
+ if (element) {
3633
+ this._applyRemoteSurfacePolicyDom(element, this._surfaceRemotePolicyStates.get(record.id));
3634
+ this._prepareSurfaceLoading(element, record, { reason: 'applySnapshot' });
3635
+ }
3636
+ });
3637
+ if (this._lastSurfaceLayoutReport) this._applySurfaceLayoutDom(this._lastSurfaceLayoutReport);
3638
+ this._applyStackPolicy(snapshot, { source: 'applySnapshot' });
3639
+ this._status.textContent = snapshot.activeSurfaceId ? `Active surface ${snapshot.activeSurfaceId}` : 'No active surface';
3640
+ return snapshot;
3641
+ }
3642
+
3643
+ _onSurfaceCommand(event) {
3644
+ const detail = event.detail || {};
3645
+ const { command, payload } = detail;
3646
+ const surfaceId = detail.surfaceId || detail.id;
3647
+ if (!surfaceId || !command) return;
3648
+ event.stopPropagation();
3649
+ const commands = {
3650
+ open: () => this.openSurface(surfaceId, payload),
3651
+ close: () => this.closeSurface(surfaceId, payload && payload.reason),
3652
+ focus: () => this.focusSurface(surfaceId),
3653
+ move: () => this.moveSurface(surfaceId, payload),
3654
+ resize: () => this.resizeSurface(surfaceId, payload),
3655
+ minimize: () => this.minimizeSurface(surfaceId),
3656
+ maximize: () => this.maximizeSurface(surfaceId),
3657
+ restore: () => this.restoreSurface(surfaceId),
3658
+ pin: () => this.pinSurface(surfaceId, payload && payload.pinned !== false),
3659
+ unpin: () => this.pinSurface(surfaceId, false),
3660
+ collapse: () => this.collapseSurface(surfaceId),
3661
+ expand: () => this.expandSurface(surfaceId, payload && payload.mode || 'docked'),
3662
+ dock: () => this.dockSurface(surfaceId, payload && payload.placement || 'right', payload && payload.mode || 'docked'),
3663
+ update: () => this.updateSurface(surfaceId, payload)
3664
+ };
3665
+ if (commands[command]) commands[command]();
3666
+ }
3667
+
3668
+ _onOverlayLifecycle(event) {
3669
+ const element = findSurfaceOverlayElement(event);
3670
+ if (!element || !this.contains(element) || this._syncingOverlayElements.has(element)) return;
3671
+ const surfaceId = overlaySurfaceId(element);
3672
+ const wasRegistered = this._registeredElements.has(surfaceId);
3673
+
3674
+ if (!wasRegistered) {
3675
+ this.registerSurface(element);
3676
+ return;
3677
+ }
3678
+
3679
+ const detail = event.detail || {};
3680
+ if (event.type.endsWith('-opened')) {
3681
+ this.openSurface(surfaceId, {
3682
+ source: detail.source || event.type,
3683
+ legacyEvent: event.type
3684
+ });
3685
+ return;
3686
+ }
3687
+
3688
+ if (event.type.endsWith('-closed')) {
3689
+ this.closeSurface(surfaceId, detail.source || event.type);
3690
+ return;
3691
+ }
3692
+
3693
+ if (event.type === 'drawer-route-selected') {
3694
+ this.updateSurface(surfaceId, {
3695
+ routeRef: detail.routeRef || null,
3696
+ legacyEvent: event.type
3697
+ });
3698
+ }
3699
+ }
3700
+
3701
+ _onSurfaceRouteSignal(event) {
3702
+ const route = this._normalizeRouteLifecycleInput(event);
3703
+ const routeSignalKey = `${route.normalizedPath}|${route.routeId || ''}|${route.component || ''}`;
3704
+ if (routeSignalKey && this._lastSurfaceRouteSignalKey === routeSignalKey) return null;
3705
+ this._lastSurfaceRouteSignalKey = routeSignalKey;
3706
+ const lifecycleResult = this._routeAware()
3707
+ ? this.applyRouteLifecycle(route, { source: event && event.type || 'route-signal' })
3708
+ : null;
3709
+ if (this._surfaceRouteHydrationPending.size === 0) return lifecycleResult;
3710
+ const pending = Array.from(this._surfaceRouteHydrationPending);
3711
+ pending.forEach((surfaceId) => {
3712
+ const element = this._resolveSurfaceElement(surfaceId);
3713
+ const record = this._resolveSurfaceRecord(surfaceId, element);
3714
+ const config = this._resolveSurfaceRouteConfig(element, record || { id: surfaceId });
3715
+ if (this._routeAware() && !config.global && !this._surfaceRouteMatches(config, route)) return;
3716
+ this.hydrateSurfaceContent(surfaceId, {
3717
+ policy: 'route',
3718
+ reason: event && event.type || 'surface.route.hydrate',
3719
+ force: true
3720
+ });
3721
+ });
3722
+ return lifecycleResult;
3723
+ }
3724
+
3725
+ _onSurfaceStackKeyDown(event) {
3726
+ if (!event || event.key !== 'Escape' || event.defaultPrevented) return;
3727
+ const stackPolicy = this.snapshotStackPolicy();
3728
+ const surfaceId = stackPolicy.escapeTargetSurfaceId;
3729
+ if (!surfaceId) return;
3730
+ const eventPath = typeof event.composedPath === 'function' ? event.composedPath() : [];
3731
+ const eventTarget = eventPath[0] || event.target;
3732
+ const eventInsideManager = eventPath.includes(this) || surfaceElementContainsTarget(this, eventTarget);
3733
+ if (!eventInsideManager) return;
3734
+ const entry = stackPolicy.surfaces.find((surface) => surface.surfaceId === surfaceId);
3735
+ if (!entry || !entry.open) return;
3736
+ if (typeof event.preventDefault === 'function') event.preventDefault();
3737
+ if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
3738
+ if (typeof event.stopPropagation === 'function') event.stopPropagation();
3739
+ const result = this.closeSurface(surfaceId, 'escape');
3740
+ this._dispatchSurfaceStackPolicyEvent('surface-stack-policy-escape', {
3741
+ ok: result && result.ok !== false,
3742
+ surfaceId,
3743
+ result,
3744
+ stackPolicy,
3745
+ snapshot: this.snapshot()
3746
+ });
3747
+ }
3748
+
3749
+ _onSurfaceStackFocusIn(event) {
3750
+ if (!event || !this._activeStackModalSurfaceId) return;
3751
+ const element = this._resolveStackElement(this._activeStackModalSurfaceId);
3752
+ if (!element || surfaceElementContainsTarget(element, event.target)) return;
3753
+ if (typeof event.stopPropagation === 'function') event.stopPropagation();
3754
+ this._ensureStackFocusWithinSurface(this._activeStackModalSurfaceId, { source: 'focusin-trap' });
3755
+ }
3756
+
3757
+ _dispatchManagerEvent(type, detail) {
3758
+ const snapshot = detail.snapshot || this.snapshot();
3759
+ this.dispatchEvent(new CustomEvent(type, {
3760
+ bubbles: true,
3761
+ composed: true,
3762
+ detail: {
3763
+ managerId: this._managerId(),
3764
+ result: detail.result,
3765
+ snapshot
3766
+ }
3767
+ }));
3768
+ }
3769
+ }
3770
+
3771
+ if (!customElements.get('x-surface-manager')) {
3772
+ customElements.define('x-surface-manager', XSurfaceManager);
3773
+ }
3774
+
3775
+ export { XSurfaceManager };