@ccslabs/xtend 0.1.0-rc.1 → 0.1.2

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 (566) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +4 -0
  3. package/catalog/component-catalog-coverage.js +2 -0
  4. package/catalog/epic13-package-export-lock.js +11 -1
  5. package/catalog/epic13-rmt-production-readiness.js +0 -1
  6. package/catalog/epic18-rmt-action-effect-runtime.d.ts +36 -0
  7. package/catalog/epic18-rmt-action-effect-runtime.js +249 -0
  8. package/catalog/epic18-rmt-app-platform-authoring.d.ts +39 -0
  9. package/catalog/epic18-rmt-app-platform-authoring.js +319 -0
  10. package/catalog/epic18-rmt-app-platform-fixture.d.ts +33 -0
  11. package/catalog/epic18-rmt-app-platform-fixture.js +221 -0
  12. package/catalog/epic18-rmt-app-platform-release-handoff.d.ts +30 -0
  13. package/catalog/epic18-rmt-app-platform-release-handoff.js +231 -0
  14. package/catalog/epic18-rmt-app-platform-tooling.d.ts +38 -0
  15. package/catalog/epic18-rmt-app-platform-tooling.js +242 -0
  16. package/catalog/epic18-rmt-component-template-primitives.d.ts +33 -0
  17. package/catalog/epic18-rmt-component-template-primitives.js +240 -0
  18. package/catalog/epic18-rmt-dom-descriptor-renderer.d.ts +35 -0
  19. package/catalog/epic18-rmt-dom-descriptor-renderer.js +232 -0
  20. package/catalog/epic18-rmt-event-routing-runtime.d.ts +35 -0
  21. package/catalog/epic18-rmt-event-routing-runtime.js +234 -0
  22. package/catalog/epic18-rmt-state-selector-runtime.d.ts +34 -0
  23. package/catalog/epic18-rmt-state-selector-runtime.js +216 -0
  24. package/catalog/epic18-rmt-surface-resource-graph-runtime.d.ts +36 -0
  25. package/catalog/epic18-rmt-surface-resource-graph-runtime.js +256 -0
  26. package/catalog/surface-manager-controller.js +5 -1
  27. package/catalog/surface-manager-materialization.js +7 -1
  28. package/catalog/surface-manager-overlay-bridge.js +41 -6
  29. package/catalog/surface-manager-workbench-fixture.js +1 -1
  30. package/catalog/surface-type-capability-matrix.d.ts +61 -0
  31. package/catalog/surface-type-capability-matrix.js +183 -0
  32. package/catalog/type-exports-rmt.js +37 -1
  33. package/catalog/type-exports.js +3 -3
  34. package/components/icon-packs/lucide.js +4 -0
  35. package/components/manifest.json +2 -0
  36. package/components/prism-rmt.d.ts +34 -0
  37. package/components/prism-rmt.js +130 -0
  38. package/components/xcards.js +15 -0
  39. package/components/xcode.d.ts +36 -1
  40. package/components/xcode.js +215 -20
  41. package/components/xfooter.js +17 -0
  42. package/components/xheader.js +14 -0
  43. package/components/xhero.js +16 -1
  44. package/components/xlink.js +97 -14
  45. package/components/xmasonry.js +15 -0
  46. package/components/xplayer.d.ts +44 -2
  47. package/components/xplayer.js +242 -15
  48. package/components/xrouter.js +27 -2
  49. package/components/xsection.js +15 -0
  50. package/components/xsidepanel.js +10 -2
  51. package/components/xsurfacemanager-controller.d.ts +2 -1
  52. package/components/xsurfacemanager-controller.js +27 -3
  53. package/components/xsurfacemanager.d.ts +2 -0
  54. package/components/xsurfacemanager.js +20 -8
  55. package/components/xsurfaceoverlay-bridge.d.ts +20 -5
  56. package/components/xsurfaceoverlay-bridge.js +114 -18
  57. package/components/xsurfaceportal.d.ts +29 -0
  58. package/components/xsurfaceportal.js +122 -0
  59. package/components/xsurfaceregion.d.ts +50 -0
  60. package/components/xsurfaceregion.js +285 -0
  61. package/components/xsurfacewindow.js +2 -1
  62. package/components/xtooltip.js +89 -23
  63. package/docs/README.md +222 -298
  64. package/docs/changelog.md +107 -0
  65. package/docs/component-catalog-coverage.md +9 -9
  66. package/docs/component-platform.md +19 -1
  67. package/docs/component-ux-app-authoring.md +56 -63
  68. package/docs/components/xcode.md +83 -53
  69. package/docs/components/xsurfaceportal.md +32 -0
  70. package/docs/components/xsurfaceregion.md +37 -0
  71. package/docs/components.md +105 -69
  72. package/docs/de/README.md +264 -0
  73. package/docs/de/XTend-ADR.md +221 -0
  74. package/docs/de/a11y-keyboard-smokes.md +62 -0
  75. package/docs/de/about.md +18 -0
  76. package/docs/de/api.md +157 -0
  77. package/docs/de/best-practices.md +76 -0
  78. package/docs/de/changelog.md +107 -0
  79. package/docs/de/component-catalog-coverage.md +58 -0
  80. package/docs/de/component-lab.md +103 -0
  81. package/docs/de/component-long-tail-migration.md +41 -0
  82. package/docs/de/component-platform.md +177 -0
  83. package/docs/de/component-ux-app-authoring.md +123 -0
  84. package/docs/de/component-ux-authoring.md +96 -0
  85. package/docs/de/component-ux-gates.md +45 -0
  86. package/docs/de/components/x-rmt-lifecycle-demo-build.md +60 -0
  87. package/docs/de/components/xalert.md +81 -0
  88. package/docs/de/components/xbutton.md +103 -0
  89. package/docs/de/components/xcalendar.md +82 -0
  90. package/docs/de/components/xcards.md +128 -0
  91. package/docs/de/components/xcheckbox.md +102 -0
  92. package/docs/de/components/xcode.md +156 -0
  93. package/docs/de/components/xdialog.md +92 -0
  94. package/docs/de/components/xdrawer.md +84 -0
  95. package/docs/de/components/xfooter.md +126 -0
  96. package/docs/de/components/xform.md +128 -0
  97. package/docs/de/components/xheader.md +308 -0
  98. package/docs/de/components/xhero.md +142 -0
  99. package/docs/de/components/xicon.md +125 -0
  100. package/docs/de/components/xinput.md +129 -0
  101. package/docs/de/components/xlightbox.md +98 -0
  102. package/docs/de/components/xlink.md +109 -0
  103. package/docs/de/components/xmasonry.md +124 -0
  104. package/docs/de/components/xmenu.md +158 -0
  105. package/docs/de/components/xmodal.md +82 -0
  106. package/docs/de/components/xplayer.md +104 -0
  107. package/docs/de/components/xpopover.md +67 -0
  108. package/docs/de/components/xprogress.md +56 -0
  109. package/docs/de/components/xradio.md +103 -0
  110. package/docs/de/components/xrouter.md +260 -0
  111. package/docs/de/components/xsection.md +125 -0
  112. package/docs/de/components/xselect.md +105 -0
  113. package/docs/de/components/xsidepanel.md +30 -0
  114. package/docs/de/components/xspinner.md +102 -0
  115. package/docs/de/components/xstate.md +148 -0
  116. package/docs/de/components/xstatus.md +55 -0
  117. package/docs/de/components/xsummary.md +78 -0
  118. package/docs/de/components/xsurfacemanager.md +27 -0
  119. package/docs/de/components/xsurfacewindow.md +21 -0
  120. package/docs/de/components/xtabs.md +160 -0
  121. package/docs/de/components/xtextarea.md +98 -0
  122. package/docs/de/components/xtheme.md +167 -0
  123. package/docs/de/components/xtoast.md +62 -0
  124. package/docs/de/components/xtooltip.md +66 -0
  125. package/docs/de/components/xtype.md +82 -0
  126. package/docs/de/components/xutils.md +144 -0
  127. package/docs/de/components/xwriter.md +94 -0
  128. package/docs/de/components.md +153 -0
  129. package/docs/de/conditional-network-evidence-ci.md +38 -0
  130. package/docs/de/conditional-network-evidence.md +50 -0
  131. package/docs/de/core-migration-guide.md +110 -0
  132. package/docs/de/design-tokens.md +116 -0
  133. package/docs/de/docs-rmt-production-hardening.md +31 -0
  134. package/docs/de/enterprise-adoption.md +413 -0
  135. package/docs/de/enterprise-component-flex-release-handoff.md +129 -0
  136. package/docs/de/epic10-platform-gates.md +62 -0
  137. package/docs/de/epic10-release-handoff.md +81 -0
  138. package/docs/de/epic11-enterprise-ux-handoff.md +70 -0
  139. package/docs/de/epic12-rc0-handoff.md +61 -0
  140. package/docs/de/epic18-media-manager-vendor-upstream.md +318 -0
  141. package/docs/de/epic18-rmt-app-platform-release-handoff.md +67 -0
  142. package/docs/de/epic18-vendor-bugfixes.md +34 -0
  143. package/docs/de/existing-component-metadata.md +67 -0
  144. package/docs/de/hydration-performance-closure.md +34 -0
  145. package/docs/de/hydration-policies.md +71 -0
  146. package/docs/de/known-residual-triage.md +22 -0
  147. package/docs/de/manifest-import-policy.md +79 -0
  148. package/docs/de/manifest.md +112 -0
  149. package/docs/de/motion-contrast.md +67 -0
  150. package/docs/de/package-export-lock.md +44 -0
  151. package/docs/de/performance-measurements.md +106 -0
  152. package/docs/de/performance-regression.md +89 -0
  153. package/docs/de/performance.md +94 -0
  154. package/docs/de/previews/README.md +17 -0
  155. package/docs/de/prod-browser-csp-smokes.md +40 -0
  156. package/docs/de/public-component-types.md +79 -0
  157. package/docs/de/quick-start-guide.md +220 -0
  158. package/docs/de/rc0-adoption-guide.md +102 -0
  159. package/docs/de/rc0-gate-matrix.md +58 -0
  160. package/docs/de/rc1-gate-matrix-ci-handoff.md +56 -0
  161. package/docs/de/rc1-migration-notes.md +69 -0
  162. package/docs/de/rc1-readiness.md +46 -0
  163. package/docs/de/release-owner-acceptance.md +56 -0
  164. package/docs/de/release-report-pack-dry-run-evidence.md +39 -0
  165. package/docs/de/rmt-action-effect-runtime.md +81 -0
  166. package/docs/de/rmt-app-platform-authoring.md +54 -0
  167. package/docs/de/rmt-app-platform-fixture.md +46 -0
  168. package/docs/de/rmt-app-platform-migration-guide.md +88 -0
  169. package/docs/de/rmt-app-platform-tooling.md +79 -0
  170. package/docs/de/rmt-component-template-primitives.md +57 -0
  171. package/docs/de/rmt-dom-descriptor-renderer.md +64 -0
  172. package/docs/de/rmt-dsl-authoring-polish.md +145 -0
  173. package/docs/de/rmt-event-routing-runtime.md +81 -0
  174. package/docs/de/rmt-first-demo-app.md +77 -0
  175. package/docs/de/rmt-first-xtend-apps.md +129 -0
  176. package/docs/de/rmt-kernel-panic-recovery-incident-handoff.md +61 -0
  177. package/docs/de/rmt-kernel-security-hardening-migration.md +50 -0
  178. package/docs/de/rmt-kernel-trusted-output-authoring.md +69 -0
  179. package/docs/de/rmt-language-server.md +234 -0
  180. package/docs/de/rmt-lifecycle-demo.md +24 -0
  181. package/docs/de/rmt-linter.md +140 -0
  182. package/docs/de/rmt-node-ssr-adapter.md +100 -0
  183. package/docs/de/rmt-php-ssr-adapter.md +120 -0
  184. package/docs/de/rmt-production-readiness.md +63 -0
  185. package/docs/de/rmt-state-selector-runtime.md +47 -0
  186. package/docs/de/rmt-surface-resource-graph-runtime.md +92 -0
  187. package/docs/de/rmt-tooling-release-gates.md +77 -0
  188. package/docs/de/rmt-vnext-authoring.md +170 -0
  189. package/docs/de/rmt-vnext-component-primitives.md +188 -0
  190. package/docs/de/rmt-vnext-cross-surface-events.md +68 -0
  191. package/docs/de/rmt-vnext-enterprise-mfe-handoff.md +70 -0
  192. package/docs/de/rmt-vnext-fabric-bridge-evidence.md +81 -0
  193. package/docs/de/rmt-vnext-migration-notes.md +62 -0
  194. package/docs/de/rmt-vnext-primitive-authoring-tooling.md +247 -0
  195. package/docs/de/rmt-vnext-primitive-grammar-design.md +289 -0
  196. package/docs/de/rmt-vnext-primitive-lowering.md +108 -0
  197. package/docs/de/rmt-vnext-primitive-migration.md +119 -0
  198. package/docs/de/rmt-vnext-primitive-parser-ast.md +76 -0
  199. package/docs/de/rmt-vnext-primitive-semantic-graph.md +118 -0
  200. package/docs/de/rmt-vnext-primitives-compiler-backlog.md +739 -0
  201. package/docs/de/rmt-vnext-release-handoff.md +83 -0
  202. package/docs/de/rmt-vnext-remote-surfaces.md +90 -0
  203. package/docs/de/rmt-vnext-source-to-sea-gate.md +612 -0
  204. package/docs/de/rmt-vnext-surface-registry-enterprise.md +76 -0
  205. package/docs/de/screenreader-signals.md +56 -0
  206. package/docs/de/supply-chain-gates.md +100 -0
  207. package/docs/de/surface-manager-authoring-guide.md +94 -0
  208. package/docs/de/surface-manager-browser-lab.md +45 -0
  209. package/docs/de/surface-manager-component-lab.md +43 -0
  210. package/docs/de/surface-manager-controller.md +66 -0
  211. package/docs/de/surface-manager-layout-engines.md +32 -0
  212. package/docs/de/surface-manager-lazy-hydration.md +63 -0
  213. package/docs/de/surface-manager-migration-guide.md +122 -0
  214. package/docs/de/surface-manager-native-rmt-surfaces.md +38 -0
  215. package/docs/de/surface-manager-overlay-bridge.md +53 -0
  216. package/docs/de/surface-manager-persistence.md +30 -0
  217. package/docs/de/surface-manager-quality-gates.md +51 -0
  218. package/docs/de/surface-manager-release-handoff.md +68 -0
  219. package/docs/de/surface-manager-remote-policy.md +54 -0
  220. package/docs/de/surface-manager-rmt-authoring.md +102 -0
  221. package/docs/de/surface-manager-route-lifecycle.md +59 -0
  222. package/docs/de/surface-manager-runtime-release-handoff.md +69 -0
  223. package/docs/de/surface-manager-side-panel-runtime.md +36 -0
  224. package/docs/de/surface-manager-stack-policy.md +39 -0
  225. package/docs/de/surface-manager-window-runtime.md +47 -0
  226. package/docs/de/surface-manager-workbench-fixture.md +43 -0
  227. package/docs/de/third-party-design-authoring.md +406 -0
  228. package/docs/de/trusted-dom-boundary-browser-proof.md +32 -0
  229. package/docs/de/trusted-dom-sanitizing.md +110 -0
  230. package/docs/de/type-exports.md +61 -0
  231. package/docs/de/typescript-components.md +63 -0
  232. package/docs/de/visual-browser-regression.md +83 -0
  233. package/docs/de/visual-owner-artifacts.md +46 -0
  234. package/docs/de/visual-snapshot-automation.md +87 -0
  235. package/docs/de/xtend-api-types.md +55 -0
  236. package/docs/de/xtend-builder-types.md +55 -0
  237. package/docs/de/xtend-catalog-types.md +44 -0
  238. package/docs/de/xtend-fabric-rmt-lane-mapping.md +143 -0
  239. package/docs/de/xtend-fabric.md +474 -0
  240. package/docs/de/xtend-loader-types.md +58 -0
  241. package/docs/de/xtend-loader.md +265 -0
  242. package/docs/de/xtend-policy-types.md +38 -0
  243. package/docs/de/xtend-rmt-types.md +40 -0
  244. package/docs/de/xtend-vendor-types.md +36 -0
  245. package/docs/de/xtendrmt-app-dsl.md +334 -0
  246. package/docs/de/xtendrmt-migration-guide.md +266 -0
  247. package/docs/de/xtendrmt-native-authoring.md +333 -0
  248. package/docs/de/xtendrmt-overview.md +109 -0
  249. package/docs/de/xtendrmt-parsedown-scheduling.md +301 -0
  250. package/docs/de/xtendrmt-runtime-bridge.md +155 -0
  251. package/docs/en/README.md +163 -0
  252. package/docs/en/XTend-ADR.md +221 -0
  253. package/docs/en/a11y-keyboard-smokes.md +68 -0
  254. package/docs/en/about.md +25 -0
  255. package/docs/en/api.md +171 -0
  256. package/docs/en/best-practices.md +125 -0
  257. package/docs/en/changelog.md +104 -0
  258. package/docs/en/component-catalog-coverage.md +104 -0
  259. package/docs/en/component-lab.md +103 -0
  260. package/docs/en/component-long-tail-migration.md +41 -0
  261. package/docs/en/component-platform.md +243 -0
  262. package/docs/en/component-ux-app-authoring.md +118 -0
  263. package/docs/en/component-ux-authoring.md +96 -0
  264. package/docs/en/component-ux-gates.md +45 -0
  265. package/docs/en/components/x-rmt-lifecycle-demo-build.md +75 -0
  266. package/docs/en/components/xalert.md +94 -0
  267. package/docs/en/components/xbutton.md +118 -0
  268. package/docs/en/components/xcalendar.md +95 -0
  269. package/docs/en/components/xcards.md +139 -0
  270. package/docs/en/components/xcheckbox.md +118 -0
  271. package/docs/en/components/xcode.md +153 -0
  272. package/docs/en/components/xdialog.md +108 -0
  273. package/docs/en/components/xdrawer.md +110 -0
  274. package/docs/en/components/xfooter.md +138 -0
  275. package/docs/en/components/xform.md +147 -0
  276. package/docs/en/components/xheader.md +308 -0
  277. package/docs/en/components/xhero.md +157 -0
  278. package/docs/en/components/xicon.md +149 -0
  279. package/docs/en/components/xinput.md +147 -0
  280. package/docs/en/components/xlightbox.md +113 -0
  281. package/docs/en/components/xlink.md +130 -0
  282. package/docs/en/components/xmasonry.md +136 -0
  283. package/docs/en/components/xmenu.md +185 -0
  284. package/docs/en/components/xmodal.md +102 -0
  285. package/docs/en/components/xplayer.md +114 -0
  286. package/docs/en/components/xpopover.md +87 -0
  287. package/docs/en/components/xprogress.md +73 -0
  288. package/docs/en/components/xradio.md +119 -0
  289. package/docs/en/components/xrouter.md +260 -0
  290. package/docs/en/components/xsection.md +136 -0
  291. package/docs/en/components/xselect.md +122 -0
  292. package/docs/en/components/xsidepanel.md +48 -0
  293. package/docs/en/components/xspinner.md +118 -0
  294. package/docs/en/components/xstate.md +163 -0
  295. package/docs/en/components/xstatus.md +71 -0
  296. package/docs/en/components/xsummary.md +90 -0
  297. package/docs/en/components/xsurfacemanager.md +42 -0
  298. package/docs/en/components/xsurfacewindow.md +31 -0
  299. package/docs/en/components/xtabs.md +187 -0
  300. package/docs/en/components/xtextarea.md +115 -0
  301. package/docs/en/components/xtheme.md +203 -0
  302. package/docs/en/components/xtoast.md +78 -0
  303. package/docs/en/components/xtooltip.md +85 -0
  304. package/docs/en/components/xtype.md +91 -0
  305. package/docs/en/components/xutils.md +161 -0
  306. package/docs/en/components/xwriter.md +106 -0
  307. package/docs/en/components.md +151 -0
  308. package/docs/en/conditional-network-evidence-ci.md +38 -0
  309. package/docs/en/conditional-network-evidence.md +50 -0
  310. package/docs/en/core-migration-guide.md +110 -0
  311. package/docs/en/design-tokens.md +137 -0
  312. package/docs/en/docs-rmt-production-hardening.md +31 -0
  313. package/docs/en/enterprise-adoption.md +413 -0
  314. package/docs/en/enterprise-component-flex-release-handoff.md +129 -0
  315. package/docs/en/epic10-platform-gates.md +62 -0
  316. package/docs/en/epic10-release-handoff.md +81 -0
  317. package/docs/en/epic11-enterprise-ux-handoff.md +70 -0
  318. package/docs/en/epic12-rc0-handoff.md +61 -0
  319. package/docs/en/epic18-media-manager-vendor-upstream.md +232 -0
  320. package/docs/en/epic18-rmt-app-platform-release-handoff.md +60 -0
  321. package/docs/en/epic18-vendor-bugfixes.md +29 -0
  322. package/docs/en/existing-component-metadata.md +67 -0
  323. package/docs/en/hydration-performance-closure.md +34 -0
  324. package/docs/en/hydration-policies.md +75 -0
  325. package/docs/en/known-residual-triage.md +22 -0
  326. package/docs/en/manifest-import-policy.md +81 -0
  327. package/docs/en/manifest.md +135 -0
  328. package/docs/en/motion-contrast.md +67 -0
  329. package/docs/en/package-export-lock.md +44 -0
  330. package/docs/en/performance-measurements.md +106 -0
  331. package/docs/en/performance-regression.md +89 -0
  332. package/docs/en/performance.md +132 -0
  333. package/docs/en/previews/README.md +17 -0
  334. package/docs/en/prod-browser-csp-smokes.md +40 -0
  335. package/docs/en/public-component-types.md +79 -0
  336. package/docs/en/quick-start-guide.md +189 -0
  337. package/docs/en/rc0-adoption-guide.md +102 -0
  338. package/docs/en/rc0-gate-matrix.md +58 -0
  339. package/docs/en/rc1-gate-matrix-ci-handoff.md +56 -0
  340. package/docs/en/rc1-migration-notes.md +69 -0
  341. package/docs/en/rc1-readiness.md +46 -0
  342. package/docs/en/release-owner-acceptance.md +56 -0
  343. package/docs/en/release-report-pack-dry-run-evidence.md +39 -0
  344. package/docs/en/rmt-action-effect-runtime.md +101 -0
  345. package/docs/en/rmt-app-platform-authoring.md +47 -0
  346. package/docs/en/rmt-app-platform-fixture.md +35 -0
  347. package/docs/en/rmt-app-platform-migration-guide.md +75 -0
  348. package/docs/en/rmt-app-platform-tooling.md +58 -0
  349. package/docs/en/rmt-component-template-primitives.md +49 -0
  350. package/docs/en/rmt-dom-descriptor-renderer.md +54 -0
  351. package/docs/en/rmt-dsl-authoring-polish.md +143 -0
  352. package/docs/en/rmt-event-routing-runtime.md +98 -0
  353. package/docs/en/rmt-first-demo-app.md +87 -0
  354. package/docs/en/rmt-first-xtend-apps.md +127 -0
  355. package/docs/en/rmt-kernel-panic-recovery-incident-handoff.md +60 -0
  356. package/docs/en/rmt-kernel-security-hardening-migration.md +49 -0
  357. package/docs/en/rmt-kernel-trusted-output-authoring.md +68 -0
  358. package/docs/en/rmt-language-server.md +243 -0
  359. package/docs/en/rmt-lifecycle-demo.md +23 -0
  360. package/docs/en/rmt-linter.md +146 -0
  361. package/docs/en/rmt-node-ssr-adapter.md +99 -0
  362. package/docs/en/rmt-php-ssr-adapter.md +118 -0
  363. package/docs/en/rmt-production-readiness.md +63 -0
  364. package/docs/en/rmt-state-selector-runtime.md +34 -0
  365. package/docs/en/rmt-surface-resource-graph-runtime.md +68 -0
  366. package/docs/en/rmt-tooling-release-gates.md +77 -0
  367. package/docs/en/rmt-vnext-authoring.md +102 -0
  368. package/docs/en/rmt-vnext-component-primitives.md +185 -0
  369. package/docs/en/rmt-vnext-cross-surface-events.md +59 -0
  370. package/docs/en/rmt-vnext-enterprise-mfe-handoff.md +62 -0
  371. package/docs/en/rmt-vnext-fabric-bridge-evidence.md +64 -0
  372. package/docs/en/rmt-vnext-migration-notes.md +62 -0
  373. package/docs/en/rmt-vnext-primitive-authoring-tooling.md +174 -0
  374. package/docs/en/rmt-vnext-primitive-grammar-design.md +268 -0
  375. package/docs/en/rmt-vnext-primitive-lowering.md +91 -0
  376. package/docs/en/rmt-vnext-primitive-migration.md +93 -0
  377. package/docs/en/rmt-vnext-primitive-parser-ast.md +59 -0
  378. package/docs/en/rmt-vnext-primitive-semantic-graph.md +103 -0
  379. package/docs/en/rmt-vnext-primitives-compiler-backlog.md +327 -0
  380. package/docs/en/rmt-vnext-release-handoff.md +83 -0
  381. package/docs/en/rmt-vnext-remote-surfaces.md +81 -0
  382. package/docs/en/rmt-vnext-source-to-sea-gate.md +482 -0
  383. package/docs/en/rmt-vnext-surface-registry-enterprise.md +68 -0
  384. package/docs/en/screenreader-signals.md +56 -0
  385. package/docs/en/supply-chain-gates.md +106 -0
  386. package/docs/en/surface-manager-authoring-guide.md +94 -0
  387. package/docs/en/surface-manager-browser-lab.md +45 -0
  388. package/docs/en/surface-manager-component-lab.md +43 -0
  389. package/docs/en/surface-manager-controller.md +66 -0
  390. package/docs/en/surface-manager-layout-engines.md +32 -0
  391. package/docs/en/surface-manager-lazy-hydration.md +63 -0
  392. package/docs/en/surface-manager-migration-guide.md +113 -0
  393. package/docs/en/surface-manager-native-rmt-surfaces.md +38 -0
  394. package/docs/en/surface-manager-overlay-bridge.md +53 -0
  395. package/docs/en/surface-manager-persistence.md +30 -0
  396. package/docs/en/surface-manager-quality-gates.md +51 -0
  397. package/docs/en/surface-manager-release-handoff.md +68 -0
  398. package/docs/en/surface-manager-remote-policy.md +54 -0
  399. package/docs/en/surface-manager-rmt-authoring.md +89 -0
  400. package/docs/en/surface-manager-route-lifecycle.md +59 -0
  401. package/docs/en/surface-manager-runtime-release-handoff.md +69 -0
  402. package/docs/en/surface-manager-side-panel-runtime.md +36 -0
  403. package/docs/en/surface-manager-stack-policy.md +39 -0
  404. package/docs/en/surface-manager-window-runtime.md +47 -0
  405. package/docs/en/surface-manager-workbench-fixture.md +43 -0
  406. package/docs/en/third-party-design-authoring.md +406 -0
  407. package/docs/en/trusted-dom-boundary-browser-proof.md +32 -0
  408. package/docs/en/trusted-dom-sanitizing.md +124 -0
  409. package/docs/en/type-exports.md +61 -0
  410. package/docs/en/typescript-components.md +63 -0
  411. package/docs/en/visual-browser-regression.md +83 -0
  412. package/docs/en/visual-owner-artifacts.md +46 -0
  413. package/docs/en/visual-snapshot-automation.md +87 -0
  414. package/docs/en/xtend-api-types.md +55 -0
  415. package/docs/en/xtend-builder-types.md +55 -0
  416. package/docs/en/xtend-catalog-types.md +44 -0
  417. package/docs/en/xtend-fabric-rmt-lane-mapping.md +143 -0
  418. package/docs/en/xtend-fabric.md +474 -0
  419. package/docs/en/xtend-loader-types.md +58 -0
  420. package/docs/en/xtend-loader.md +265 -0
  421. package/docs/en/xtend-policy-types.md +38 -0
  422. package/docs/en/xtend-rmt-types.md +40 -0
  423. package/docs/en/xtend-vendor-types.md +36 -0
  424. package/docs/en/xtendrmt-app-dsl.md +331 -0
  425. package/docs/en/xtendrmt-migration-guide.md +256 -0
  426. package/docs/en/xtendrmt-native-authoring.md +336 -0
  427. package/docs/en/xtendrmt-overview.md +63 -0
  428. package/docs/en/xtendrmt-parsedown-scheduling.md +301 -0
  429. package/docs/en/xtendrmt-runtime-bridge.md +155 -0
  430. package/docs/enterprise-adoption.md +4 -2
  431. package/docs/epic18-media-manager-vendor-upstream.md +318 -0
  432. package/docs/epic18-rmt-app-platform-release-handoff.md +67 -0
  433. package/docs/epic18-vendor-bugfixes.md +34 -0
  434. package/docs/index.php +1056 -109
  435. package/docs/manifest.md +8 -2
  436. package/docs/menu.json +986 -133
  437. package/docs/package-export-lock.md +2 -2
  438. package/docs/public-component-types.md +2 -2
  439. package/docs/quick-start-guide.md +126 -58
  440. package/docs/rmt-action-effect-runtime.md +101 -0
  441. package/docs/rmt-app-platform-authoring.md +54 -0
  442. package/docs/rmt-app-platform-fixture.md +46 -0
  443. package/docs/rmt-app-platform-migration-guide.md +88 -0
  444. package/docs/rmt-app-platform-tooling.md +79 -0
  445. package/docs/rmt-component-template-primitives.md +57 -0
  446. package/docs/rmt-dom-descriptor-renderer.md +64 -0
  447. package/docs/rmt-dsl-authoring-polish.md +67 -44
  448. package/docs/rmt-event-routing-runtime.md +98 -0
  449. package/docs/rmt-first-demo-app.md +2 -2
  450. package/docs/rmt-first-xtend-apps.md +70 -46
  451. package/docs/rmt-language-server.md +61 -4
  452. package/docs/rmt-lifecycle-demo.md +1 -2
  453. package/docs/rmt-node-ssr-adapter.md +144 -0
  454. package/docs/rmt-php-ssr-adapter.md +158 -0
  455. package/docs/rmt-state-selector-runtime.md +47 -0
  456. package/docs/rmt-surface-resource-graph-runtime.md +92 -0
  457. package/docs/rmt-vnext-authoring.md +128 -18
  458. package/docs/rmt-vnext-component-primitives.md +188 -0
  459. package/docs/rmt-vnext-fabric-bridge-evidence.md +81 -0
  460. package/docs/rmt-vnext-primitive-authoring-tooling.md +247 -0
  461. package/docs/rmt-vnext-primitive-grammar-design.md +289 -0
  462. package/docs/rmt-vnext-primitive-lowering.md +108 -0
  463. package/docs/rmt-vnext-primitive-migration.md +119 -0
  464. package/docs/rmt-vnext-primitive-parser-ast.md +76 -0
  465. package/docs/rmt-vnext-primitive-semantic-graph.md +118 -0
  466. package/docs/rmt-vnext-primitives-compiler-backlog.md +742 -0
  467. package/docs/rmt-vnext-release-handoff.md +14 -0
  468. package/docs/rmt-vnext-source-to-sea-gate.md +629 -0
  469. package/docs/surface-manager-migration-guide.md +34 -6
  470. package/docs/surface-manager-overlay-bridge.md +9 -4
  471. package/docs/surface-manager-rmt-authoring.md +50 -34
  472. package/docs/surface-manager-workbench-fixture.md +1 -2
  473. package/docs/third-party-design-authoring.md +1 -1
  474. package/docs/type-exports.md +3 -3
  475. package/docs/utils/pageloader.js +811 -62
  476. package/docs/visual-browser-regression.md +1 -1
  477. package/docs/xtend-rmt-types.md +3 -2
  478. package/docs/xtendrmt-app-dsl.md +187 -122
  479. package/docs/xtendrmt-docs-shell-vnext.rmt +165 -0
  480. package/docs/xtendrmt-migration-guide.md +48 -17
  481. package/docs/xtendrmt-native-authoring.md +213 -217
  482. package/docs/xtendrmt-overview.md +81 -61
  483. package/docs/xtendrmt-parsedown-scheduling.md +23 -8
  484. package/fabric/package.json +1 -1
  485. package/package.json +684 -21
  486. package/tools/package.json +5 -1
  487. package/tools/rmt-editor/vscode/README.md +72 -5
  488. package/tools/rmt-editor/vscode/XTend-Logo.png +0 -0
  489. package/tools/rmt-editor/vscode/extension.d.ts +33 -0
  490. package/tools/rmt-editor/vscode/extension.js +1816 -7
  491. package/tools/rmt-editor/vscode/language-configuration.json +2 -1
  492. package/tools/rmt-editor/vscode/package.json +193 -2
  493. package/tools/rmt-editor/vscode/snippets/rmt.code-snippets +41 -0
  494. package/tools/rmt-editor/vscode/syntaxes/rmt.tmLanguage.json +103 -1
  495. package/tools/rmt-editor/vscode/templates/launch.json +70 -0
  496. package/tools/rmt-editor/vscode/templates/tasks.json +172 -0
  497. package/tools/rmt-editor/vscode/xtend-rmt-language-0.0.0-enterprise-readiness.vsix +0 -0
  498. package/tools/rmt-language/app-platform-tooling.d.ts +128 -0
  499. package/tools/rmt-language/app-platform-tooling.js +677 -0
  500. package/tools/rmt-language/completions.d.ts +5 -0
  501. package/tools/rmt-language/completions.js +185 -3
  502. package/tools/rmt-language/diagnostics.js +54 -0
  503. package/tools/rmt-language/hover.js +36 -0
  504. package/tools/rmt-language/rmt-tooling-public-types.d.ts +7 -0
  505. package/tools/rmt-language/rules/app-platform-policy.js +39 -0
  506. package/tools/rmt-language/rules/index.js +5 -1
  507. package/tools/rmt-language/semantic-graph.d.ts +6 -0
  508. package/tools/rmt-language/semantic-graph.js +928 -0
  509. package/tools/rmt-language/snippets/index.js +44 -0
  510. package/tools/rmt-language/snippets/rmt.code-snippets +41 -0
  511. package/tools/rmt-language/vnext-compatibility.d.ts +10 -0
  512. package/tools/rmt-language/vnext-compatibility.js +642 -0
  513. package/tools/rmt-language/vnext-compiler.d.ts +5 -0
  514. package/tools/rmt-language/vnext-compiler.js +863 -17
  515. package/tools/rmt-language/vnext-parser.js +725 -9
  516. package/tools/rmt-language/vnext-release.d.ts +1 -0
  517. package/tools/rmt-language/vnext-release.js +20 -0
  518. package/tools/rmt-language/vnext-source-to-sea.d.ts +33 -0
  519. package/tools/rmt-language/vnext-source-to-sea.js +2227 -0
  520. package/tools/rmt-language/vnext-surfaces.js +111 -52
  521. package/tools/rmt-language/vnext-tooling.d.ts +19 -1
  522. package/tools/rmt-language/vnext-tooling.js +1247 -5
  523. package/tools/rmt-language-server/protocol.js +3 -0
  524. package/tools/rmt-language-server/server.d.ts +2 -0
  525. package/tools/rmt-language-server/server.js +176 -22
  526. package/tools/rmt-linter/cli.d.ts +2 -0
  527. package/tools/rmt-linter/cli.js +62 -0
  528. package/xtend-builder/generators/registry.js +11 -0
  529. package/xtend-builder/generators/rmt-app-platform.js +239 -0
  530. package/xtend-builder/generators/rmt-lifecycle-demo.js +3 -11
  531. package/xtend-builder/lib/cli.js +38 -0
  532. package/xtend-builder/package.json +3 -3
  533. package/xtend-builder/scaffold.config.js +29 -2
  534. package/xtend.css +49 -2
  535. package/xtendrmt/package.json +49 -1
  536. package/xtendrmt/rmt-action-effect-runtime.d.ts +126 -0
  537. package/xtendrmt/rmt-action-effect-runtime.js +494 -0
  538. package/xtendrmt/rmt-component-capability-registry.d.ts +180 -0
  539. package/xtendrmt/rmt-component-capability-registry.js +636 -0
  540. package/xtendrmt/rmt-core.d.ts +6 -0
  541. package/xtendrmt/rmt-core.esm.js +32 -6
  542. package/xtendrmt/rmt-dom-descriptor-renderer.d.ts +107 -0
  543. package/xtendrmt/rmt-dom-descriptor-renderer.js +1066 -0
  544. package/xtendrmt/rmt-event-routing-runtime.d.ts +144 -0
  545. package/xtendrmt/rmt-event-routing-runtime.js +666 -0
  546. package/xtendrmt/rmt-lifecycle-demo.app.js +2 -2
  547. package/xtendrmt/rmt-lifecycle-demo.core.json +4 -0
  548. package/xtendrmt/rmt-lifecycle-demo.rmt-build.app.js +1 -1
  549. package/xtendrmt/rmt-lifecycle-demo.rmt-build.scaffold.json +2 -2
  550. package/xtendrmt/rmt-lifecycle-demo.scaffold.json +4 -4
  551. package/xtendrmt/rmt-native-shell-runtime.d.ts +77 -0
  552. package/xtendrmt/rmt-native-shell-runtime.js +309 -0
  553. package/xtendrmt/rmt-node-ssr-adapter.d.ts +197 -0
  554. package/xtendrmt/rmt-node-ssr-adapter.js +1006 -0
  555. package/xtendrmt/rmt-php-ssr-adapter.php +976 -0
  556. package/xtendrmt/rmt-runtime.browser.js +32 -6
  557. package/xtendrmt/rmt-runtime.esm.js +32 -6
  558. package/xtendrmt/rmt-state-selector-runtime.d.ts +166 -0
  559. package/xtendrmt/rmt-state-selector-runtime.js +866 -0
  560. package/xtendrmt/rmt-surface-resource-graph-runtime.d.ts +224 -0
  561. package/xtendrmt/rmt-surface-resource-graph-runtime.js +932 -0
  562. package/xtendrmt/rmt-vnext-enterprise-mfe-demo.core.json +3 -0
  563. package/xtendrmt/rmt-vnext-reference-demo.core.json +3 -0
  564. package/xtendrmt/xtendrmt-bestcase-demo.core.json +3420 -372
  565. package/xtendrmt/xtendrmt-bestcase-demo.js +424 -8
  566. package/xtendrmt/xtendrmt-bestcase-demo.rmt +214 -6
package/docs/index.php CHANGED
@@ -9,13 +9,36 @@ if (function_exists('header_remove')) {
9
9
 
10
10
  // --- Konfiguration ---
11
11
  $docsRoot = __DIR__;
12
+ $repoRoot = realpath($docsRoot . '/..') ?: dirname($docsRoot);
12
13
  $componentsDir = $docsRoot . '/components';
13
14
  $utilsDir = $docsRoot . '/utils';
14
15
  $parsedownFile = $utilsDir . '/parsedown.php';
15
16
  $rmtPilotDocument = 'xtendrmt-parsedown-docs.rmt';
16
17
  $rmtPilotDocumentPath = $docsRoot . '/' . $rmtPilotDocument;
18
+ $docsRmtVNextDocument = 'xtendrmt-docs-shell-vnext.rmt';
19
+ $docsRmtVNextDocumentPath = $docsRoot . '/' . $docsRmtVNextDocument;
20
+ $rmtPhpSsrAdapterFile = $repoRoot . '/xtendrmt/rmt-php-ssr-adapter.php';
21
+ $docsRmtCompilerBridgePath = $repoRoot . '/scripts/compile_rmt_vnext_bridge.js';
17
22
  $rmtPilotDocumentData = null;
18
23
  $rmtPilotDocumentJson = '{}';
24
+ $docsSsrPrehydration = null;
25
+ $docsSsrEndpoint = '';
26
+ $docsDefaultLocale = 'de';
27
+ $docsFallbackLocale = 'de';
28
+ $docsAvailableLocales = [
29
+ 'de' => [
30
+ 'label' => 'Deutsch',
31
+ 'nativeLabel' => 'Deutsch',
32
+ 'htmlLang' => 'de',
33
+ 'titleSuffix' => 'XTend Dokumentation'
34
+ ],
35
+ 'en' => [
36
+ 'label' => 'English',
37
+ 'nativeLabel' => 'English',
38
+ 'htmlLang' => 'en',
39
+ 'titleSuffix' => 'XTend Documentation'
40
+ ]
41
+ ];
19
42
 
20
43
  function docsAssetMap($docsRoot) {
21
44
  return [
@@ -162,6 +185,9 @@ $xtendAssetVersion = xtendAssetVersion([
162
185
  __DIR__ . '/../docs/utils/pageloader.js',
163
186
  __DIR__ . '/../docs/utils/fabric-runtime.js',
164
187
  __DIR__ . '/../docs/xtendrmt-parsedown-docs.rmt',
188
+ __DIR__ . '/../docs/xtendrmt-docs-shell-vnext.rmt',
189
+ __DIR__ . '/../scripts/compile_rmt_vnext_bridge.js',
190
+ __DIR__ . '/../xtendrmt/rmt-php-ssr-adapter.php',
165
191
  __DIR__ . '/../api.js',
166
192
  ]);
167
193
  $xtendAssetVersionAttr = htmlspecialchars($xtendAssetVersion, ENT_QUOTES, 'UTF-8');
@@ -175,6 +201,7 @@ $docsLightboxLogoUrl = htmlspecialchars(docsAssetUrl('xtend-logo.png', $xtendAss
175
201
  // Alle Markdown-Dateien finden (rekursiv)
176
202
  function findMarkdownFiles($dir, $base = '') {
177
203
  $files = [];
204
+ if (!is_dir($dir)) return $files;
178
205
  foreach (scandir($dir) as $file) {
179
206
  if ($file === '.' || $file === '..') continue;
180
207
  $path = "$dir/$file";
@@ -188,7 +215,53 @@ function findMarkdownFiles($dir, $base = '') {
188
215
  return $files;
189
216
  }
190
217
 
191
- $mdFiles = findMarkdownFiles($docsRoot);
218
+ function docsNormalizeLocale($locale, $availableLocales, $fallbackLocale = 'de') {
219
+ $candidate = strtolower(trim((string) $locale));
220
+ $candidate = preg_replace('/[^a-z-]/', '', $candidate);
221
+ if (isset($availableLocales[$candidate])) return $candidate;
222
+ $short = substr($candidate, 0, 2);
223
+ if (isset($availableLocales[$short])) return $short;
224
+ return isset($availableLocales[$fallbackLocale]) ? $fallbackLocale : array_key_first($availableLocales);
225
+ }
226
+
227
+ function docsSplitLocalizedPath($value, $availableLocales) {
228
+ $path = trim((string) $value);
229
+ $path = preg_replace('/^#\\/?/', '', $path);
230
+ $path = preg_replace('/^\\/+/', '', $path);
231
+ $path = preg_replace('/\\?.*$/', '', $path);
232
+ if ($path === '' || $path === '/') {
233
+ return ['locale' => null, 'slug' => 'readme'];
234
+ }
235
+ $parts = explode('/', $path, 2);
236
+ $first = strtolower($parts[0] ?? '');
237
+ if (isset($availableLocales[$first])) {
238
+ return ['locale' => $first, 'slug' => $parts[1] ?? 'readme'];
239
+ }
240
+ return ['locale' => null, 'slug' => $path];
241
+ }
242
+
243
+ function docsLocaleTitleSuffix($locale, $availableLocales) {
244
+ return $availableLocales[$locale]['titleSuffix'] ?? 'XTend Dokumentation';
245
+ }
246
+
247
+ function docsBuildLocalizedMarkdownFiles($docsRoot, $availableLocales, $fallbackLocale) {
248
+ $localized = [];
249
+ foreach ($availableLocales as $locale => $config) {
250
+ $localeRoot = $docsRoot . '/' . $locale;
251
+ $localized[$locale] = findMarkdownFiles($localeRoot);
252
+ }
253
+ if (empty($localized[$fallbackLocale])) {
254
+ $rootFiles = findMarkdownFiles($docsRoot);
255
+ $localized[$fallbackLocale] = array_filter($rootFiles, function($path) use ($availableLocales) {
256
+ $first = explode('/', (string) $path, 2)[0] ?? '';
257
+ return !isset($availableLocales[$first]);
258
+ }, ARRAY_FILTER_USE_KEY);
259
+ }
260
+ return $localized;
261
+ }
262
+
263
+ $localizedMdFiles = docsBuildLocalizedMarkdownFiles($docsRoot, $docsAvailableLocales, $docsFallbackLocale);
264
+ $mdFiles = $localizedMdFiles[$docsDefaultLocale] ?? [];
192
265
 
193
266
  // Slug-Generierung: z.B. components/xalert.md => components-xalert
194
267
  function slugify($path) {
@@ -278,9 +351,10 @@ function docsExtractMarkdownDescription($markdown, $fallbackTitle) {
278
351
  }
279
352
 
280
353
  function docsBuildRouteRecord($slug, $rel, $pageMeta) {
354
+ $locale = $pageMeta['locale'] ?? 'de';
281
355
  return [
282
356
  'id' => docsRouteIdFromSlug($slug),
283
- 'path' => '/' . $slug,
357
+ 'path' => '/' . $locale . '/' . $slug,
284
358
  'router' => 'xtend.xrouter',
285
359
  'component' => 'docs.page',
286
360
  'title' => $pageMeta['title'],
@@ -299,7 +373,13 @@ function docsBuildRouteRecord($slug, $rel, $pageMeta) {
299
373
  'policy' => 'visible'
300
374
  ],
301
375
  'metadata' => [
302
- 'source' => 'docs/' . $rel,
376
+ 'source' => $pageMeta['source'],
377
+ 'slug' => $slug,
378
+ 'locale' => $locale,
379
+ 'requestedLocale' => $pageMeta['requestedLocale'] ?? $locale,
380
+ 'resolvedLocale' => $pageMeta['resolvedLocale'] ?? $locale,
381
+ 'fallbackLocale' => $pageMeta['fallbackLocale'] ?? 'de',
382
+ 'translationAvailable' => $pageMeta['translationAvailable'] ?? true,
303
383
  'shellTemplate' => $pageMeta['shellTemplate'],
304
384
  'searchTemplate' => $pageMeta['searchTemplate'],
305
385
  'contentKind' => $pageMeta['contentKind'],
@@ -316,23 +396,33 @@ function docsBuildRouteRecord($slug, $rel, $pageMeta) {
316
396
  ];
317
397
  }
318
398
 
319
- function docsBuildPageMeta($slug, $rel, $markdown) {
399
+ function docsBuildPageMeta($slug, $rel, $markdown, $locale = 'de', $requestedLocale = null, $translationAvailable = true) {
400
+ global $docsAvailableLocales, $docsFallbackLocale;
320
401
  $title = docsExtractMarkdownTitle($markdown, $rel);
321
402
  $description = docsExtractMarkdownDescription($markdown, $title);
403
+ $locale = docsNormalizeLocale($locale, $docsAvailableLocales, $docsFallbackLocale);
404
+ $requestedLocale = docsNormalizeLocale($requestedLocale ?? $locale, $docsAvailableLocales, $docsFallbackLocale);
405
+ $titleSuffix = docsLocaleTitleSuffix($locale, $docsAvailableLocales);
322
406
  $keywords = [
323
407
  'xtend',
324
- 'dokumentation',
408
+ $locale === 'en' ? 'documentation' : 'dokumentation',
325
409
  str_replace('-', ' ', $slug)
326
410
  ];
327
411
  $pageMeta = [
328
412
  'schema' => 'xtend.docs.parsedown-rmt-page.v1',
329
- 'source' => 'docs/' . $rel,
413
+ 'source' => 'docs/' . $locale . '/' . $rel,
414
+ 'slug' => $slug,
415
+ 'locale' => $locale,
416
+ 'requestedLocale' => $requestedLocale,
417
+ 'resolvedLocale' => $locale,
418
+ 'fallbackLocale' => $docsFallbackLocale,
419
+ 'translationAvailable' => (bool) $translationAvailable,
330
420
  'routeId' => docsRouteIdFromSlug($slug),
331
- 'path' => '/' . $slug,
421
+ 'path' => '/' . $locale . '/' . $slug,
332
422
  'router' => 'xtend.xrouter',
333
423
  'title' => $title,
334
- 'documentTitle' => $title . ' | XTend Dokumentation',
335
- 'titleTemplate' => '{{title}} | XTend Dokumentation',
424
+ 'documentTitle' => $title . ' | ' . $titleSuffix,
425
+ 'titleTemplate' => '{{title}} | ' . $titleSuffix,
336
426
  'metaDescription' => $description,
337
427
  'metaKeywords' => $keywords,
338
428
  'template' => 'docs.' . $slug . '.markdown',
@@ -415,10 +505,16 @@ function docsRouteAttrValue($value) {
415
505
  return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
416
506
  }
417
507
 
418
- function docsRenderXRoute($route, $pathOverride = null) {
508
+ function docsRouteAttributes($route, $pathOverride = null) {
419
509
  global $xtendAssetVersionAttr;
420
510
  $metadata = $route['metadata'] ?? [];
421
- $attrs = [
511
+ $routeId = $route['id'] ?? '';
512
+ $routeRef = $metadata['slug'] ?? $routeId;
513
+ $metaKeywords = $route['metaKeywords'] ?? ($metadata['seo']['keywords'] ?? []);
514
+ if (is_array($metaKeywords)) {
515
+ $metaKeywords = implode(', ', $metaKeywords);
516
+ }
517
+ return [
422
518
  'path' => $pathOverride ?? ($route['path'] ?? ''),
423
519
  'component' => 'xtend-doc-page',
424
520
  'import' => '/docs/utils/pageloader.js?v=' . $xtendAssetVersionAttr,
@@ -426,19 +522,23 @@ function docsRenderXRoute($route, $pathOverride = null) {
426
522
  'document-title' => $route['documentTitle'] ?? '',
427
523
  'title-template' => $route['titleTemplate'] ?? '',
428
524
  'meta-description' => $route['metaDescription'] ?? ($metadata['seo']['description'] ?? ''),
429
- 'meta-keywords' => $route['metaKeywords'] ?? ($metadata['seo']['keywords'] ?? []),
525
+ 'meta-keywords' => $metaKeywords,
430
526
  'skeleton' => $route['skeleton'] ?? 'article',
431
527
  'skeleton-lines' => $route['skeletonLines'] ?? 10,
432
528
  'skeleton-min-height' => $route['skeletonMinHeight'] ?? '26rem',
433
529
  'hydrate-schedule' => $route['hydration']['schedule'] ?? 'docs.page.hydrate',
434
530
  'data-rmt-route-id' => $route['id'] ?? '',
531
+ 'data-rmt-route-ref' => $routeRef,
435
532
  'data-rmt-router' => $route['router'] ?? 'xtend.xrouter',
436
533
  'data-rmt-component' => $route['component'] ?? 'docs.page',
437
534
  'data-rmt-template' => $route['template'] ?? '',
438
535
  'data-rmt-schedule' => $route['schedule'] ?? '',
439
- 'data-rmt-hydrate-schedule' => $route['hydration']['schedule'] ?? 'docs.page.hydrate',
440
- 'data-rmt-metadata' => json_encode($metadata, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)
536
+ 'data-rmt-hydrate-schedule' => $route['hydration']['schedule'] ?? 'docs.page.hydrate'
441
537
  ];
538
+ }
539
+
540
+ function docsRenderXRoute($route, $pathOverride = null) {
541
+ $attrs = docsRouteAttributes($route, $pathOverride);
442
542
  $parts = [];
443
543
  foreach ($attrs as $name => $value) {
444
544
  if ($value === null || $value === '' || $value === []) continue;
@@ -447,28 +547,677 @@ function docsRenderXRoute($route, $pathOverride = null) {
447
547
  return '<x-route ' . implode(' ', $parts) . '></x-route>';
448
548
  }
449
549
 
550
+ function docsJsonEncodeForHtml($value) {
551
+ return json_encode($value, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT);
552
+ }
553
+
554
+ function docsDescriptorText($text) {
555
+ return ['type' => 'text', 'text' => (string) $text];
556
+ }
557
+
558
+ function docsDescriptorElement($tag, $attributes = [], $children = []) {
559
+ return [
560
+ 'type' => 'element',
561
+ 'tag' => (string) $tag,
562
+ 'attributes' => array_filter($attributes, function ($value) {
563
+ return $value !== null && $value !== false && $value !== [];
564
+ }),
565
+ 'children' => array_values($children)
566
+ ];
567
+ }
568
+
569
+ function docsDescriptorComponent($tag, $attributes = [], $children = [], $extra = []) {
570
+ return array_replace_recursive([
571
+ 'type' => 'component',
572
+ 'tag' => (string) $tag,
573
+ 'attributes' => array_filter($attributes, function ($value) {
574
+ return $value !== null && $value !== false && $value !== [];
575
+ }),
576
+ 'children' => array_values($children)
577
+ ], $extra);
578
+ }
579
+
580
+ function docsRouteDescriptor($route, $pathOverride = null) {
581
+ return docsDescriptorElement('x-route', docsRouteAttributes($route, $pathOverride), []);
582
+ }
583
+
584
+ function docsCompactPageMetaForBootstrap($meta) {
585
+ if (!is_array($meta)) return $meta;
586
+ $compact = [];
587
+ foreach ([
588
+ 'schema',
589
+ 'source',
590
+ 'slug',
591
+ 'locale',
592
+ 'requestedLocale',
593
+ 'resolvedLocale',
594
+ 'fallbackLocale',
595
+ 'translationAvailable',
596
+ 'routeId',
597
+ 'path',
598
+ 'router',
599
+ 'title',
600
+ 'documentTitle',
601
+ 'titleTemplate',
602
+ 'metaDescription',
603
+ 'metaKeywords',
604
+ 'template',
605
+ 'shellFirst',
606
+ 'shellTemplate',
607
+ 'searchTemplate',
608
+ 'contentSlot',
609
+ 'contentKind',
610
+ 'adapter',
611
+ 'component',
612
+ 'markupClass',
613
+ 'trustBoundary',
614
+ 'lazyPayload',
615
+ 'skeletonLoader'
616
+ ] as $key) {
617
+ if (array_key_exists($key, $meta)) {
618
+ $compact[$key] = $meta[$key];
619
+ }
620
+ }
621
+ return $compact;
622
+ }
623
+
624
+ function docsCompactMetaMapForBootstrap($metaMap) {
625
+ if (!is_array($metaMap)) return $metaMap;
626
+ $compact = [];
627
+ foreach ($metaMap as $key => $value) {
628
+ $compact[$key] = is_array($value) ? docsCompactPageMetaForBootstrap($value) : $value;
629
+ }
630
+ return $compact;
631
+ }
632
+
633
+ function docsCompactLocalizedMetaForBootstrap($localizedMeta) {
634
+ if (!is_array($localizedMeta)) return $localizedMeta;
635
+ $compact = [];
636
+ foreach ($localizedMeta as $locale => $metaMap) {
637
+ $compact[$locale] = docsCompactMetaMapForBootstrap($metaMap);
638
+ }
639
+ return $compact;
640
+ }
641
+
642
+ function docsLoadComponentManifest($repoRoot) {
643
+ $manifestPath = rtrim((string) $repoRoot, '/') . '/components/manifest.json';
644
+ if (!is_readable($manifestPath)) return [];
645
+ $decoded = json_decode(file_get_contents($manifestPath), true);
646
+ return is_array($decoded) ? $decoded : [];
647
+ }
648
+
649
+ function docsFindRmtTemplate($document, $templateId) {
650
+ foreach (($document['templates'] ?? []) as $template) {
651
+ if (is_array($template) && (($template['id'] ?? null) === $templateId || ($template['qualifiedId'] ?? null) === $templateId)) {
652
+ return $template;
653
+ }
654
+ }
655
+ return null;
656
+ }
657
+
658
+ function docsBuildDocsRootShellDescriptor($allPagesMeta, $localizedAllPagesMeta, $fileToSlug, $docsAvailableLocales, $pageLocale, $docsDefaultLocale, $docsLogoUrl, $xtendAssetVersionAttr) {
659
+ global $page;
660
+ $ssrRoot = [
661
+ 'data-rmt-ssr-root' => 'docs.app.root-shell',
662
+ 'data-rmt-ssr-chunk' => 'rmt:docs.app.root-shell',
663
+ 'data-rmt-shell-prehydrated' => 'true',
664
+ 'data-rmt-hydration-mode' => 'server_prerender_hydrate',
665
+ 'data-rmt-contract' => 'xtend.docs.rmt-shell-primitives.v1'
666
+ ];
667
+ $routeChildren = [];
668
+ if (isset($allPagesMeta['readme']['route'])) {
669
+ $routeChildren[] = docsRouteDescriptor($allPagesMeta['readme']['route'], '/');
670
+ }
671
+ foreach ($localizedAllPagesMeta as $locale => $localePagesMeta) {
672
+ foreach ($localePagesMeta as $slug => $meta) {
673
+ $routeChildren[] = docsRouteDescriptor($meta['route'], '/' . $locale . '/' . $slug);
674
+ }
675
+ }
676
+ foreach ($fileToSlug as $rel => $slug) {
677
+ if (isset($allPagesMeta[$slug]['route'])) {
678
+ $routeChildren[] = docsRouteDescriptor($allPagesMeta[$slug]['route'], '/' . $slug);
679
+ }
680
+ }
681
+ $routeChildren[] = docsDescriptorElement('x-route', [
682
+ 'path' => '*',
683
+ 'component' => 'xtend-doc-page',
684
+ 'import' => '/docs/utils/pageloader.js?v=' . $xtendAssetVersionAttr,
685
+ 'title' => 'Seite nicht gefunden',
686
+ 'document-title' => 'Seite nicht gefunden | XTend Dokumentation',
687
+ 'meta-description' => 'Die angeforderte Dokumentationsseite wurde nicht gefunden.',
688
+ 'skeleton' => 'article',
689
+ 'skeleton-lines' => '8',
690
+ 'skeleton-min-height' => '20rem',
691
+ 'hydrate-schedule' => 'docs.page.hydrate',
692
+ 'data-rmt-route-id' => 'docs.notFound',
693
+ 'data-rmt-router' => 'xtend.xrouter',
694
+ 'data-rmt-component' => 'docs.page',
695
+ 'data-rmt-schedule' => 'docs.route.render',
696
+ 'data-rmt-hydrate-schedule' => 'docs.page.hydrate'
697
+ ], []);
698
+
699
+ $languageOptions = [];
700
+ foreach ($docsAvailableLocales as $locale => $localeConfig) {
701
+ $languageOptions[] = docsDescriptorElement('option', [
702
+ 'value' => $locale,
703
+ 'selected' => $locale === $pageLocale ? true : null
704
+ ], [docsDescriptorText($localeConfig['nativeLabel'] ?? strtoupper($locale))]);
705
+ }
706
+ $menuShell = docsDescriptorElement('div', [
707
+ 'slot' => 'nav',
708
+ 'class' => 'docs-menu-shell docs-menu-shell--ssr',
709
+ 'data-docs-menu-shell' => true,
710
+ 'data-rmt-menu-placeholder' => 'true',
711
+ 'data-rmt-shell-surface' => 'docs.header.nav',
712
+ 'role' => 'list',
713
+ 'aria-label' => $pageLocale === 'en' ? 'Documentation sections' : 'Dokumentationsbereiche'
714
+ ], [
715
+ docsDescriptorComponent('x-icon', [
716
+ 'class' => 'docs-nav-link-icon',
717
+ 'name' => docsMenuIconForSlug($page),
718
+ 'pack' => 'lucide',
719
+ 'decorative' => true,
720
+ 'size' => '1rem'
721
+ ], []),
722
+ docsDescriptorElement('span', [
723
+ 'class' => 'docs-menu-section-title docs-menu-section-title--ssr',
724
+ 'role' => 'listitem'
725
+ ], [
726
+ docsDescriptorText($pageLocale === 'en' ? 'Documentation menu' : 'Dokumentationsmenue')
727
+ ])
728
+ ]);
729
+
730
+ return [
731
+ 'type' => 'fragment',
732
+ 'children' => [
733
+ docsDescriptorComponent('x-theme', array_replace($ssrRoot, [
734
+ 'data-rmt-surface-id' => 'docs.root',
735
+ 'data-rmt-shell-surface' => 'docs.root'
736
+ ]), []),
737
+ docsDescriptorComponent('x-header', array_replace($ssrRoot, [
738
+ 'src' => $docsLogoUrl,
739
+ 'logo-size' => '48',
740
+ 'sticky' => true,
741
+ 'data-xtend-skeleton' => true,
742
+ 'data-xtend-layout-reserve' => 'header',
743
+ 'data-xtend-cls-anchor' => 'docs.header',
744
+ 'style' => '--xtend-skeleton-min-height: 4.75rem; --xtend-layout-reserved-block-size: 4.75rem; --header-reserved-block-size: 4.75rem;',
745
+ 'data-rmt-surface-id' => 'docs.header',
746
+ 'data-rmt-shell-surface' => 'docs.header'
747
+ ]), array_merge([
748
+ docsDescriptorElement('span', ['slot' => 'title'], [docsDescriptorText('XTend Dokumentation')]),
749
+ docsDescriptorElement('span', [
750
+ 'class' => 'docs-language-control',
751
+ 'slot' => 'actions',
752
+ 'data-docs-language-control' => true,
753
+ 'aria-label' => $pageLocale === 'en' ? 'Change language' : 'Sprache wechseln'
754
+ ], [
755
+ docsDescriptorComponent('x-icon', ['class' => 'docs-language-icon', 'name' => 'globe', 'pack' => 'lucide', 'decorative' => true, 'size' => '1.05rem'], []),
756
+ docsDescriptorComponent('x-select', [
757
+ 'id' => 'docs-language-select',
758
+ 'class' => 'docs-language-select',
759
+ 'label' => 'Sprache',
760
+ 'value' => $pageLocale,
761
+ 'data-docs-language-select' => true
762
+ ], $languageOptions),
763
+ docsDescriptorElement('span', ['class' => 'docs-language-status', 'data-docs-language-status' => true, 'role' => 'status', 'aria-live' => 'polite', 'hidden' => true], [
764
+ docsDescriptorElement('span', ['class' => 'docs-language-status-spinner', 'aria-hidden' => 'true'], []),
765
+ docsDescriptorElement('span', ['class' => 'docs-language-status-label', 'data-docs-language-status-label' => true], [
766
+ docsDescriptorText($pageLocale === 'en' ? 'Loading' : 'Laedt')
767
+ ])
768
+ ])
769
+ ]),
770
+ docsDescriptorComponent('x-button', [
771
+ 'id' => 'theme-toggle',
772
+ 'class' => 'docs-icon-button docs-theme-toggle',
773
+ 'slot' => 'actions',
774
+ 'type' => 'button',
775
+ 'variant' => 'secondary',
776
+ 'aria-label' => 'Dunkelmodus aktivieren',
777
+ 'title' => 'Dunkelmodus aktivieren',
778
+ 'aria-pressed' => 'false'
779
+ ], [
780
+ docsDescriptorComponent('x-icon', ['id' => 'theme-toggle-icon', 'name' => 'moon', 'pack' => 'core', 'decorative' => true, 'size' => '1.1rem'], []),
781
+ docsDescriptorElement('span', ['id' => 'theme-toggle-label', 'class' => 'docs-visually-hidden'], [docsDescriptorText('Dunkelmodus aktivieren')])
782
+ ])
783
+ ], [$menuShell])),
784
+ docsDescriptorComponent('x-hero', array_replace($ssrRoot, [
785
+ 'class' => 'docs-hero',
786
+ 'data-xtend-skeleton' => true,
787
+ 'background-light' => 'var(--docs-hero-bg-light)',
788
+ 'background-dark' => 'var(--docs-hero-bg-dark)',
789
+ 'font-color-light' => 'var(--docs-hero-text-light)',
790
+ 'font-color-dark' => 'var(--docs-hero-text-dark)',
791
+ 'overlay-light' => 'rgba(255, 255, 255, 0.16)',
792
+ 'overlay-dark' => 'rgba(0, 0, 0, 0.28)',
793
+ 'align' => 'block',
794
+ 'overlay' => true,
795
+ 'animate' => true,
796
+ 'vertical-align' => 'top',
797
+ 'data-xtend-layout-reserve' => 'hero',
798
+ 'data-xtend-cls-anchor' => 'docs.hero',
799
+ 'style' => '--xtend-skeleton-min-height: clamp(12rem, 30vw, 22rem); --xtend-layout-reserved-block-size: clamp(12rem, 30vw, 22rem); --hero-reserved-block-size: clamp(12rem, 30vw, 22rem);',
800
+ 'data-rmt-surface-id' => 'docs.hero',
801
+ 'data-rmt-shell-surface' => 'docs.hero'
802
+ ]), [
803
+ docsDescriptorElement('h1', [], [docsDescriptorText('XTend Developer Center')]),
804
+ docsDescriptorElement('p', [], [docsDescriptorText('Build with XTend today')])
805
+ ]),
806
+ docsDescriptorElement('main', array_replace($ssrRoot, [
807
+ 'data-rmt-surface-id' => 'docs.main',
808
+ 'data-rmt-shell-surface' => 'docs.router-host',
809
+ 'data-xtend-layout-reserve' => 'shell route',
810
+ 'data-xtend-cls-anchor' => 'docs.main',
811
+ 'style' => '--xtend-layout-reserved-block-size: var(--docs-route-reserved-block-size); --xtend-router-reserved-block-size: var(--docs-route-reserved-block-size);'
812
+ ]), [
813
+ docsDescriptorComponent('x-router', [
814
+ 'mode' => 'hash',
815
+ 'reuse-component' => true,
816
+ 'skeleton' => 'article',
817
+ 'skeleton-lines' => '10',
818
+ 'skeleton-min-height' => 'var(--docs-route-reserved-block-size)',
819
+ 'skeleton-label' => 'Dokumentation wird geladen',
820
+ 'data-xtend-skeleton' => true,
821
+ 'data-xtend-layout-reserve' => 'router route',
822
+ 'data-xtend-cls-anchor' => 'docs.router',
823
+ 'style' => '--xtend-skeleton-min-height: var(--docs-route-reserved-block-size); --xtend-layout-reserved-block-size: var(--docs-route-reserved-block-size); --xtend-router-reserved-block-size: var(--docs-route-reserved-block-size); --xtend-skeleton-width: calc(100% - var(--docs-viewport-gutter) - var(--docs-viewport-gutter)); --xtend-skeleton-max-width: calc(100% - var(--docs-viewport-gutter) - var(--docs-viewport-gutter)); --xtend-skeleton-margin-inline: var(--docs-viewport-gutter);',
824
+ 'document-title-template' => '{{title}} | XTend Dokumentation',
825
+ 'default-title' => 'XTend Dokumentation',
826
+ 'data-rmt-ssr-root' => 'docs.router',
827
+ 'data-rmt-ssr-chunk' => 'rmt:docs.router',
828
+ 'data-rmt-shell-prehydrated' => 'true',
829
+ 'data-rmt-hydration-mode' => 'server_prerender_hydrate',
830
+ 'data-rmt-surface-id' => 'docs.router',
831
+ 'data-rmt-shell-surface' => 'docs.router'
832
+ ], $routeChildren)
833
+ ]),
834
+ docsDescriptorComponent('x-footer', array_replace($ssrRoot, [
835
+ 'src' => $docsLogoUrl,
836
+ 'logo-size' => '32',
837
+ 'data-xtend-skeleton' => true,
838
+ 'data-xtend-layout-reserve' => 'footer',
839
+ 'data-xtend-cls-anchor' => 'docs.footer',
840
+ 'style' => '--xtend-skeleton-min-height: var(--docs-footer-reserved-block-size); --xtend-layout-reserved-block-size: var(--docs-footer-reserved-block-size); --footer-reserved-block-size: var(--docs-footer-reserved-block-size); --footer-logo-size: 32px;',
841
+ 'data-rmt-surface-id' => 'docs.footer',
842
+ 'data-rmt-shell-surface' => 'docs.footer'
843
+ ]), [
844
+ docsDescriptorElement('span', ['slot' => 'title'], [docsDescriptorText('(c) 2026 - CCS Networks | Powered by XRouter PHP Extension')])
845
+ ])
846
+ ]
847
+ ];
848
+ }
849
+
850
+ function docsFallbackSerializeDescriptor($descriptor) {
851
+ if (!is_array($descriptor)) return htmlspecialchars((string) $descriptor, ENT_QUOTES, 'UTF-8');
852
+ $type = $descriptor['type'] ?? (isset($descriptor['tag']) ? 'element' : 'fragment');
853
+ if ($type === 'text') return htmlspecialchars((string) ($descriptor['text'] ?? ''), ENT_QUOTES, 'UTF-8');
854
+ if ($type === 'fragment') {
855
+ return implode('', array_map('docsFallbackSerializeDescriptor', $descriptor['children'] ?? []));
856
+ }
857
+ $tag = preg_replace('/[^a-zA-Z0-9:-]/', '', (string) ($descriptor['tag'] ?? 'div')) ?: 'div';
858
+ $attrs = '';
859
+ foreach (($descriptor['attributes'] ?? []) as $name => $value) {
860
+ if ($value === null || $value === false || $value === []) continue;
861
+ if ($value === true) $value = 'true';
862
+ if (is_array($value)) $value = json_encode($value, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
863
+ $attrs .= ' ' . htmlspecialchars((string) $name, ENT_QUOTES, 'UTF-8') . '="' . htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8') . '"';
864
+ }
865
+ $children = implode('', array_map('docsFallbackSerializeDescriptor', $descriptor['children'] ?? []));
866
+ return '<' . $tag . $attrs . '>' . $children . '</' . $tag . '>';
867
+ }
868
+
869
+ function docsCreateRmtCompilerBridge($bridgePath, $repoRoot, $nodeBinary = 'node') {
870
+ return function ($source, array $context = []) use ($bridgePath, $repoRoot, $nodeBinary) {
871
+ if (!is_readable($bridgePath) || !function_exists('proc_open')) {
872
+ return [
873
+ 'schema' => 'xtend.docs.rmt-compiler-bridge.v1',
874
+ 'ok' => false,
875
+ 'status' => 'bridge-unavailable',
876
+ 'coreDocument' => null,
877
+ 'diagnostics' => [[
878
+ 'code' => 'xtend.docs.rmt_compiler_bridge.unavailable',
879
+ 'severity' => 'error',
880
+ 'message' => 'The docs PHP host could not start the Node vNext compiler bridge.'
881
+ ]]
882
+ ];
883
+ }
884
+ $payload = json_encode([
885
+ 'source' => (string) $source,
886
+ 'filePath' => $context['filePath'] ?? 'docs/xtendrmt-docs-shell-vnext.rmt',
887
+ 'options' => $context['options'] ?? []
888
+ ], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
889
+ $descriptorSpec = [
890
+ 0 => ['pipe', 'r'],
891
+ 1 => ['pipe', 'w'],
892
+ 2 => ['pipe', 'w']
893
+ ];
894
+ $command = escapeshellcmd((string) $nodeBinary) . ' ' . escapeshellarg((string) $bridgePath);
895
+ $process = proc_open($command, $descriptorSpec, $pipes, (string) $repoRoot);
896
+ if (!is_resource($process)) {
897
+ return [
898
+ 'schema' => 'xtend.docs.rmt-compiler-bridge.v1',
899
+ 'ok' => false,
900
+ 'status' => 'bridge-start-failed',
901
+ 'coreDocument' => null,
902
+ 'diagnostics' => [[
903
+ 'code' => 'xtend.docs.rmt_compiler_bridge.start_failed',
904
+ 'severity' => 'error',
905
+ 'message' => 'The docs PHP host failed to open the Node vNext compiler bridge.'
906
+ ]]
907
+ ];
908
+ }
909
+ fwrite($pipes[0], $payload ?: '{}');
910
+ fclose($pipes[0]);
911
+ $stdout = stream_get_contents($pipes[1]);
912
+ fclose($pipes[1]);
913
+ $stderr = stream_get_contents($pipes[2]);
914
+ fclose($pipes[2]);
915
+ $exitCode = proc_close($process);
916
+ $decoded = json_decode((string) $stdout, true);
917
+ if (is_array($decoded)) {
918
+ $decoded['exitCode'] = $exitCode;
919
+ if ($stderr !== '') $decoded['stderr'] = trim($stderr);
920
+ return $decoded;
921
+ }
922
+ return [
923
+ 'schema' => 'xtend.docs.rmt-compiler-bridge.v1',
924
+ 'ok' => false,
925
+ 'status' => 'bridge-output-invalid',
926
+ 'coreDocument' => null,
927
+ 'diagnostics' => [[
928
+ 'code' => 'xtend.docs.rmt_compiler_bridge.output_invalid',
929
+ 'severity' => 'error',
930
+ 'message' => trim($stderr) ?: 'The Node vNext compiler bridge did not return JSON.'
931
+ ]]
932
+ ];
933
+ };
934
+ }
935
+
936
+ function docsSsrEndpointUrl($page, $locale) {
937
+ return 'index.php?xtend-docs-rmt-ssr=shell&format=jsonl&page=' . rawurlencode((string) $page) . '&locale=' . rawurlencode((string) $locale);
938
+ }
939
+
940
+ function docsCreateDocsSsrAdapter($repoRoot, $bridgePath) {
941
+ if (!function_exists('createRmtPhpSsrAdapter')) return null;
942
+ $boundary = 'xtend.security.sanitizing-boundary.v1';
943
+ return createRmtPhpSsrAdapter([
944
+ 'manifest' => docsLoadComponentManifest($repoRoot),
945
+ 'compileRmtVNextSource' => docsCreateRmtCompilerBridge($bridgePath, $repoRoot),
946
+ 'defaultTrustBoundary' => $boundary,
947
+ 'staticDataSources' => [
948
+ 'xtendrmt.docs.php-ssr.shell' => [
949
+ 'html' => '<section data-rmt-stream="xtendrmt.docs.php-ssr.shell" data-rmt-trust-boundary="' . $boundary . '" hidden></section>',
950
+ 'trustBoundary' => $boundary
951
+ ],
952
+ 'xtendrmt.docs.parsedown.parse' => [
953
+ 'html' => '<section data-rmt-stream="xtendrmt.docs.parsedown.parse" data-rmt-trust-boundary="' . $boundary . '" hidden></section>',
954
+ 'trustBoundary' => $boundary
955
+ ],
956
+ 'xtendrmt.docs.related.prepare' => [
957
+ 'value' => [],
958
+ 'trustBoundary' => $boundary
959
+ ],
960
+ 'index.php?xtend-docs-page={slug}&locale={locale}' => [
961
+ 'html' => '<section data-rmt-stream="docs.page.payload" data-rmt-trust-boundary="' . $boundary . '" hidden></section>',
962
+ 'trustBoundary' => $boundary
963
+ ],
964
+ 'index.php?xtend-docs-rmt-ssr=shell&format=jsonl' => [
965
+ 'html' => '<section data-rmt-stream="docs.shell.ssr" data-rmt-trust-boundary="xtend.security.streaming-boundary.v1" hidden></section>',
966
+ 'trustBoundary' => 'xtend.security.streaming-boundary.v1'
967
+ ],
968
+ 'docs.page.payload' => [
969
+ 'html' => '<section data-rmt-stream="docs.page.payload" data-rmt-trust-boundary="' . $boundary . '" hidden></section>',
970
+ 'trustBoundary' => $boundary
971
+ ],
972
+ 'docs.shell.ssr' => [
973
+ 'html' => '<section data-rmt-stream="docs.shell.ssr" data-rmt-trust-boundary="' . $boundary . '" hidden></section>',
974
+ 'trustBoundary' => 'xtend.security.streaming-boundary.v1'
975
+ ]
976
+ ]
977
+ ]);
978
+ }
979
+
980
+ function docsBuildDocsSsrInput($source, $sourceRef, $descriptor) {
981
+ return [
982
+ 'source' => (string) $source,
983
+ 'filePath' => (string) $sourceRef,
984
+ 'descriptor' => $descriptor
985
+ ];
986
+ }
987
+
988
+ function docsCompactSsrMarkupReference($markup) {
989
+ if (!is_array($markup)) return null;
990
+ $html = isset($markup['html']) ? (string) $markup['html'] : '';
991
+ return array_filter([
992
+ 'schema' => $markup['schema'] ?? 'xtend.rmt.node-ssr-markup.v1',
993
+ 'htmlAlreadyInDom' => true,
994
+ 'byteLength' => strlen($html),
995
+ 'sha1' => $html !== '' ? sha1($html) : null
996
+ ], function ($value) {
997
+ return $value !== null && $value !== '';
998
+ });
999
+ }
1000
+
1001
+ function docsCompactSsrChunkForBootstrap($chunk) {
1002
+ if (!is_array($chunk)) return $chunk;
1003
+ $compact = [];
1004
+ foreach ([
1005
+ 'schema',
1006
+ 'kind',
1007
+ 'key',
1008
+ 'chunkKey',
1009
+ 'id',
1010
+ 'operationId',
1011
+ 'requestId',
1012
+ 'sequence',
1013
+ 'variant',
1014
+ 'capability',
1015
+ 'lane',
1016
+ 'target',
1017
+ 'templateId',
1018
+ 'qualifiedId',
1019
+ 'resourceId',
1020
+ 'ownershipMode',
1021
+ 'executionMode',
1022
+ 'renderedAt'
1023
+ ] as $key) {
1024
+ if (array_key_exists($key, $chunk)) {
1025
+ $compact[$key] = $chunk[$key];
1026
+ }
1027
+ }
1028
+ $markup = docsCompactSsrMarkupReference($chunk['markup'] ?? null);
1029
+ if ($markup) {
1030
+ $compact['markup'] = $markup;
1031
+ }
1032
+ if (isset($chunk['diagnostics']) && is_array($chunk['diagnostics'])) {
1033
+ $compact['diagnostics'] = $chunk['diagnostics'];
1034
+ }
1035
+ return $compact;
1036
+ }
1037
+
1038
+ function docsCompactRenderResultForBootstrap($renderResult) {
1039
+ if (!is_array($renderResult)) return null;
1040
+ return array_filter([
1041
+ 'schema' => $renderResult['schema'] ?? null,
1042
+ 'adapterSchema' => $renderResult['adapterSchema'] ?? null,
1043
+ 'ok' => $renderResult['ok'] ?? false,
1044
+ 'status' => $renderResult['status'] ?? null,
1045
+ 'requestId' => $renderResult['requestId'] ?? null,
1046
+ 'htmlAlreadyInDom' => true,
1047
+ 'htmlByteLength' => isset($renderResult['html']) ? strlen((string) $renderResult['html']) : null,
1048
+ 'head' => $renderResult['head'] ?? null,
1049
+ 'streamingContract' => $renderResult['streamingContract'] ?? null,
1050
+ 'componentCapabilities' => $renderResult['componentCapabilities'] ?? null,
1051
+ 'fabricTelemetryHints' => $renderResult['fabricTelemetryHints'] ?? null,
1052
+ 'diagnostics' => $renderResult['diagnostics'] ?? []
1053
+ ], function ($value) {
1054
+ return $value !== null && $value !== [];
1055
+ });
1056
+ }
1057
+
1058
+ function docsCompactDocsSsrPrehydrationForBootstrap($payload) {
1059
+ if (!is_array($payload)) return $payload;
1060
+ $html = isset($payload['html']) ? (string) $payload['html'] : '';
1061
+ $compact = [];
1062
+ foreach ([
1063
+ 'schema',
1064
+ 'ok',
1065
+ 'status',
1066
+ 'endpoint',
1067
+ 'source',
1068
+ 'compilerBridge',
1069
+ 'ssrEndpoint',
1070
+ 'shellPrimitives',
1071
+ 'hydration',
1072
+ 'diagnostics'
1073
+ ] as $key) {
1074
+ if (array_key_exists($key, $payload)) {
1075
+ $compact[$key] = $payload[$key];
1076
+ }
1077
+ }
1078
+ $compact['htmlAlreadyInDom'] = true;
1079
+ $compact['htmlByteLength'] = strlen($html);
1080
+ $compact['htmlSha1'] = $html !== '' ? sha1($html) : null;
1081
+ $compact['chunks'] = array_map('docsCompactSsrChunkForBootstrap', $payload['chunks'] ?? []);
1082
+ $compact['renderResult'] = docsCompactRenderResultForBootstrap($payload['renderResult'] ?? null);
1083
+ return $compact;
1084
+ }
1085
+
1086
+ function docsRenderDocsSsrPrehydration($repoRoot, $bridgePath, $sourcePath, $descriptor, $page, $locale) {
1087
+ $endpoint = docsSsrEndpointUrl($page, $locale);
1088
+ $source = is_readable($sourcePath) ? file_get_contents($sourcePath) : '';
1089
+ $fallbackHtml = docsFallbackSerializeDescriptor($descriptor);
1090
+ $result = [
1091
+ 'schema' => 'xtend.docs.php-ssr-prehydration.v1',
1092
+ 'ok' => false,
1093
+ 'status' => 'degraded',
1094
+ 'endpoint' => $endpoint,
1095
+ 'source' => 'docs/xtendrmt-docs-shell-vnext.rmt',
1096
+ 'compilerBridge' => [
1097
+ 'schema' => 'xtend.docs.rmt-compiler-bridge.v1',
1098
+ 'runner' => 'scripts/compile_rmt_vnext_bridge.js',
1099
+ 'injected' => false
1100
+ ],
1101
+ 'ssrEndpoint' => [
1102
+ 'schema' => 'xtend.docs.rmt-ssr-endpoint.v1',
1103
+ 'format' => 'jsonl',
1104
+ 'contentType' => 'application/x-ndjson',
1105
+ 'url' => $endpoint
1106
+ ],
1107
+ 'shellPrimitives' => [
1108
+ 'schema' => 'xtend.docs.rmt-shell-primitives.v1',
1109
+ 'rootSurfaces' => ['docs.root', 'docs.header', 'docs.hero', 'docs.router', 'docs.page', 'docs.sidebar', 'docs.footer', 'docs.diagnostics'],
1110
+ 'hydrationMode' => 'server_prerender_hydrate'
1111
+ ],
1112
+ 'renderResult' => null,
1113
+ 'hydration' => null,
1114
+ 'chunks' => [],
1115
+ 'diagnostics' => [],
1116
+ 'html' => $fallbackHtml
1117
+ ];
1118
+ if ($source === '') {
1119
+ $result['diagnostics'][] = [
1120
+ 'code' => 'xtend.docs.rmt_shell_source_missing',
1121
+ 'severity' => 'error',
1122
+ 'message' => 'The docs vNext shell source could not be read.'
1123
+ ];
1124
+ return $result;
1125
+ }
1126
+ $adapter = docsCreateDocsSsrAdapter($repoRoot, $bridgePath);
1127
+ if (!$adapter) {
1128
+ $result['diagnostics'][] = [
1129
+ 'code' => 'xtend.docs.php_ssr_adapter_missing',
1130
+ 'severity' => 'error',
1131
+ 'message' => 'The PHP SSR adapter factory is not available.'
1132
+ ];
1133
+ return $result;
1134
+ }
1135
+ $renderResult = $adapter->render(docsBuildDocsSsrInput($source, 'docs/xtendrmt-docs-shell-vnext.rmt', $descriptor), [
1136
+ 'requestId' => 'docs-php-ssr-' . preg_replace('/[^a-z0-9_-]+/i', '-', (string) $locale . '-' . (string) $page),
1137
+ 'rootId' => 'xtend-docs-rmt-root',
1138
+ 'namespace' => 'docs',
1139
+ 'templateId' => 'docs.app.root-shell',
1140
+ 'model' => [
1141
+ 'page' => $page,
1142
+ 'locale' => $locale,
1143
+ 'ssrEndpoint' => $endpoint
1144
+ ]
1145
+ ]);
1146
+ $result['renderResult'] = $renderResult;
1147
+ $result['hydration'] = $renderResult['hydration'] ?? null;
1148
+ $result['chunks'] = $renderResult['chunks'] ?? [];
1149
+ $result['diagnostics'] = $renderResult['diagnostics'] ?? [];
1150
+ $result['html'] = ($renderResult['html'] ?? '') !== '' ? $renderResult['html'] : $fallbackHtml;
1151
+ $result['ok'] = ($renderResult['ok'] ?? false) === true;
1152
+ $result['status'] = $result['ok'] ? 'prehydrated' : 'degraded';
1153
+ $result['compilerBridge']['injected'] = true;
1154
+ $result['compilerBridge']['coreSchema'] = $renderResult['hydration']['coreDocumentSchema'] ?? null;
1155
+ return $result;
1156
+ }
1157
+
450
1158
  // Slug <-> Datei-Mapping
451
1159
  $slugToFile = [];
452
1160
  $fileToSlug = [];
453
- foreach ($mdFiles as $rel => $abs) {
454
- $slug = slugify($rel);
455
- $slugToFile[$slug] = $rel;
456
- $fileToSlug[$rel] = $slug;
1161
+ $localizedSlugToFile = [];
1162
+ $localizedFileToSlug = [];
1163
+ foreach ($localizedMdFiles as $locale => $localeFiles) {
1164
+ $localizedSlugToFile[$locale] = [];
1165
+ $localizedFileToSlug[$locale] = [];
1166
+ foreach ($localeFiles as $rel => $abs) {
1167
+ $slug = slugify($rel);
1168
+ $localizedSlugToFile[$locale][$slug] = $rel;
1169
+ $localizedFileToSlug[$locale][$rel] = $slug;
1170
+ if ($locale === $docsDefaultLocale) {
1171
+ $slugToFile[$slug] = $rel;
1172
+ $fileToSlug[$rel] = $slug;
1173
+ }
1174
+ }
1175
+ }
1176
+
1177
+ function docsResolveLocalizedPage($rawSlug, $rawLocale, $localizedSlugToFile, $availableLocales, $fallbackLocale) {
1178
+ $parts = docsSplitLocalizedPath($rawSlug, $availableLocales);
1179
+ $requestedLocale = docsNormalizeLocale($parts['locale'] ?? $rawLocale, $availableLocales, $fallbackLocale);
1180
+ $slug = slugify($parts['slug'] ?? 'readme');
1181
+ if ($slug === '') $slug = 'readme';
1182
+ $hasRequested = isset($localizedSlugToFile[$requestedLocale][$slug]);
1183
+ $resolvedLocale = $hasRequested ? $requestedLocale : $fallbackLocale;
1184
+ $translationAvailable = $hasRequested;
1185
+ if (!isset($localizedSlugToFile[$resolvedLocale][$slug])) {
1186
+ return null;
1187
+ }
1188
+ return [
1189
+ 'slug' => $slug,
1190
+ 'requestedLocale' => $requestedLocale,
1191
+ 'resolvedLocale' => $resolvedLocale,
1192
+ 'translationAvailable' => $translationAvailable,
1193
+ 'rel' => $localizedSlugToFile[$resolvedLocale][$slug]
1194
+ ];
457
1195
  }
458
1196
 
459
1197
  // Routing: Slug aus URL
460
- $page = $_GET['page'] ?? '';
461
- if ($page && isset($slugToFile[$page])) {
462
- $mdFile = $mdFiles[$slugToFile[$page]];
1198
+ $pageRequest = docsResolveLocalizedPage($_GET['page'] ?? 'readme', $_GET['locale'] ?? $docsDefaultLocale, $localizedSlugToFile, $docsAvailableLocales, $docsFallbackLocale);
1199
+ if ($pageRequest) {
1200
+ $page = $pageRequest['slug'];
1201
+ $pageLocale = $pageRequest['resolvedLocale'];
1202
+ $mdFile = $localizedMdFiles[$pageLocale][$pageRequest['rel']];
463
1203
  } else {
464
1204
  // Default: README.md
465
- $mdFile = $docsRoot . '/README.md';
1205
+ $page = 'readme';
1206
+ $pageLocale = $docsDefaultLocale;
1207
+ $mdFile = $localizedMdFiles[$pageLocale]['README.md'] ?? ($docsRoot . '/' . $pageLocale . '/README.md');
466
1208
  $page = $fileToSlug['README.md'] ?? slugify('README.md');
467
1209
  }
468
1210
 
469
1211
  // Download-Handler
470
- if (isset($_GET['download']) && isset($slugToFile[$_GET['download']])) {
471
- $dlFile = $mdFiles[$slugToFile[$_GET['download']]];
1212
+ if (isset($_GET['download'])) {
1213
+ $downloadRequest = docsResolveLocalizedPage($_GET['download'], $_GET['locale'] ?? $docsDefaultLocale, $localizedSlugToFile, $docsAvailableLocales, $docsFallbackLocale);
1214
+ if (!$downloadRequest) {
1215
+ http_response_code(404);
1216
+ header('Content-Type: text/plain; charset=UTF-8');
1217
+ echo 'Docs page not found.';
1218
+ exit;
1219
+ }
1220
+ $dlFile = $localizedMdFiles[$downloadRequest['resolvedLocale']][$downloadRequest['rel']];
472
1221
  header('Content-Type: text/markdown');
473
1222
  header('Content-Disposition: attachment; filename="' . basename($dlFile) . '"');
474
1223
  readfile($dlFile);
@@ -477,12 +1226,16 @@ if (isset($_GET['download']) && isset($slugToFile[$_GET['download']])) {
477
1226
 
478
1227
  // Parsedown einbinden
479
1228
  require_once $parsedownFile;
1229
+ if (is_readable($rmtPhpSsrAdapterFile)) {
1230
+ require_once $rmtPhpSsrAdapterFile;
1231
+ }
480
1232
  $Parsedown = new Parsedown();
481
1233
  $Parsedown->setSafeMode(true);
482
1234
 
483
1235
  if (isset($_GET['xtend-docs-page'])) {
484
- $requestedSlug = slugify((string) $_GET['xtend-docs-page']);
485
- if (!isset($slugToFile[$requestedSlug])) {
1236
+ $pagePayloadRequest = docsResolveLocalizedPage($_GET['xtend-docs-page'], $_GET['locale'] ?? $docsDefaultLocale, $localizedSlugToFile, $docsAvailableLocales, $docsFallbackLocale);
1237
+ if (!$pagePayloadRequest) {
1238
+ $requestedSlug = slugify((string) $_GET['xtend-docs-page']);
486
1239
  http_response_code(404);
487
1240
  header('Content-Type: application/json; charset=UTF-8');
488
1241
  header('X-Content-Type-Options: nosniff');
@@ -490,14 +1243,20 @@ if (isset($_GET['xtend-docs-page'])) {
490
1243
  'schema' => 'xtend.docs.parsedown-rmt-page-payload.v1',
491
1244
  'ok' => false,
492
1245
  'slug' => $requestedSlug,
1246
+ 'requestedLocale' => docsNormalizeLocale($_GET['locale'] ?? $docsDefaultLocale, $docsAvailableLocales, $docsFallbackLocale),
1247
+ 'fallbackLocale' => $docsFallbackLocale,
1248
+ 'translationAvailable' => false,
493
1249
  'error' => 'docs-page-not-found'
494
1250
  ], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
495
1251
  exit;
496
1252
  }
497
1253
 
498
- $rel = $slugToFile[$requestedSlug];
499
- $markdown = file_get_contents($mdFiles[$rel]);
500
- $meta = docsBuildPageMeta($requestedSlug, $rel, $markdown);
1254
+ $requestedSlug = $pagePayloadRequest['slug'];
1255
+ $requestedLocale = $pagePayloadRequest['requestedLocale'];
1256
+ $resolvedLocale = $pagePayloadRequest['resolvedLocale'];
1257
+ $rel = $pagePayloadRequest['rel'];
1258
+ $markdown = file_get_contents($localizedMdFiles[$resolvedLocale][$rel]);
1259
+ $meta = docsBuildPageMeta($requestedSlug, $rel, $markdown, $resolvedLocale, $requestedLocale, $pagePayloadRequest['translationAvailable']);
501
1260
  header('Content-Type: application/json; charset=UTF-8');
502
1261
  header('X-Content-Type-Options: nosniff');
503
1262
  header('Cache-Control: no-store');
@@ -505,6 +1264,11 @@ if (isset($_GET['xtend-docs-page'])) {
505
1264
  'schema' => 'xtend.docs.parsedown-rmt-page-payload.v1',
506
1265
  'ok' => true,
507
1266
  'slug' => $requestedSlug,
1267
+ 'locale' => $resolvedLocale,
1268
+ 'requestedLocale' => $requestedLocale,
1269
+ 'resolvedLocale' => $resolvedLocale,
1270
+ 'fallbackLocale' => $docsFallbackLocale,
1271
+ 'translationAvailable' => $pagePayloadRequest['translationAvailable'],
508
1272
  'html' => $Parsedown->text($markdown),
509
1273
  'meta' => $meta,
510
1274
  'source' => $meta['source'],
@@ -529,28 +1293,45 @@ function navLinks($fileToSlug) {
529
1293
  // --- Nach dem Parsen aller Seiten: JS-Objekt für alle Seiteninhalte ---
530
1294
  $allPages = [];
531
1295
  $allPagesMeta = [];
1296
+ $localizedAllPages = [];
1297
+ $localizedAllPagesMeta = [];
1298
+ $localizedTitles = [];
532
1299
  $docsRmtRoutes = [];
533
1300
  $titles = [];
534
- foreach ($fileToSlug as $rel => $slug) {
535
- $mdFile = $mdFiles[$slugToFile[$slug]];
536
- $mdContent = file_get_contents($mdFile);
537
- $allPagesMeta[$slug] = docsBuildPageMeta($slug, $rel, $mdContent);
538
- if ($slug === $page) {
539
- $allPages[$slug] = $Parsedown->text($mdContent);
1301
+ foreach ($localizedFileToSlug as $locale => $localeFileToSlug) {
1302
+ $localizedAllPages[$locale] = [];
1303
+ $localizedAllPagesMeta[$locale] = [];
1304
+ $localizedTitles[$locale] = [];
1305
+ foreach ($localeFileToSlug as $rel => $slug) {
1306
+ $mdFile = $localizedMdFiles[$locale][$rel];
1307
+ $mdContent = file_get_contents($mdFile);
1308
+ $meta = docsBuildPageMeta($slug, $rel, $mdContent, $locale, $locale, true);
1309
+ $localizedAllPagesMeta[$locale][$slug] = $meta;
1310
+ if ($slug === $page && $locale === $pageLocale) {
1311
+ $localizedAllPages[$locale][$slug] = $Parsedown->text($mdContent);
1312
+ }
1313
+ $localizedTitles[$locale][$slug] = $meta['title'];
1314
+ if ($locale === $docsDefaultLocale) {
1315
+ $allPagesMeta[$slug] = $meta;
1316
+ if ($slug === $page && $locale === $pageLocale) {
1317
+ $allPages[$slug] = $Parsedown->text($mdContent);
1318
+ }
1319
+ $docsRmtRoutes[] = $meta['route'];
1320
+ $titles[$slug] = $meta['title'];
1321
+ }
540
1322
  }
541
- $docsRmtRoutes[] = $allPagesMeta[$slug]['route'];
542
- $titles[$slug] = $allPagesMeta[$slug]['title'];
543
1323
  }
544
- $readmeTitle = $allPagesMeta['readme']['title'] ?? 'XTend Dokumentation';
545
- $readmeDocumentTitle = $allPagesMeta['readme']['documentTitle'] ?? 'XTend Dokumentation';
546
- $readmeDescription = $allPagesMeta['readme']['metaDescription'] ?? 'XTend Dokumentation';
1324
+ $initialLocaleConfig = $docsAvailableLocales[$pageLocale] ?? $docsAvailableLocales[$docsDefaultLocale];
1325
+ $readmeTitle = $localizedAllPagesMeta[$docsDefaultLocale]['readme']['title'] ?? 'XTend Dokumentation';
1326
+ $readmeDocumentTitle = $localizedAllPagesMeta[$docsDefaultLocale]['readme']['documentTitle'] ?? 'XTend Dokumentation';
1327
+ $readmeDescription = $localizedAllPagesMeta[$docsDefaultLocale]['readme']['metaDescription'] ?? 'XTend Dokumentation';
547
1328
  $docsRmtRoutes[] = array_replace_recursive($allPagesMeta['readme']['route'] ?? [], [
548
1329
  'id' => 'docs.home',
549
1330
  'path' => '/',
550
1331
  'title' => $readmeTitle,
551
1332
  'documentTitle' => $readmeDocumentTitle,
552
1333
  'metadata' => [
553
- 'source' => 'docs/README.md',
1334
+ 'source' => 'docs/' . $docsDefaultLocale . '/README.md',
554
1335
  'seo' => [
555
1336
  'title' => $readmeTitle,
556
1337
  'documentTitle' => $readmeDocumentTitle,
@@ -560,19 +1341,89 @@ $docsRmtRoutes[] = array_replace_recursive($allPagesMeta['readme']['route'] ?? [
560
1341
  ]);
561
1342
  $rmtPilotDocumentData = docsMergeRmtRoutes($rmtPilotDocumentData, $docsRmtRoutes);
562
1343
  $rmtPilotDocumentJson = json_encode($rmtPilotDocumentData, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
563
- $initialDocsSlug = isset($allPagesMeta[$page]) ? $page : 'readme';
564
- $initialTitle = $allPagesMeta[$initialDocsSlug]['documentTitle'] ?? 'XTend Dokumentation';
565
- $initialDescription = $allPagesMeta[$initialDocsSlug]['metaDescription'] ?? 'XTend Dokumentation';
566
- $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords'] ?? ['xtend', 'dokumentation']);
1344
+ $initialDocsSlug = isset($localizedAllPagesMeta[$pageLocale][$page]) ? $page : 'readme';
1345
+ $initialTitle = $localizedAllPagesMeta[$pageLocale][$initialDocsSlug]['documentTitle'] ?? 'XTend Dokumentation';
1346
+ $initialDescription = $localizedAllPagesMeta[$pageLocale][$initialDocsSlug]['metaDescription'] ?? 'XTend Dokumentation';
1347
+ $initialKeywords = implode(', ', $localizedAllPagesMeta[$pageLocale][$initialDocsSlug]['metaKeywords'] ?? ['xtend', 'dokumentation']);
1348
+ $docsRootShellDescriptor = docsBuildDocsRootShellDescriptor(
1349
+ $allPagesMeta,
1350
+ $localizedAllPagesMeta,
1351
+ $fileToSlug,
1352
+ $docsAvailableLocales,
1353
+ $pageLocale,
1354
+ $docsDefaultLocale,
1355
+ htmlspecialchars_decode($docsLogoUrl, ENT_QUOTES),
1356
+ $xtendAssetVersionAttr
1357
+ );
1358
+ $docsSsrEndpoint = docsSsrEndpointUrl($initialDocsSlug, $pageLocale);
1359
+ $docsSsrPrehydration = docsRenderDocsSsrPrehydration(
1360
+ $repoRoot,
1361
+ $docsRmtCompilerBridgePath,
1362
+ $docsRmtVNextDocumentPath,
1363
+ $docsRootShellDescriptor,
1364
+ $initialDocsSlug,
1365
+ $pageLocale
1366
+ );
1367
+ if (isset($_GET['xtend-docs-rmt-ssr']) && $_GET['xtend-docs-rmt-ssr'] === 'shell') {
1368
+ $streamPageRequest = docsResolveLocalizedPage($_GET['page'] ?? $initialDocsSlug, $_GET['locale'] ?? $pageLocale, $localizedSlugToFile, $docsAvailableLocales, $docsFallbackLocale);
1369
+ $streamPage = $streamPageRequest['slug'] ?? $initialDocsSlug;
1370
+ $streamLocale = $streamPageRequest['resolvedLocale'] ?? $pageLocale;
1371
+ $streamDescriptor = docsBuildDocsRootShellDescriptor(
1372
+ $allPagesMeta,
1373
+ $localizedAllPagesMeta,
1374
+ $fileToSlug,
1375
+ $docsAvailableLocales,
1376
+ $streamLocale,
1377
+ $docsDefaultLocale,
1378
+ htmlspecialchars_decode($docsLogoUrl, ENT_QUOTES),
1379
+ $xtendAssetVersionAttr
1380
+ );
1381
+ $streamSource = is_readable($docsRmtVNextDocumentPath) ? file_get_contents($docsRmtVNextDocumentPath) : '';
1382
+ $streamAdapter = docsCreateDocsSsrAdapter($repoRoot, $docsRmtCompilerBridgePath);
1383
+ header('Content-Type: application/x-ndjson; charset=UTF-8');
1384
+ header('X-Content-Type-Options: nosniff');
1385
+ header('Cache-Control: no-store');
1386
+ if (!$streamAdapter || $streamSource === '') {
1387
+ echo json_encode([
1388
+ 'schema' => 'xtend.rmt.node-ssr-jsonl-frame.v1',
1389
+ 'type' => 'error',
1390
+ 'requestId' => 'docs-php-ssr-stream-unavailable',
1391
+ 'sequence' => 0,
1392
+ 'payload' => ['code' => 'xtend.docs.rmt_ssr_endpoint.unavailable'],
1393
+ 'diagnostics' => [[
1394
+ 'code' => 'xtend.docs.rmt_ssr_endpoint.unavailable',
1395
+ 'severity' => 'error',
1396
+ 'message' => 'The docs RMT SSR stream endpoint could not create the adapter or source.'
1397
+ ]]
1398
+ ], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) . "\n";
1399
+ exit;
1400
+ }
1401
+ foreach ($streamAdapter->streamJsonl(docsBuildDocsSsrInput($streamSource, 'docs/xtendrmt-docs-shell-vnext.rmt', $streamDescriptor), [
1402
+ 'requestId' => 'docs-php-ssr-stream-' . preg_replace('/[^a-z0-9_-]+/i', '-', $streamLocale . '-' . $streamPage),
1403
+ 'rootId' => 'xtend-docs-rmt-root',
1404
+ 'namespace' => 'docs',
1405
+ 'templateId' => 'docs.app.root-shell',
1406
+ 'model' => [
1407
+ 'page' => $streamPage,
1408
+ 'locale' => $streamLocale,
1409
+ 'ssrEndpoint' => docsSsrEndpointUrl($streamPage, $streamLocale)
1410
+ ]
1411
+ ]) as $line) {
1412
+ echo $line;
1413
+ if (function_exists('ob_flush')) @ob_flush();
1414
+ flush();
1415
+ }
1416
+ exit;
1417
+ }
567
1418
  ?><!DOCTYPE html>
568
- <html lang="de">
1419
+ <html lang="<?= htmlspecialchars($initialLocaleConfig['htmlLang'] ?? $pageLocale, ENT_QUOTES, 'UTF-8') ?>">
569
1420
  <head>
570
1421
  <meta charset="UTF-8">
571
1422
  <title><?= htmlspecialchars($initialTitle, ENT_QUOTES, 'UTF-8') ?></title>
572
1423
  <meta name="description" content="<?= htmlspecialchars($initialDescription, ENT_QUOTES, 'UTF-8') ?>">
573
1424
  <meta name="keywords" content="<?= htmlspecialchars($initialKeywords, ENT_QUOTES, 'UTF-8') ?>">
574
1425
  <meta name="viewport" content="width=device-width,initial-scale=1">
575
- <meta name="xtend-preload" content="x-theme,x-button,x-icon,x-link,x-input,x-form,x-header,x-hero,x-router,x-footer,x-section,x-code,x-modal,x-dialog">
1426
+ <meta name="xtend-preload" content="x-theme,x-button,x-icon,x-link,x-input,x-form,x-header,x-hero,x-router,x-footer,x-select,x-section,x-code,x-modal,x-dialog">
576
1427
  <link rel="icon" href="<?= $docsFaviconIcoUrl ?>" sizes="any">
577
1428
  <link rel="icon" type="image/png" sizes="32x32" href="<?= $docsFavicon32Url ?>">
578
1429
  <link rel="icon" type="image/png" sizes="16x16" href="<?= $docsFavicon16Url ?>">
@@ -581,6 +1432,7 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
581
1432
  <script src="/fabric/xtend-fabric.js?v=<?= $xtendAssetVersionAttr ?>"></script>
582
1433
  <script type="module" src="/xtend-loader.js?v=<?= $xtendAssetVersionAttr ?>" data-manifest="/components/manifest.json?v=<?= $xtendAssetVersionAttr ?>" data-module-cache-bust="<?= $xtendAssetVersionAttr ?>"></script>
583
1434
  <script src="/components/prism.js" nonce="<?= $nonce ?>"></script>
1435
+ <script src="/components/prism-rmt.js" nonce="<?= $nonce ?>"></script>
584
1436
  <style>
585
1437
  html {
586
1438
  --body-bg: #f7f8fb;
@@ -615,6 +1467,8 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
615
1467
  --docs-viewport-gutter: 0.5rem;
616
1468
  --docs-layout-gap: clamp(1rem, 2.2vw, 2.5rem);
617
1469
  --docs-sidebar-width: clamp(20rem, 24vw, 27rem);
1470
+ --docs-route-reserved-block-size: max(42rem, calc(100svh - 12rem));
1471
+ --docs-footer-reserved-block-size: clamp(4.75rem, 7vw, 6.5rem);
618
1472
  --docs-hero-bg-light: linear-gradient(135deg, #f8fbff 0%, #e7f0f7 100%);
619
1473
  --docs-hero-bg-dark: #050506;
620
1474
  --docs-hero-text-light: #162033;
@@ -670,6 +1524,7 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
670
1524
  main {
671
1525
  width: 100%;
672
1526
  min-width: 0;
1527
+ min-block-size: var(--docs-route-reserved-block-size);
673
1528
  box-sizing: border-box;
674
1529
  background: transparent;
675
1530
  border: 0;
@@ -679,6 +1534,8 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
679
1534
  }
680
1535
  x-footer {
681
1536
  display: block;
1537
+ min-block-size: var(--docs-footer-reserved-block-size);
1538
+ contain-intrinsic-size: auto var(--docs-footer-reserved-block-size);
682
1539
  margin: var(--docs-shell-vertical-gap) var(--docs-viewport-gutter) 0;
683
1540
  }
684
1541
  main > x-router {
@@ -686,11 +1543,13 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
686
1543
  width: 100%;
687
1544
  max-width: 100%;
688
1545
  min-width: 0;
1546
+ min-block-size: var(--docs-route-reserved-block-size);
689
1547
  }
690
1548
  main > x-router::part(outlet) {
691
1549
  width: 100%;
692
1550
  max-width: 100%;
693
1551
  min-width: 0;
1552
+ min-block-size: var(--docs-route-reserved-block-size);
694
1553
  box-sizing: border-box;
695
1554
  }
696
1555
  x-header {
@@ -1023,6 +1882,7 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1023
1882
  width: 100%;
1024
1883
  max-width: none;
1025
1884
  min-width: 0;
1885
+ min-block-size: var(--docs-route-reserved-block-size);
1026
1886
  box-sizing: border-box;
1027
1887
  --section-bg: var(--docs-shell-bg);
1028
1888
  --section-padding: 0;
@@ -1050,6 +1910,7 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1050
1910
  max-width: calc(100% - var(--docs-viewport-gutter) - var(--docs-viewport-gutter));
1051
1911
  margin-inline: var(--docs-viewport-gutter);
1052
1912
  min-width: 0;
1913
+ min-block-size: var(--docs-route-reserved-block-size);
1053
1914
  box-sizing: border-box;
1054
1915
  }
1055
1916
  .docs-article-surface,
@@ -1064,6 +1925,7 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1064
1925
  border: 1px solid var(--border-color);
1065
1926
  border-radius: 8px;
1066
1927
  padding: clamp(1rem, 2vw, 2rem);
1928
+ min-block-size: var(--docs-route-reserved-block-size);
1067
1929
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.08);
1068
1930
  }
1069
1931
  [data-theme="dark"] .docs-article-surface {
@@ -1224,6 +2086,68 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1224
2086
  float: none;
1225
2087
  font-size: 0.9em;
1226
2088
  }
2089
+ .docs-language-control {
2090
+ display: inline-grid;
2091
+ grid-template-columns: auto minmax(7.35rem, 8.8rem) auto;
2092
+ align-items: center;
2093
+ gap: 0.42rem;
2094
+ min-height: 44px;
2095
+ padding: 0 0.32rem 0 0.58rem;
2096
+ border: 1px solid color-mix(in srgb, var(--border-color) 84%, transparent);
2097
+ border-radius: 999px;
2098
+ background: color-mix(in srgb, var(--surface-muted) 82%, transparent);
2099
+ color: var(--text-color);
2100
+ box-sizing: border-box;
2101
+ }
2102
+ .docs-language-control:focus-within {
2103
+ outline: 2px solid color-mix(in srgb, var(--primary-color) 56%, transparent);
2104
+ outline-offset: 2px;
2105
+ }
2106
+ .docs-language-icon {
2107
+ color: var(--primary-color);
2108
+ flex: none;
2109
+ opacity: 0.9;
2110
+ }
2111
+ .docs-language-status {
2112
+ display: none;
2113
+ align-items: center;
2114
+ gap: 0.32rem;
2115
+ color: var(--muted-text-color);
2116
+ font-size: 0.78rem;
2117
+ line-height: 1;
2118
+ white-space: nowrap;
2119
+ }
2120
+ .docs-language-control[data-docs-locale-busy="true"] .docs-language-status {
2121
+ display: inline-flex;
2122
+ }
2123
+ .docs-language-status-spinner {
2124
+ width: 0.85rem;
2125
+ height: 0.85rem;
2126
+ border: 2px solid color-mix(in srgb, var(--primary-color) 22%, transparent);
2127
+ border-top-color: var(--primary-color);
2128
+ border-radius: 999px;
2129
+ box-sizing: border-box;
2130
+ animation: docs-language-spin 0.78s linear infinite;
2131
+ }
2132
+ .docs-language-status-label {
2133
+ max-width: 4.8rem;
2134
+ overflow: hidden;
2135
+ text-overflow: ellipsis;
2136
+ }
2137
+ @keyframes docs-language-spin {
2138
+ to { transform: rotate(360deg); }
2139
+ }
2140
+ .docs-language-select {
2141
+ display: block;
2142
+ min-width: 7.5rem;
2143
+ max-width: 8.8rem;
2144
+ --xtend-form-control-min-height: 44px;
2145
+ }
2146
+ .docs-language-select::part(label),
2147
+ .docs-language-select::part(helper),
2148
+ .docs-language-select::part(error) {
2149
+ display: none;
2150
+ }
1227
2151
  xtend-doc-page {
1228
2152
  display: block;
1229
2153
  width: 100%;
@@ -1246,6 +2170,8 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1246
2170
  @media (max-width: 700px) {
1247
2171
  :root {
1248
2172
  --docs-shell-vertical-gap: 1rem;
2173
+ --docs-route-reserved-block-size: max(48rem, calc(100svh - 10rem));
2174
+ --docs-footer-reserved-block-size: 7.5rem;
1249
2175
  }
1250
2176
  x-hero.docs-hero {
1251
2177
  margin: 0 var(--docs-viewport-gutter);
@@ -1280,14 +2206,65 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1280
2206
  xtend-doc-page[data-docs-route-state="loading"] {
1281
2207
  transform: none;
1282
2208
  }
2209
+ .docs-language-status-spinner {
2210
+ animation: none;
2211
+ }
1283
2212
  }
1284
2213
  </style>
1285
2214
  <script nonce="<?= $nonce ?>">
1286
2215
  window.xtendInitialDocsSlug = <?= json_encode($initialDocsSlug, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
1287
- if (!location.hash) location.hash = '#/' + (window.xtendInitialDocsSlug || 'readme');
2216
+ window.xtendInitialDocsLocale = <?= json_encode($pageLocale, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
2217
+ window.xtendDocsLocales = <?php echo json_encode($docsAvailableLocales, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
2218
+ window.xtendDocsI18n = {
2219
+ schema: 'xtend.docs.i18n.v1',
2220
+ defaultLocale: <?= json_encode($docsDefaultLocale, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>,
2221
+ fallbackLocale: <?= json_encode($docsFallbackLocale, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>,
2222
+ storageKey: 'xtend.docs.locale',
2223
+ stateKeys: {
2224
+ locale: 'xtend.docs.locale',
2225
+ target: 'xtend.docs.locale.target',
2226
+ source: 'xtend.docs.locale.source',
2227
+ status: 'xtend.docs.locale.status',
2228
+ busy: 'xtend.docs.locale.busy',
2229
+ transition: 'xtend.docs.locale.transition',
2230
+ error: 'xtend.docs.locale.error',
2231
+ available: 'xtend.docs.locale.available',
2232
+ fallback: 'xtend.docs.locale.fallback'
2233
+ },
2234
+ available: Object.keys(window.xtendDocsLocales || {})
2235
+ };
2236
+ window.xtendDocsLocalizedPages = <?php echo json_encode($localizedAllPages, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
2237
+ window.xtendDocsLocalizedPagesMeta = <?php echo json_encode(docsCompactLocalizedMetaForBootstrap($localizedAllPagesMeta), JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
2238
+ window.xtendDocsLocalizedTitles = <?php echo json_encode($localizedTitles, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
2239
+ (function() {
2240
+ const config = window.xtendDocsI18n || {};
2241
+ const available = config.available || ['de'];
2242
+ const fallback = config.fallbackLocale || 'de';
2243
+ const normalizeLocale = (value) => {
2244
+ const raw = String(value || '').toLowerCase();
2245
+ if (available.includes(raw)) return raw;
2246
+ const short = raw.slice(0, 2);
2247
+ return available.includes(short) ? short : fallback;
2248
+ };
2249
+ const stored = (() => {
2250
+ try { return localStorage.getItem(config.storageKey || 'xtend.docs.locale'); } catch (error) { return ''; }
2251
+ })();
2252
+ const browser = (navigator.languages && navigator.languages[0]) || navigator.language || '';
2253
+ const locale = normalizeLocale(stored || browser || config.defaultLocale || fallback);
2254
+ const rawHash = location.hash.replace(/^#\/?/, '').replace(/^\/+/, '');
2255
+ const parts = rawHash.split('/');
2256
+ const hashLocale = available.includes(parts[0]) ? parts[0] : '';
2257
+ const slug = hashLocale ? (parts.slice(1).join('/') || window.xtendInitialDocsSlug || 'readme') : (rawHash || window.xtendInitialDocsSlug || 'readme');
2258
+ window.xtendDocsCurrentLocale = hashLocale || locale;
2259
+ if (!location.hash || !hashLocale) {
2260
+ location.hash = '#/' + window.xtendDocsCurrentLocale + '/' + slug;
2261
+ }
2262
+ })();
1288
2263
  window.xtendDocsPages = <?php echo json_encode($allPages, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
1289
- window.xtendDocsPageEndpoint = 'index.php?xtend-docs-page=';
1290
- window.xtendDocsPagesMeta = <?php echo json_encode($allPagesMeta, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
2264
+ window.xtendDocsPageEndpoint = 'index.php?xtend-docs-page={slug}&locale={locale}';
2265
+ window.xtendDocsRmtSsrEndpoint = <?= docsJsonEncodeForHtml($docsSsrEndpoint); ?>;
2266
+ window.xtendDocsSsrPrehydration = <?php echo docsJsonEncodeForHtml(docsCompactDocsSsrPrehydrationForBootstrap($docsSsrPrehydration)); ?>;
2267
+ window.xtendDocsPagesMeta = <?php echo json_encode(docsCompactMetaMapForBootstrap($allPagesMeta), JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
1291
2268
  window.xtendDocsTitles = <?php echo json_encode($titles, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
1292
2269
  window.xtendDocsAssetUrls = {
1293
2270
  favicon: '<?= $docsFaviconIcoUrl ?>',
@@ -1304,6 +2281,18 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1304
2281
  workpackage: 'ER-WP-40',
1305
2282
  document: './<?= htmlspecialchars($rmtPilotDocument, ENT_QUOTES, 'UTF-8') ?>',
1306
2283
  renderMode: 'shell-first',
2284
+ phpSsrPrehydration: window.xtendDocsSsrPrehydration,
2285
+ rmtVNextDocument: './<?= htmlspecialchars($docsRmtVNextDocument, ENT_QUOTES, 'UTF-8') ?>',
2286
+ ssrEndpoint: window.xtendDocsRmtSsrEndpoint,
2287
+ compilerBridge: {
2288
+ schema: 'xtend.docs.rmt-compiler-bridge.v1',
2289
+ runner: 'scripts/compile_rmt_vnext_bridge.js',
2290
+ function: 'compileRmtVNextSource',
2291
+ injected: Boolean(window.xtendDocsSsrPrehydration && window.xtendDocsSsrPrehydration.compilerBridge && window.xtendDocsSsrPrehydration.compilerBridge.injected)
2292
+ },
2293
+ ssrPrehydrationContract: 'xtend.docs.php-ssr-prehydration.v1',
2294
+ ssrEndpointContract: 'xtend.docs.rmt-ssr-endpoint.v1',
2295
+ shellPrimitivesContract: 'xtend.docs.rmt-shell-primitives.v1',
1307
2296
  insularHydration: true,
1308
2297
  lazyParsedownRoutes: true,
1309
2298
  skeletonLoader: 'xtend.loader.skeleton-loader.v1',
@@ -1392,59 +2381,7 @@ $initialKeywords = implode(', ', $allPagesMeta[$initialDocsSlug]['metaKeywords']
1392
2381
  <script src="/docs/utils/fabric-runtime.js?v=<?= $xtendAssetVersionAttr ?>" nonce="<?= $nonce ?>"></script>
1393
2382
  </head>
1394
2383
  <body xt-ui-effects="none">
1395
- <x-theme></x-theme>
1396
- <x-header src="<?= $docsLogoUrl ?>" logo-size="48" sticky data-xtend-skeleton style="--xtend-skeleton-min-height: 4.75rem;">
1397
- <span slot="title">XTend Dokumentation</span>
1398
- <x-button
1399
- id="theme-toggle"
1400
- class="docs-icon-button docs-theme-toggle"
1401
- slot="actions"
1402
- type="button"
1403
- variant="secondary"
1404
- aria-label="Dunkelmodus aktivieren"
1405
- title="Dunkelmodus aktivieren"
1406
- aria-pressed="false"
1407
- >
1408
- <x-icon id="theme-toggle-icon" name="moon" pack="core" decorative size="1.1rem"></x-icon>
1409
- <span id="theme-toggle-label" class="docs-visually-hidden">Dunkelmodus aktivieren</span>
1410
- </x-button>
1411
- <?php foreach ($fileToSlug as $rel => $slug): ?>
1412
- <x-link class="docs-nav-link" slot="nav" href="/<?= $slug ?>" <?= $page === $slug ? 'active' : '' ?>>
1413
- <x-icon class="docs-nav-link-icon" name="<?= htmlspecialchars(docsMenuIconForSlug($slug), ENT_QUOTES, 'UTF-8') ?>" decorative size="1rem"></x-icon>
1414
- <span class="docs-nav-link-label"><?= htmlspecialchars(ucfirst(preg_replace('/[-_]/', ' ', preg_replace('/\.md$/i', '', basename($rel))))) ?></span>
1415
- </x-link>
1416
- <?php endforeach; ?>
1417
- </x-header>
1418
- <x-hero
1419
- class="docs-hero"
1420
- data-xtend-skeleton
1421
- style="--xtend-skeleton-min-height: clamp(12rem, 30vw, 22rem);"
1422
- background-light="var(--docs-hero-bg-light)"
1423
- background-dark="var(--docs-hero-bg-dark)"
1424
- font-color-light="var(--docs-hero-text-light)"
1425
- font-color-dark="var(--docs-hero-text-dark)"
1426
- overlay-light="rgba(255, 255, 255, 0.16)"
1427
- overlay-dark="rgba(0, 0, 0, 0.28)"
1428
- align="block"
1429
- overlay
1430
- animate
1431
- vertical-align="top"
1432
- >
1433
- <h1>XTend Developer Center</h1>
1434
- <p>Build with XTend today</p>
1435
- </x-hero>
1436
- <main>
1437
- <x-router mode="hash" reuse-component skeleton="article" skeleton-lines="10" skeleton-min-height="26rem" skeleton-label="Dokumentation wird geladen" data-xtend-skeleton style="--xtend-skeleton-min-height: 26rem; --xtend-skeleton-width: calc(100% - var(--docs-viewport-gutter) - var(--docs-viewport-gutter)); --xtend-skeleton-max-width: calc(100% - var(--docs-viewport-gutter) - var(--docs-viewport-gutter)); --xtend-skeleton-margin-inline: var(--docs-viewport-gutter);" document-title-template="{{title}} | XTend Dokumentation" default-title="XTend Dokumentation">
1438
- <?= docsRenderXRoute($allPagesMeta['readme']['route'], '/') . "\n" ?>
1439
- <?php foreach ($fileToSlug as $rel => $slug): ?>
1440
- <?= docsRenderXRoute($allPagesMeta[$slug]['route']) . "\n" ?>
1441
- <?php endforeach; ?>
1442
- <x-route path="*" component="xtend-doc-page" import="/docs/utils/pageloader.js?v=<?= $xtendAssetVersionAttr ?>" title="Seite nicht gefunden" document-title="Seite nicht gefunden | XTend Dokumentation" meta-description="Die angeforderte Dokumentationsseite wurde nicht gefunden." skeleton="article" skeleton-lines="8" skeleton-min-height="20rem" hydrate-schedule="docs.page.hydrate" data-rmt-route-id="docs.notFound" data-rmt-router="xtend.xrouter" data-rmt-component="docs.page" data-rmt-schedule="docs.route.render" data-rmt-hydrate-schedule="docs.page.hydrate"></x-route>
1443
- </x-router>
1444
- </main>
1445
- <x-footer src="<?= $docsLogoUrl ?>" logo-size="32" data-xtend-skeleton="inline" style="--xtend-skeleton-min-height: 3.25rem;">
1446
- <span slot="title">© 2026 – CCS Networks | Powered by XRouter PHP Extension</span>
1447
- </x-footer>
2384
+ <?= $docsSsrPrehydration['html'] ?? docsFallbackSerializeDescriptor($docsRootShellDescriptor) ?>
1448
2385
  <script src="/docs/utils/pageloader.js?v=<?= $xtendAssetVersionAttr ?>" nonce="<?= $nonce ?>">
1449
2386
  </script>
1450
2387
  <script nonce="<?= $nonce ?>">
@@ -1456,16 +2393,19 @@ document.addEventListener('DOMContentLoaded', function() {
1456
2393
  function updateThemeButton() {
1457
2394
  if (!btn || !label) return;
1458
2395
  const theme = document.documentElement.getAttribute('data-theme');
2396
+ const locale = window.xtendDocsCurrentLocale === 'en' ? 'en' : 'de';
2397
+ const darkLabel = locale === 'en' ? 'Enable dark mode' : 'Dunkelmodus aktivieren';
2398
+ const lightLabel = locale === 'en' ? 'Enable light mode' : 'Hellmodus aktivieren';
1459
2399
  if (theme === 'dark') {
1460
- label.textContent = 'Hellmodus aktivieren';
1461
- btn.setAttribute('aria-label', 'Hellmodus aktivieren');
1462
- btn.setAttribute('title', 'Hellmodus aktivieren');
2400
+ label.textContent = lightLabel;
2401
+ btn.setAttribute('aria-label', lightLabel);
2402
+ btn.setAttribute('title', lightLabel);
1463
2403
  btn.setAttribute('aria-pressed', 'true');
1464
2404
  if (icon) icon.setAttribute('name', 'sun');
1465
2405
  } else {
1466
- label.textContent = 'Dunkelmodus aktivieren';
1467
- btn.setAttribute('aria-label', 'Dunkelmodus aktivieren');
1468
- btn.setAttribute('title', 'Dunkelmodus aktivieren');
2406
+ label.textContent = darkLabel;
2407
+ btn.setAttribute('aria-label', darkLabel);
2408
+ btn.setAttribute('title', darkLabel);
1469
2409
  btn.setAttribute('aria-pressed', 'false');
1470
2410
  if (icon) icon.setAttribute('name', 'moon');
1471
2411
  }
@@ -1481,6 +2421,7 @@ document.addEventListener('DOMContentLoaded', function() {
1481
2421
  updateThemeButton();
1482
2422
  document.addEventListener('theme-changed', updateThemeButton);
1483
2423
  document.addEventListener('theme-initialized', updateThemeButton);
2424
+ window.addEventListener('xtend-docs-locale-changed', updateThemeButton);
1484
2425
  // Standardfarben für beide Themes setzen
1485
2426
  if (window.XTend && window.XTend.theme) {
1486
2427
  window.XTend.theme.setTheme('light');
@@ -1589,7 +2530,13 @@ document.addEventListener('DOMContentLoaded', function() {
1589
2530
  function schedulePrismHighlight(root) {
1590
2531
  const scope = root && root.querySelectorAll ? root : document;
1591
2532
  const run = () => {
2533
+ scope.querySelectorAll('x-code').forEach((node) => {
2534
+ if (typeof node.hydrate === 'function') node.hydrate();
2535
+ });
1592
2536
  if (!window.Prism) return;
2537
+ if (window.XTendRmtPrism && typeof window.XTendRmtPrism.register === 'function') {
2538
+ window.XTendRmtPrism.register(window.Prism);
2539
+ }
1593
2540
  if (typeof Prism.highlightAllUnder === 'function') {
1594
2541
  Prism.highlightAllUnder(scope);
1595
2542
  return;