@forgeax/view 0.2.1-beta-20260924075842

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 (585) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +742 -0
  3. package/dist/modules/backend.mjs +54 -0
  4. package/dist/modules/backend.mjs.map +7 -0
  5. package/dist/modules/browser.mjs +180 -0
  6. package/dist/modules/browser.mjs.map +7 -0
  7. package/dist/modules/carrier-contract.mjs +38 -0
  8. package/dist/modules/carrier-contract.mjs.map +7 -0
  9. package/dist/modules/carrier.mjs +13 -0
  10. package/dist/modules/carrier.mjs.map +7 -0
  11. package/dist/modules/chunks/chunk-2ASWB6IX.mjs +225 -0
  12. package/dist/modules/chunks/chunk-2ASWB6IX.mjs.map +7 -0
  13. package/dist/modules/chunks/chunk-2IJKOG2F.mjs +801 -0
  14. package/dist/modules/chunks/chunk-2IJKOG2F.mjs.map +7 -0
  15. package/dist/modules/chunks/chunk-2K3BBJ5S.mjs +9 -0
  16. package/dist/modules/chunks/chunk-2K3BBJ5S.mjs.map +7 -0
  17. package/dist/modules/chunks/chunk-32GD5LL6.mjs +482 -0
  18. package/dist/modules/chunks/chunk-32GD5LL6.mjs.map +7 -0
  19. package/dist/modules/chunks/chunk-3B4KFAEC.mjs +10 -0
  20. package/dist/modules/chunks/chunk-3B4KFAEC.mjs.map +7 -0
  21. package/dist/modules/chunks/chunk-46O5WX43.mjs +25 -0
  22. package/dist/modules/chunks/chunk-46O5WX43.mjs.map +7 -0
  23. package/dist/modules/chunks/chunk-47J5JXAB.mjs +237 -0
  24. package/dist/modules/chunks/chunk-47J5JXAB.mjs.map +7 -0
  25. package/dist/modules/chunks/chunk-4BXQOUDQ.mjs +17 -0
  26. package/dist/modules/chunks/chunk-4BXQOUDQ.mjs.map +7 -0
  27. package/dist/modules/chunks/chunk-4GQWYU2V.mjs +126 -0
  28. package/dist/modules/chunks/chunk-4GQWYU2V.mjs.map +7 -0
  29. package/dist/modules/chunks/chunk-4N5X2PRQ.mjs +48 -0
  30. package/dist/modules/chunks/chunk-4N5X2PRQ.mjs.map +7 -0
  31. package/dist/modules/chunks/chunk-4WXD2KYX.mjs +56 -0
  32. package/dist/modules/chunks/chunk-4WXD2KYX.mjs.map +7 -0
  33. package/dist/modules/chunks/chunk-6ZWWVAZK.mjs +468 -0
  34. package/dist/modules/chunks/chunk-6ZWWVAZK.mjs.map +7 -0
  35. package/dist/modules/chunks/chunk-73UZNRHN.mjs +296 -0
  36. package/dist/modules/chunks/chunk-73UZNRHN.mjs.map +7 -0
  37. package/dist/modules/chunks/chunk-7ITLCRND.mjs +10 -0
  38. package/dist/modules/chunks/chunk-7ITLCRND.mjs.map +7 -0
  39. package/dist/modules/chunks/chunk-7TGVWKH7.mjs +59 -0
  40. package/dist/modules/chunks/chunk-7TGVWKH7.mjs.map +7 -0
  41. package/dist/modules/chunks/chunk-7URFF53W.mjs +42 -0
  42. package/dist/modules/chunks/chunk-7URFF53W.mjs.map +7 -0
  43. package/dist/modules/chunks/chunk-7YSDRIFN.mjs +14 -0
  44. package/dist/modules/chunks/chunk-7YSDRIFN.mjs.map +7 -0
  45. package/dist/modules/chunks/chunk-AAFVCQPK.mjs +52 -0
  46. package/dist/modules/chunks/chunk-AAFVCQPK.mjs.map +7 -0
  47. package/dist/modules/chunks/chunk-AEK7ZESQ.mjs +18 -0
  48. package/dist/modules/chunks/chunk-AEK7ZESQ.mjs.map +7 -0
  49. package/dist/modules/chunks/chunk-AL6ZWIEU.mjs +42 -0
  50. package/dist/modules/chunks/chunk-AL6ZWIEU.mjs.map +7 -0
  51. package/dist/modules/chunks/chunk-ALT7XVMQ.mjs +73 -0
  52. package/dist/modules/chunks/chunk-ALT7XVMQ.mjs.map +7 -0
  53. package/dist/modules/chunks/chunk-ASI2HBE6.mjs +116 -0
  54. package/dist/modules/chunks/chunk-ASI2HBE6.mjs.map +7 -0
  55. package/dist/modules/chunks/chunk-ATWGCH7I.mjs +174 -0
  56. package/dist/modules/chunks/chunk-ATWGCH7I.mjs.map +7 -0
  57. package/dist/modules/chunks/chunk-C45U6IIY.mjs +692 -0
  58. package/dist/modules/chunks/chunk-C45U6IIY.mjs.map +7 -0
  59. package/dist/modules/chunks/chunk-C7R3YRA7.mjs +98 -0
  60. package/dist/modules/chunks/chunk-C7R3YRA7.mjs.map +7 -0
  61. package/dist/modules/chunks/chunk-CRMICXKN.mjs +87 -0
  62. package/dist/modules/chunks/chunk-CRMICXKN.mjs.map +7 -0
  63. package/dist/modules/chunks/chunk-CUH2G6UF.mjs +81 -0
  64. package/dist/modules/chunks/chunk-CUH2G6UF.mjs.map +7 -0
  65. package/dist/modules/chunks/chunk-D7GWRZLL.mjs +77 -0
  66. package/dist/modules/chunks/chunk-D7GWRZLL.mjs.map +7 -0
  67. package/dist/modules/chunks/chunk-DBWUIBE3.mjs +10 -0
  68. package/dist/modules/chunks/chunk-DBWUIBE3.mjs.map +7 -0
  69. package/dist/modules/chunks/chunk-DQWVWWUU.mjs +77 -0
  70. package/dist/modules/chunks/chunk-DQWVWWUU.mjs.map +7 -0
  71. package/dist/modules/chunks/chunk-DZZ2WFEU.mjs +122 -0
  72. package/dist/modules/chunks/chunk-DZZ2WFEU.mjs.map +7 -0
  73. package/dist/modules/chunks/chunk-E4UIAN26.mjs +58 -0
  74. package/dist/modules/chunks/chunk-E4UIAN26.mjs.map +7 -0
  75. package/dist/modules/chunks/chunk-EJGBVKFE.mjs +77 -0
  76. package/dist/modules/chunks/chunk-EJGBVKFE.mjs.map +7 -0
  77. package/dist/modules/chunks/chunk-EPSTTHWV.mjs +173 -0
  78. package/dist/modules/chunks/chunk-EPSTTHWV.mjs.map +7 -0
  79. package/dist/modules/chunks/chunk-ER7T6QJ3.mjs +64 -0
  80. package/dist/modules/chunks/chunk-ER7T6QJ3.mjs.map +7 -0
  81. package/dist/modules/chunks/chunk-FD4BAJ6K.mjs +389 -0
  82. package/dist/modules/chunks/chunk-FD4BAJ6K.mjs.map +7 -0
  83. package/dist/modules/chunks/chunk-FJM6WWIY.mjs +80 -0
  84. package/dist/modules/chunks/chunk-FJM6WWIY.mjs.map +7 -0
  85. package/dist/modules/chunks/chunk-FKCQYDLX.mjs +162 -0
  86. package/dist/modules/chunks/chunk-FKCQYDLX.mjs.map +7 -0
  87. package/dist/modules/chunks/chunk-FLGC65SR.mjs +10 -0
  88. package/dist/modules/chunks/chunk-FLGC65SR.mjs.map +7 -0
  89. package/dist/modules/chunks/chunk-FMCACPX5.mjs +289 -0
  90. package/dist/modules/chunks/chunk-FMCACPX5.mjs.map +7 -0
  91. package/dist/modules/chunks/chunk-FOBRLUQV.mjs +51 -0
  92. package/dist/modules/chunks/chunk-FOBRLUQV.mjs.map +7 -0
  93. package/dist/modules/chunks/chunk-FV3DSKZB.mjs +33 -0
  94. package/dist/modules/chunks/chunk-FV3DSKZB.mjs.map +7 -0
  95. package/dist/modules/chunks/chunk-G7BAFAGO.mjs +98 -0
  96. package/dist/modules/chunks/chunk-G7BAFAGO.mjs.map +7 -0
  97. package/dist/modules/chunks/chunk-GQBZMCTK.mjs +145 -0
  98. package/dist/modules/chunks/chunk-GQBZMCTK.mjs.map +7 -0
  99. package/dist/modules/chunks/chunk-GYWIY7AL.mjs +131 -0
  100. package/dist/modules/chunks/chunk-GYWIY7AL.mjs.map +7 -0
  101. package/dist/modules/chunks/chunk-H3KNBALD.mjs +256 -0
  102. package/dist/modules/chunks/chunk-H3KNBALD.mjs.map +7 -0
  103. package/dist/modules/chunks/chunk-H3M22JDL.mjs +144 -0
  104. package/dist/modules/chunks/chunk-H3M22JDL.mjs.map +7 -0
  105. package/dist/modules/chunks/chunk-HES3DNTM.mjs +40 -0
  106. package/dist/modules/chunks/chunk-HES3DNTM.mjs.map +7 -0
  107. package/dist/modules/chunks/chunk-I5BFP7SS.mjs +2392 -0
  108. package/dist/modules/chunks/chunk-I5BFP7SS.mjs.map +7 -0
  109. package/dist/modules/chunks/chunk-IGRMZYRD.mjs +15 -0
  110. package/dist/modules/chunks/chunk-IGRMZYRD.mjs.map +7 -0
  111. package/dist/modules/chunks/chunk-IKNGC766.mjs +321 -0
  112. package/dist/modules/chunks/chunk-IKNGC766.mjs.map +7 -0
  113. package/dist/modules/chunks/chunk-IVHNYKZB.mjs +35 -0
  114. package/dist/modules/chunks/chunk-IVHNYKZB.mjs.map +7 -0
  115. package/dist/modules/chunks/chunk-JHOURMYW.mjs +101 -0
  116. package/dist/modules/chunks/chunk-JHOURMYW.mjs.map +7 -0
  117. package/dist/modules/chunks/chunk-JURXMRFA.mjs +282 -0
  118. package/dist/modules/chunks/chunk-JURXMRFA.mjs.map +7 -0
  119. package/dist/modules/chunks/chunk-JWZIREC3.mjs +18 -0
  120. package/dist/modules/chunks/chunk-JWZIREC3.mjs.map +7 -0
  121. package/dist/modules/chunks/chunk-KHRTIZ56.mjs +1400 -0
  122. package/dist/modules/chunks/chunk-KHRTIZ56.mjs.map +7 -0
  123. package/dist/modules/chunks/chunk-KLJZZ23J.mjs +102 -0
  124. package/dist/modules/chunks/chunk-KLJZZ23J.mjs.map +7 -0
  125. package/dist/modules/chunks/chunk-KNBAYU5I.mjs +49 -0
  126. package/dist/modules/chunks/chunk-KNBAYU5I.mjs.map +7 -0
  127. package/dist/modules/chunks/chunk-KSZNCFU4.mjs +125 -0
  128. package/dist/modules/chunks/chunk-KSZNCFU4.mjs.map +7 -0
  129. package/dist/modules/chunks/chunk-L45W6KM6.mjs +158 -0
  130. package/dist/modules/chunks/chunk-L45W6KM6.mjs.map +7 -0
  131. package/dist/modules/chunks/chunk-LERMYZRC.mjs +239 -0
  132. package/dist/modules/chunks/chunk-LERMYZRC.mjs.map +7 -0
  133. package/dist/modules/chunks/chunk-LKJCXYSJ.mjs +91 -0
  134. package/dist/modules/chunks/chunk-LKJCXYSJ.mjs.map +7 -0
  135. package/dist/modules/chunks/chunk-MBS3EICT.mjs +25 -0
  136. package/dist/modules/chunks/chunk-MBS3EICT.mjs.map +7 -0
  137. package/dist/modules/chunks/chunk-MUOQZPVH.mjs +609 -0
  138. package/dist/modules/chunks/chunk-MUOQZPVH.mjs.map +7 -0
  139. package/dist/modules/chunks/chunk-MVEPGFSB.mjs +1 -0
  140. package/dist/modules/chunks/chunk-MVEPGFSB.mjs.map +7 -0
  141. package/dist/modules/chunks/chunk-NBJKLWJ5.mjs +42 -0
  142. package/dist/modules/chunks/chunk-NBJKLWJ5.mjs.map +7 -0
  143. package/dist/modules/chunks/chunk-NBLGKTEM.mjs +86 -0
  144. package/dist/modules/chunks/chunk-NBLGKTEM.mjs.map +7 -0
  145. package/dist/modules/chunks/chunk-NI7CS3I2.mjs +110 -0
  146. package/dist/modules/chunks/chunk-NI7CS3I2.mjs.map +7 -0
  147. package/dist/modules/chunks/chunk-NJH2OJFC.mjs +2113 -0
  148. package/dist/modules/chunks/chunk-NJH2OJFC.mjs.map +7 -0
  149. package/dist/modules/chunks/chunk-OBK4LIJB.mjs +20 -0
  150. package/dist/modules/chunks/chunk-OBK4LIJB.mjs.map +7 -0
  151. package/dist/modules/chunks/chunk-PEUT3FW7.mjs +1 -0
  152. package/dist/modules/chunks/chunk-PEUT3FW7.mjs.map +7 -0
  153. package/dist/modules/chunks/chunk-PRZOWPDN.mjs +66 -0
  154. package/dist/modules/chunks/chunk-PRZOWPDN.mjs.map +7 -0
  155. package/dist/modules/chunks/chunk-Q4RXBGQS.mjs +55 -0
  156. package/dist/modules/chunks/chunk-Q4RXBGQS.mjs.map +7 -0
  157. package/dist/modules/chunks/chunk-QBHBKOIL.mjs +55 -0
  158. package/dist/modules/chunks/chunk-QBHBKOIL.mjs.map +7 -0
  159. package/dist/modules/chunks/chunk-QD6CCRMG.mjs +20 -0
  160. package/dist/modules/chunks/chunk-QD6CCRMG.mjs.map +7 -0
  161. package/dist/modules/chunks/chunk-QF4V23GW.mjs +39 -0
  162. package/dist/modules/chunks/chunk-QF4V23GW.mjs.map +7 -0
  163. package/dist/modules/chunks/chunk-QK6W7MJO.mjs +42 -0
  164. package/dist/modules/chunks/chunk-QK6W7MJO.mjs.map +7 -0
  165. package/dist/modules/chunks/chunk-QL7V6DK7.mjs +34 -0
  166. package/dist/modules/chunks/chunk-QL7V6DK7.mjs.map +7 -0
  167. package/dist/modules/chunks/chunk-QLBQQKRI.mjs +25 -0
  168. package/dist/modules/chunks/chunk-QLBQQKRI.mjs.map +7 -0
  169. package/dist/modules/chunks/chunk-QLZQGZDC.mjs +418 -0
  170. package/dist/modules/chunks/chunk-QLZQGZDC.mjs.map +7 -0
  171. package/dist/modules/chunks/chunk-QSKQZGK7.mjs +1625 -0
  172. package/dist/modules/chunks/chunk-QSKQZGK7.mjs.map +7 -0
  173. package/dist/modules/chunks/chunk-QURKBAG4.mjs +25 -0
  174. package/dist/modules/chunks/chunk-QURKBAG4.mjs.map +7 -0
  175. package/dist/modules/chunks/chunk-R274XBEH.mjs +53 -0
  176. package/dist/modules/chunks/chunk-R274XBEH.mjs.map +7 -0
  177. package/dist/modules/chunks/chunk-R4I4JEY5.mjs +77 -0
  178. package/dist/modules/chunks/chunk-R4I4JEY5.mjs.map +7 -0
  179. package/dist/modules/chunks/chunk-RR6L6VVR.mjs +9 -0
  180. package/dist/modules/chunks/chunk-RR6L6VVR.mjs.map +7 -0
  181. package/dist/modules/chunks/chunk-RXF7SBBZ.mjs +125 -0
  182. package/dist/modules/chunks/chunk-RXF7SBBZ.mjs.map +7 -0
  183. package/dist/modules/chunks/chunk-SR66S6EJ.mjs +138 -0
  184. package/dist/modules/chunks/chunk-SR66S6EJ.mjs.map +7 -0
  185. package/dist/modules/chunks/chunk-SSQMQJ52.mjs +27 -0
  186. package/dist/modules/chunks/chunk-SSQMQJ52.mjs.map +7 -0
  187. package/dist/modules/chunks/chunk-TP26TASL.mjs +20 -0
  188. package/dist/modules/chunks/chunk-TP26TASL.mjs.map +7 -0
  189. package/dist/modules/chunks/chunk-TSAEK5P3.mjs +50 -0
  190. package/dist/modules/chunks/chunk-TSAEK5P3.mjs.map +7 -0
  191. package/dist/modules/chunks/chunk-UAY27HT3.mjs +68 -0
  192. package/dist/modules/chunks/chunk-UAY27HT3.mjs.map +7 -0
  193. package/dist/modules/chunks/chunk-UDLIWGWS.mjs +103 -0
  194. package/dist/modules/chunks/chunk-UDLIWGWS.mjs.map +7 -0
  195. package/dist/modules/chunks/chunk-UDVQHPWV.mjs +89 -0
  196. package/dist/modules/chunks/chunk-UDVQHPWV.mjs.map +7 -0
  197. package/dist/modules/chunks/chunk-UM23W3G7.mjs +237 -0
  198. package/dist/modules/chunks/chunk-UM23W3G7.mjs.map +7 -0
  199. package/dist/modules/chunks/chunk-VDZJWEAA.mjs +214 -0
  200. package/dist/modules/chunks/chunk-VDZJWEAA.mjs.map +7 -0
  201. package/dist/modules/chunks/chunk-VIGOJWSO.mjs +42 -0
  202. package/dist/modules/chunks/chunk-VIGOJWSO.mjs.map +7 -0
  203. package/dist/modules/chunks/chunk-VY3S5BWI.mjs +284 -0
  204. package/dist/modules/chunks/chunk-VY3S5BWI.mjs.map +7 -0
  205. package/dist/modules/chunks/chunk-VZXGRZYU.mjs +47 -0
  206. package/dist/modules/chunks/chunk-VZXGRZYU.mjs.map +7 -0
  207. package/dist/modules/chunks/chunk-W5DMQZB5.mjs +42 -0
  208. package/dist/modules/chunks/chunk-W5DMQZB5.mjs.map +7 -0
  209. package/dist/modules/chunks/chunk-WOMHSTVZ.mjs +918 -0
  210. package/dist/modules/chunks/chunk-WOMHSTVZ.mjs.map +7 -0
  211. package/dist/modules/chunks/chunk-XFQT7XCG.mjs +42 -0
  212. package/dist/modules/chunks/chunk-XFQT7XCG.mjs.map +7 -0
  213. package/dist/modules/chunks/chunk-XJZEVRYX.mjs +98 -0
  214. package/dist/modules/chunks/chunk-XJZEVRYX.mjs.map +7 -0
  215. package/dist/modules/chunks/chunk-XUYFV23R.mjs +317 -0
  216. package/dist/modules/chunks/chunk-XUYFV23R.mjs.map +7 -0
  217. package/dist/modules/chunks/chunk-Y5HXCPPQ.mjs +58 -0
  218. package/dist/modules/chunks/chunk-Y5HXCPPQ.mjs.map +7 -0
  219. package/dist/modules/chunks/chunk-YTHGRKGI.mjs +147 -0
  220. package/dist/modules/chunks/chunk-YTHGRKGI.mjs.map +7 -0
  221. package/dist/modules/chunks/chunk-YVQSDKAO.mjs +341 -0
  222. package/dist/modules/chunks/chunk-YVQSDKAO.mjs.map +7 -0
  223. package/dist/modules/chunks/chunk-YYXQDUVT.mjs +123 -0
  224. package/dist/modules/chunks/chunk-YYXQDUVT.mjs.map +7 -0
  225. package/dist/modules/chunks/chunk-ZFXZ2NUI.mjs +142 -0
  226. package/dist/modules/chunks/chunk-ZFXZ2NUI.mjs.map +7 -0
  227. package/dist/modules/chunks/chunk-ZLNWF4ET.mjs +9 -0
  228. package/dist/modules/chunks/chunk-ZLNWF4ET.mjs.map +7 -0
  229. package/dist/modules/chunks/chunk-ZLU5QW2O.mjs +9 -0
  230. package/dist/modules/chunks/chunk-ZLU5QW2O.mjs.map +7 -0
  231. package/dist/modules/chunks/chunk-ZNZPYE2V.mjs +28 -0
  232. package/dist/modules/chunks/chunk-ZNZPYE2V.mjs.map +7 -0
  233. package/dist/modules/chunks/core-564N45MO.mjs +7480 -0
  234. package/dist/modules/chunks/core-564N45MO.mjs.map +7 -0
  235. package/dist/modules/chunks/css-BKH4SVJG.mjs +8 -0
  236. package/dist/modules/chunks/css-BKH4SVJG.mjs.map +7 -0
  237. package/dist/modules/chunks/engine-javascript-PDVIGNGR.mjs +3241 -0
  238. package/dist/modules/chunks/engine-javascript-PDVIGNGR.mjs.map +7 -0
  239. package/dist/modules/chunks/github-dark-default-6HVTHEWF.mjs +8 -0
  240. package/dist/modules/chunks/github-dark-default-6HVTHEWF.mjs.map +7 -0
  241. package/dist/modules/chunks/github-light-default-LAXRA6XL.mjs +8 -0
  242. package/dist/modules/chunks/github-light-default-LAXRA6XL.mjs.map +7 -0
  243. package/dist/modules/chunks/glsl-UC3YWUD2.mjs +18 -0
  244. package/dist/modules/chunks/glsl-UC3YWUD2.mjs.map +7 -0
  245. package/dist/modules/chunks/html-FRVIUV63.mjs +19 -0
  246. package/dist/modules/chunks/html-FRVIUV63.mjs.map +7 -0
  247. package/dist/modules/chunks/javascript-LN3OC7S2.mjs +8 -0
  248. package/dist/modules/chunks/javascript-LN3OC7S2.mjs.map +7 -0
  249. package/dist/modules/chunks/json-5CUGWTOP.mjs +11 -0
  250. package/dist/modules/chunks/json-5CUGWTOP.mjs.map +7 -0
  251. package/dist/modules/chunks/json5-YZQI5VNO.mjs +11 -0
  252. package/dist/modules/chunks/json5-YZQI5VNO.mjs.map +7 -0
  253. package/dist/modules/chunks/jsonc-SWID6VOZ.mjs +11 -0
  254. package/dist/modules/chunks/jsonc-SWID6VOZ.mjs.map +7 -0
  255. package/dist/modules/chunks/jsx-A7RDCLJO.mjs +11 -0
  256. package/dist/modules/chunks/jsx-A7RDCLJO.mjs.map +7 -0
  257. package/dist/modules/chunks/markdown-QTCU5KP5.mjs +11 -0
  258. package/dist/modules/chunks/markdown-QTCU5KP5.mjs.map +7 -0
  259. package/dist/modules/chunks/python-LAZONBIB.mjs +11 -0
  260. package/dist/modules/chunks/python-LAZONBIB.mjs.map +7 -0
  261. package/dist/modules/chunks/rust-XWTPJFJO.mjs +11 -0
  262. package/dist/modules/chunks/rust-XWTPJFJO.mjs.map +7 -0
  263. package/dist/modules/chunks/scss-CFXRHUUW.mjs +15 -0
  264. package/dist/modules/chunks/scss-CFXRHUUW.mjs.map +7 -0
  265. package/dist/modules/chunks/shellscript-OHO3LCVU.mjs +11 -0
  266. package/dist/modules/chunks/shellscript-OHO3LCVU.mjs.map +7 -0
  267. package/dist/modules/chunks/toml-IOHFZJ5B.mjs +11 -0
  268. package/dist/modules/chunks/toml-IOHFZJ5B.mjs.map +7 -0
  269. package/dist/modules/chunks/tsx-2E6WNX2E.mjs +11 -0
  270. package/dist/modules/chunks/tsx-2E6WNX2E.mjs.map +7 -0
  271. package/dist/modules/chunks/typescript-PBKAS54P.mjs +11 -0
  272. package/dist/modules/chunks/typescript-PBKAS54P.mjs.map +7 -0
  273. package/dist/modules/chunks/wgsl-PS6QPRLZ.mjs +11 -0
  274. package/dist/modules/chunks/wgsl-PS6QPRLZ.mjs.map +7 -0
  275. package/dist/modules/chunks/xml-JECR2ACB.mjs +18 -0
  276. package/dist/modules/chunks/xml-JECR2ACB.mjs.map +7 -0
  277. package/dist/modules/chunks/yaml-P2SV4LOE.mjs +11 -0
  278. package/dist/modules/chunks/yaml-P2SV4LOE.mjs.map +7 -0
  279. package/dist/modules/cli-contributions.mjs +32 -0
  280. package/dist/modules/cli-contributions.mjs.map +7 -0
  281. package/dist/modules/cli.mjs +14 -0
  282. package/dist/modules/cli.mjs.map +7 -0
  283. package/dist/modules/command-executor.mjs +65 -0
  284. package/dist/modules/command-executor.mjs.map +7 -0
  285. package/dist/modules/commands.mjs +10 -0
  286. package/dist/modules/commands.mjs.map +7 -0
  287. package/dist/modules/embedded.mjs +18608 -0
  288. package/dist/modules/embedded.mjs.map +7 -0
  289. package/dist/modules/extension-bridge.mjs +18 -0
  290. package/dist/modules/extension-bridge.mjs.map +7 -0
  291. package/dist/modules/frontend-root.mjs +61 -0
  292. package/dist/modules/frontend-root.mjs.map +7 -0
  293. package/dist/modules/index.mjs +784 -0
  294. package/dist/modules/index.mjs.map +7 -0
  295. package/dist/modules/page.mjs +45 -0
  296. package/dist/modules/page.mjs.map +7 -0
  297. package/dist/modules/pages/scene.mjs +18 -0
  298. package/dist/modules/pages/scene.mjs.map +7 -0
  299. package/dist/modules/plugin.mjs +56 -0
  300. package/dist/modules/plugin.mjs.map +7 -0
  301. package/dist/modules/plugins/asset/frontend.mjs +23 -0
  302. package/dist/modules/plugins/asset/frontend.mjs.map +7 -0
  303. package/dist/modules/plugins/asset/i18n.mjs +15 -0
  304. package/dist/modules/plugins/asset/i18n.mjs.map +7 -0
  305. package/dist/modules/plugins/asset/identity.mjs +42 -0
  306. package/dist/modules/plugins/asset/identity.mjs.map +7 -0
  307. package/dist/modules/plugins/asset/schema.mjs +10 -0
  308. package/dist/modules/plugins/asset/schema.mjs.map +7 -0
  309. package/dist/modules/plugins/asset/ui.mjs +16 -0
  310. package/dist/modules/plugins/asset/ui.mjs.map +7 -0
  311. package/dist/modules/plugins/content-browser/frontend.mjs +17 -0
  312. package/dist/modules/plugins/content-browser/frontend.mjs.map +7 -0
  313. package/dist/modules/plugins/content-browser/i18n.mjs +15 -0
  314. package/dist/modules/plugins/content-browser/i18n.mjs.map +7 -0
  315. package/dist/modules/plugins/content-browser/identity.mjs +22 -0
  316. package/dist/modules/plugins/content-browser/identity.mjs.map +7 -0
  317. package/dist/modules/plugins/content-browser/schema.mjs +12 -0
  318. package/dist/modules/plugins/content-browser/schema.mjs.map +7 -0
  319. package/dist/modules/plugins/content-browser/ui.mjs +15 -0
  320. package/dist/modules/plugins/content-browser/ui.mjs.map +7 -0
  321. package/dist/modules/plugins/display/api.mjs +10 -0
  322. package/dist/modules/plugins/display/api.mjs.map +7 -0
  323. package/dist/modules/plugins/display/backend.mjs +16 -0
  324. package/dist/modules/plugins/display/backend.mjs.map +7 -0
  325. package/dist/modules/plugins/display/carrier-contract.mjs +38 -0
  326. package/dist/modules/plugins/display/carrier-contract.mjs.map +7 -0
  327. package/dist/modules/plugins/display/carrier.mjs +13 -0
  328. package/dist/modules/plugins/display/carrier.mjs.map +7 -0
  329. package/dist/modules/plugins/display/effects.mjs +8 -0
  330. package/dist/modules/plugins/display/effects.mjs.map +7 -0
  331. package/dist/modules/plugins/display/frontend.mjs +14 -0
  332. package/dist/modules/plugins/display/frontend.mjs.map +7 -0
  333. package/dist/modules/plugins/display/i18n.mjs +58 -0
  334. package/dist/modules/plugins/display/i18n.mjs.map +7 -0
  335. package/dist/modules/plugins/display/identity.mjs +30 -0
  336. package/dist/modules/plugins/display/identity.mjs.map +7 -0
  337. package/dist/modules/plugins/display/page-broker.mjs +12 -0
  338. package/dist/modules/plugins/display/page-broker.mjs.map +7 -0
  339. package/dist/modules/plugins/display/schema.mjs +40 -0
  340. package/dist/modules/plugins/display/schema.mjs.map +7 -0
  341. package/dist/modules/plugins/display/ui.mjs +9 -0
  342. package/dist/modules/plugins/display/ui.mjs.map +7 -0
  343. package/dist/modules/plugins/inspector/frontend.mjs +17 -0
  344. package/dist/modules/plugins/inspector/frontend.mjs.map +7 -0
  345. package/dist/modules/plugins/inspector/i18n.mjs +15 -0
  346. package/dist/modules/plugins/inspector/i18n.mjs.map +7 -0
  347. package/dist/modules/plugins/inspector/identity.mjs +22 -0
  348. package/dist/modules/plugins/inspector/identity.mjs.map +7 -0
  349. package/dist/modules/plugins/inspector/schema.mjs +12 -0
  350. package/dist/modules/plugins/inspector/schema.mjs.map +7 -0
  351. package/dist/modules/plugins/inspector/ui.mjs +16 -0
  352. package/dist/modules/plugins/inspector/ui.mjs.map +7 -0
  353. package/dist/modules/plugins/material/frontend.mjs +25 -0
  354. package/dist/modules/plugins/material/frontend.mjs.map +7 -0
  355. package/dist/modules/plugins/material/i18n.mjs +15 -0
  356. package/dist/modules/plugins/material/i18n.mjs.map +7 -0
  357. package/dist/modules/plugins/material/identity.mjs +60 -0
  358. package/dist/modules/plugins/material/identity.mjs.map +7 -0
  359. package/dist/modules/plugins/material/schema.mjs +47 -0
  360. package/dist/modules/plugins/material/schema.mjs.map +7 -0
  361. package/dist/modules/plugins/material/ui.mjs +28 -0
  362. package/dist/modules/plugins/material/ui.mjs.map +7 -0
  363. package/dist/modules/plugins/mesh/frontend.mjs +23 -0
  364. package/dist/modules/plugins/mesh/frontend.mjs.map +7 -0
  365. package/dist/modules/plugins/mesh/i18n.mjs +15 -0
  366. package/dist/modules/plugins/mesh/i18n.mjs.map +7 -0
  367. package/dist/modules/plugins/mesh/identity.mjs +54 -0
  368. package/dist/modules/plugins/mesh/identity.mjs.map +7 -0
  369. package/dist/modules/plugins/mesh/schema.mjs +10 -0
  370. package/dist/modules/plugins/mesh/schema.mjs.map +7 -0
  371. package/dist/modules/plugins/mesh/ui.mjs +26 -0
  372. package/dist/modules/plugins/mesh/ui.mjs.map +7 -0
  373. package/dist/modules/plugins/plugins/api.mjs +11 -0
  374. package/dist/modules/plugins/plugins/api.mjs.map +7 -0
  375. package/dist/modules/plugins/plugins/backend.mjs +21 -0
  376. package/dist/modules/plugins/plugins/backend.mjs.map +7 -0
  377. package/dist/modules/plugins/plugins/cli.mjs +12 -0
  378. package/dist/modules/plugins/plugins/cli.mjs.map +7 -0
  379. package/dist/modules/plugins/plugins/frontend.mjs +17 -0
  380. package/dist/modules/plugins/plugins/frontend.mjs.map +7 -0
  381. package/dist/modules/plugins/plugins/i18n.mjs +15 -0
  382. package/dist/modules/plugins/plugins/i18n.mjs.map +7 -0
  383. package/dist/modules/plugins/plugins/identity.mjs +26 -0
  384. package/dist/modules/plugins/plugins/identity.mjs.map +7 -0
  385. package/dist/modules/plugins/plugins/runtime.mjs +50 -0
  386. package/dist/modules/plugins/plugins/runtime.mjs.map +7 -0
  387. package/dist/modules/plugins/plugins/schema.mjs +12 -0
  388. package/dist/modules/plugins/plugins/schema.mjs.map +7 -0
  389. package/dist/modules/plugins/plugins/ui/panel.mjs +14 -0
  390. package/dist/modules/plugins/plugins/ui/panel.mjs.map +7 -0
  391. package/dist/modules/plugins/plugins/ui.mjs +15 -0
  392. package/dist/modules/plugins/plugins/ui.mjs.map +7 -0
  393. package/dist/modules/plugins/scene/frontend.mjs +18 -0
  394. package/dist/modules/plugins/scene/frontend.mjs.map +7 -0
  395. package/dist/modules/plugins/scene/identity.mjs +14 -0
  396. package/dist/modules/plugins/scene/identity.mjs.map +7 -0
  397. package/dist/modules/plugins/scene-tree/frontend.mjs +17 -0
  398. package/dist/modules/plugins/scene-tree/frontend.mjs.map +7 -0
  399. package/dist/modules/plugins/scene-tree/i18n.mjs +15 -0
  400. package/dist/modules/plugins/scene-tree/i18n.mjs.map +7 -0
  401. package/dist/modules/plugins/scene-tree/identity.mjs +22 -0
  402. package/dist/modules/plugins/scene-tree/identity.mjs.map +7 -0
  403. package/dist/modules/plugins/scene-tree/schema.mjs +12 -0
  404. package/dist/modules/plugins/scene-tree/schema.mjs.map +7 -0
  405. package/dist/modules/plugins/scene-tree/ui.mjs +16 -0
  406. package/dist/modules/plugins/scene-tree/ui.mjs.map +7 -0
  407. package/dist/modules/plugins/texture/frontend.mjs +23 -0
  408. package/dist/modules/plugins/texture/frontend.mjs.map +7 -0
  409. package/dist/modules/plugins/texture/i18n.mjs +15 -0
  410. package/dist/modules/plugins/texture/i18n.mjs.map +7 -0
  411. package/dist/modules/plugins/texture/identity.mjs +54 -0
  412. package/dist/modules/plugins/texture/identity.mjs.map +7 -0
  413. package/dist/modules/plugins/texture/schema.mjs +10 -0
  414. package/dist/modules/plugins/texture/schema.mjs.map +7 -0
  415. package/dist/modules/plugins/texture/ui.mjs +26 -0
  416. package/dist/modules/plugins/texture/ui.mjs.map +7 -0
  417. package/dist/modules/plugins/viewport/frontend.mjs +27 -0
  418. package/dist/modules/plugins/viewport/frontend.mjs.map +7 -0
  419. package/dist/modules/plugins/viewport/identity.mjs +28 -0
  420. package/dist/modules/plugins/viewport/identity.mjs.map +7 -0
  421. package/dist/modules/plugins/viewport/presentation-identity.mjs +10 -0
  422. package/dist/modules/plugins/viewport/presentation-identity.mjs.map +7 -0
  423. package/dist/modules/plugins/viewport/presentation.mjs +18 -0
  424. package/dist/modules/plugins/viewport/presentation.mjs.map +7 -0
  425. package/dist/modules/plugins/viewport/schema.mjs +18 -0
  426. package/dist/modules/plugins/viewport/schema.mjs.map +7 -0
  427. package/dist/modules/plugins/viewport/workspace-shell.mjs +29 -0
  428. package/dist/modules/plugins/viewport/workspace-shell.mjs.map +7 -0
  429. package/dist/modules/shell/contract.mjs +10 -0
  430. package/dist/modules/shell/contract.mjs.map +7 -0
  431. package/dist/modules/shell/frontend.mjs +14 -0
  432. package/dist/modules/shell/frontend.mjs.map +7 -0
  433. package/dist/modules/shell/layout-zones.mjs +20 -0
  434. package/dist/modules/shell/layout-zones.mjs.map +7 -0
  435. package/dist/modules/start-cli.mjs +57 -0
  436. package/dist/modules/start-cli.mjs.map +7 -0
  437. package/dist/modules/start.mjs +18 -0
  438. package/dist/modules/start.mjs.map +7 -0
  439. package/dist/modules/viewer/catalog/backend.mjs +47 -0
  440. package/dist/modules/viewer/catalog/backend.mjs.map +7 -0
  441. package/dist/modules/viewer/catalog/frontend.mjs +55 -0
  442. package/dist/modules/viewer/catalog/frontend.mjs.map +7 -0
  443. package/dist/modules/viewer/catalog/shared.mjs +43 -0
  444. package/dist/modules/viewer/catalog/shared.mjs.map +7 -0
  445. package/dist/modules/viewer/catalog.mjs +85 -0
  446. package/dist/modules/viewer/catalog.mjs.map +7 -0
  447. package/dist/modules/viewer/cli.mjs +23 -0
  448. package/dist/modules/viewer/cli.mjs.map +7 -0
  449. package/dist/modules/viewer-host/frontend.mjs +65 -0
  450. package/dist/modules/viewer-host/frontend.mjs.map +7 -0
  451. package/dist/modules/viewer-host/page-registry.mjs +27 -0
  452. package/dist/modules/viewer-host/page-registry.mjs.map +7 -0
  453. package/dist/modules/viewer-host/slot-registry.mjs +8 -0
  454. package/dist/modules/viewer-host/slot-registry.mjs.map +7 -0
  455. package/dist/modules/viewer-host.mjs +43 -0
  456. package/dist/modules/viewer-host.mjs.map +7 -0
  457. package/dist/modules/viewer.mjs +85 -0
  458. package/dist/modules/viewer.mjs.map +7 -0
  459. package/dist/modules/workspace/adopt-surface.mjs +16 -0
  460. package/dist/modules/workspace/adopt-surface.mjs.map +7 -0
  461. package/dist/modules/workspace/api.mjs +8 -0
  462. package/dist/modules/workspace/api.mjs.map +7 -0
  463. package/dist/modules/workspace/backend.mjs +23 -0
  464. package/dist/modules/workspace/backend.mjs.map +7 -0
  465. package/dist/modules/workspace/broker.mjs +16 -0
  466. package/dist/modules/workspace/broker.mjs.map +7 -0
  467. package/dist/modules/workspace/cli.mjs +9 -0
  468. package/dist/modules/workspace/cli.mjs.map +7 -0
  469. package/dist/modules/workspace/client.mjs +15 -0
  470. package/dist/modules/workspace/client.mjs.map +7 -0
  471. package/dist/modules/workspace/command-error.mjs +16 -0
  472. package/dist/modules/workspace/command-error.mjs.map +7 -0
  473. package/dist/modules/workspace/contract.mjs +71 -0
  474. package/dist/modules/workspace/contract.mjs.map +7 -0
  475. package/dist/modules/workspace/demo-client.mjs +127 -0
  476. package/dist/modules/workspace/demo-client.mjs.map +7 -0
  477. package/dist/modules/workspace/engine-adapter.mjs +16 -0
  478. package/dist/modules/workspace/engine-adapter.mjs.map +7 -0
  479. package/dist/modules/workspace/engine-presentation.mjs +10 -0
  480. package/dist/modules/workspace/engine-presentation.mjs.map +7 -0
  481. package/dist/modules/workspace/extension-bridge.mjs +18 -0
  482. package/dist/modules/workspace/extension-bridge.mjs.map +7 -0
  483. package/dist/modules/workspace/frontend-plugin.mjs +18 -0
  484. package/dist/modules/workspace/frontend-plugin.mjs.map +7 -0
  485. package/dist/modules/workspace/frontend.mjs +29 -0
  486. package/dist/modules/workspace/frontend.mjs.map +7 -0
  487. package/dist/modules/workspace/id.mjs +8 -0
  488. package/dist/modules/workspace/id.mjs.map +7 -0
  489. package/dist/modules/workspace/inspection-presentation.mjs +12 -0
  490. package/dist/modules/workspace/inspection-presentation.mjs.map +7 -0
  491. package/dist/modules/workspace/locale-bridge.mjs +14 -0
  492. package/dist/modules/workspace/locale-bridge.mjs.map +7 -0
  493. package/dist/modules/workspace/page-title.mjs +13 -0
  494. package/dist/modules/workspace/page-title.mjs.map +7 -0
  495. package/dist/modules/workspace/presentation.mjs +18 -0
  496. package/dist/modules/workspace/presentation.mjs.map +7 -0
  497. package/dist/modules/workspace/preview-surface.mjs +17 -0
  498. package/dist/modules/workspace/preview-surface.mjs.map +7 -0
  499. package/dist/modules/workspace/project-session.mjs +18 -0
  500. package/dist/modules/workspace/project-session.mjs.map +7 -0
  501. package/dist/modules/workspace/render-resize-sync.mjs +12 -0
  502. package/dist/modules/workspace/render-resize-sync.mjs.map +7 -0
  503. package/dist/modules/workspace/resident.mjs +16 -0
  504. package/dist/modules/workspace/resident.mjs.map +7 -0
  505. package/dist/modules/workspace/resource-open.mjs +34 -0
  506. package/dist/modules/workspace/resource-open.mjs.map +7 -0
  507. package/dist/modules/workspace/resource-page.mjs +27 -0
  508. package/dist/modules/workspace/resource-page.mjs.map +7 -0
  509. package/dist/modules/workspace/tool-runtime.mjs +14 -0
  510. package/dist/modules/workspace/tool-runtime.mjs.map +7 -0
  511. package/dist/modules/workspace/view-trace.mjs +60 -0
  512. package/dist/modules/workspace/view-trace.mjs.map +7 -0
  513. package/dist/modules/workspace/workspace-client-connection.mjs +22 -0
  514. package/dist/modules/workspace/workspace-client-connection.mjs.map +7 -0
  515. package/dist/modules/workspace/workspace-recovery.mjs +35 -0
  516. package/dist/modules/workspace/workspace-recovery.mjs.map +7 -0
  517. package/dist/modules/workspace/workspace-state.mjs +12 -0
  518. package/dist/modules/workspace/workspace-state.mjs.map +7 -0
  519. package/dist/modules/workspace-frontend.mjs +17 -0
  520. package/dist/modules/workspace-frontend.mjs.map +7 -0
  521. package/dist/viewer/assets/chunk-CilyBKbf.js +1 -0
  522. package/dist/viewer/assets/core-DSQma37-.js +13 -0
  523. package/dist/viewer/assets/core-DSQma37-.js.map +1 -0
  524. package/dist/viewer/assets/css-Bq1BXecw.js +2 -0
  525. package/dist/viewer/assets/css-Bq1BXecw.js.map +1 -0
  526. package/dist/viewer/assets/css-CWQWazmX.js +1 -0
  527. package/dist/viewer/assets/embedded-D4ZDx--W.js +2 -0
  528. package/dist/viewer/assets/embedded-D4ZDx--W.js.map +1 -0
  529. package/dist/viewer/assets/engine-javascript-BvokIV9O.js +142 -0
  530. package/dist/viewer/assets/engine-javascript-BvokIV9O.js.map +1 -0
  531. package/dist/viewer/assets/github-dark-default-DaDlj-WZ.js +2 -0
  532. package/dist/viewer/assets/github-dark-default-DaDlj-WZ.js.map +1 -0
  533. package/dist/viewer/assets/github-light-default-BqhWxAZd.js +2 -0
  534. package/dist/viewer/assets/github-light-default-BqhWxAZd.js.map +1 -0
  535. package/dist/viewer/assets/glsl-BJgVnv11.js +2 -0
  536. package/dist/viewer/assets/glsl-BJgVnv11.js.map +1 -0
  537. package/dist/viewer/assets/html-AaaHGGyt.js +2 -0
  538. package/dist/viewer/assets/html-AaaHGGyt.js.map +1 -0
  539. package/dist/viewer/assets/javascript-BX9W64FE.js +1 -0
  540. package/dist/viewer/assets/javascript-DQODvD07.js +2 -0
  541. package/dist/viewer/assets/javascript-DQODvD07.js.map +1 -0
  542. package/dist/viewer/assets/json-CpcIDpT7.js +2 -0
  543. package/dist/viewer/assets/json-CpcIDpT7.js.map +1 -0
  544. package/dist/viewer/assets/json5-Czq4A7dk.js +2 -0
  545. package/dist/viewer/assets/json5-Czq4A7dk.js.map +1 -0
  546. package/dist/viewer/assets/jsonc-BXDfCMmu.js +2 -0
  547. package/dist/viewer/assets/jsonc-BXDfCMmu.js.map +1 -0
  548. package/dist/viewer/assets/jsx-DAWscEnf.js +2 -0
  549. package/dist/viewer/assets/jsx-DAWscEnf.js.map +1 -0
  550. package/dist/viewer/assets/main-C-2CHTN_.js +15 -0
  551. package/dist/viewer/assets/main-C-2CHTN_.js.map +1 -0
  552. package/dist/viewer/assets/markdown-Cx1FMNw-.js +2 -0
  553. package/dist/viewer/assets/markdown-Cx1FMNw-.js.map +1 -0
  554. package/dist/viewer/assets/panels-entry-Ddhfjgf0.js +46 -0
  555. package/dist/viewer/assets/panels-entry-Ddhfjgf0.js.map +1 -0
  556. package/dist/viewer/assets/python-CYPKjWV9.js +2 -0
  557. package/dist/viewer/assets/python-CYPKjWV9.js.map +1 -0
  558. package/dist/viewer/assets/rust-0e5cNx_V.js +2 -0
  559. package/dist/viewer/assets/rust-0e5cNx_V.js.map +1 -0
  560. package/dist/viewer/assets/scss-B-aKzLbT.js +2 -0
  561. package/dist/viewer/assets/scss-B-aKzLbT.js.map +1 -0
  562. package/dist/viewer/assets/shellscript-CpXD-pSm.js +2 -0
  563. package/dist/viewer/assets/shellscript-CpXD-pSm.js.map +1 -0
  564. package/dist/viewer/assets/style-ClttNKZk.css +2 -0
  565. package/dist/viewer/assets/styles-BXozhwiU.js +11 -0
  566. package/dist/viewer/assets/styles-BXozhwiU.js.map +1 -0
  567. package/dist/viewer/assets/toml-GmchYTXa.js +2 -0
  568. package/dist/viewer/assets/toml-GmchYTXa.js.map +1 -0
  569. package/dist/viewer/assets/tsx-Crj1Bi53.js +2 -0
  570. package/dist/viewer/assets/tsx-Crj1Bi53.js.map +1 -0
  571. package/dist/viewer/assets/typescript-xi0cSHCO.js +2 -0
  572. package/dist/viewer/assets/typescript-xi0cSHCO.js.map +1 -0
  573. package/dist/viewer/assets/wgsl-BoEPRo9U.js +2 -0
  574. package/dist/viewer/assets/wgsl-BoEPRo9U.js.map +1 -0
  575. package/dist/viewer/assets/xml-B8JqQrMD.js +2 -0
  576. package/dist/viewer/assets/xml-B8JqQrMD.js.map +1 -0
  577. package/dist/viewer/assets/yaml-DsIB85X9.js +2 -0
  578. package/dist/viewer/assets/yaml-DsIB85X9.js.map +1 -0
  579. package/dist/viewer/index.html +15 -0
  580. package/dist/viewer/panels.js +1 -0
  581. package/host.pack.json +13 -0
  582. package/package.json +174 -0
  583. package/skills/forgeax-view-cli/SKILL.md +74 -0
  584. package/skills/forgeax-view-start/SKILL.md +202 -0
  585. package/skills/forgeax-view-start/scripts/start-view.mjs +202 -0
@@ -0,0 +1,2113 @@
1
+ // packages/view-components/src/components.tsx
2
+ import {
3
+ AlertCircle,
4
+ Check,
5
+ ChevronDown,
6
+ ChevronRight,
7
+ CircleAlert,
8
+ CircleCheck,
9
+ Info,
10
+ LoaderCircle,
11
+ Search,
12
+ X
13
+ } from "lucide-react";
14
+ import {
15
+ cloneElement,
16
+ createContext,
17
+ forwardRef,
18
+ useCallback,
19
+ useContext,
20
+ useEffect,
21
+ useId,
22
+ useImperativeHandle,
23
+ useLayoutEffect,
24
+ useMemo,
25
+ useRef,
26
+ useState
27
+ } from "react";
28
+ import { createPortal } from "react-dom";
29
+
30
+ // packages/view-components/src/menuPlacement.ts
31
+ var DEFAULT_PREFERENCE = ["right", "left", "bottom", "top"];
32
+ function viewportSize() {
33
+ return {
34
+ width: window.innerWidth,
35
+ height: window.innerHeight
36
+ };
37
+ }
38
+ function candidatePosition(placement, anchor, menuWidth, menuHeight, gap) {
39
+ switch (placement) {
40
+ case "right":
41
+ return { x: anchor.right + gap, y: anchor.top };
42
+ case "left":
43
+ return { x: anchor.left - gap - menuWidth, y: anchor.top };
44
+ case "bottom":
45
+ return { x: anchor.left + anchor.width / 2 - menuWidth / 2, y: anchor.bottom + gap };
46
+ case "top":
47
+ return { x: anchor.left + anchor.width / 2 - menuWidth / 2, y: anchor.top - gap - menuHeight };
48
+ }
49
+ }
50
+ function fitsHorizontally(x, menuWidth, padding) {
51
+ const { width } = viewportSize();
52
+ return x >= padding && x + menuWidth <= width - padding;
53
+ }
54
+ function fitsVertically(y, menuHeight, padding) {
55
+ const { height } = viewportSize();
56
+ return y >= padding && y + menuHeight <= height - padding;
57
+ }
58
+ function fitsViewport(x, y, menuWidth, menuHeight, padding) {
59
+ return fitsHorizontally(x, menuWidth, padding) && fitsVertically(y, menuHeight, padding);
60
+ }
61
+ function visibleArea(x, y, menuWidth, menuHeight, padding) {
62
+ const { width, height } = viewportSize();
63
+ const left = Math.max(x, padding);
64
+ const top = Math.max(y, padding);
65
+ const right = Math.min(x + menuWidth, width - padding);
66
+ const bottom = Math.min(y + menuHeight, height - padding);
67
+ return Math.max(0, right - left) * Math.max(0, bottom - top);
68
+ }
69
+ function clampForPlacement(placement, x, y, menuWidth, menuHeight, padding) {
70
+ const { width, height } = viewportSize();
71
+ if (placement === "right" || placement === "left") {
72
+ return {
73
+ x: Math.max(padding, Math.min(x, width - padding - menuWidth)),
74
+ y: Math.max(padding, Math.min(y, height - padding - menuHeight))
75
+ };
76
+ }
77
+ return {
78
+ x: Math.max(padding, Math.min(x, width - padding - menuWidth)),
79
+ y: Math.max(padding, Math.min(y, height - padding - menuHeight))
80
+ };
81
+ }
82
+ function resolveFloatingMenuPosition(anchor, menuWidth, menuHeight, options = {}) {
83
+ const gap = options.gap ?? 8;
84
+ const padding = options.padding ?? 8;
85
+ const preference = options.preference ?? DEFAULT_PREFERENCE;
86
+ let best = preference[0];
87
+ let bestPoint = candidatePosition(best, anchor, menuWidth, menuHeight, gap);
88
+ let bestScore = -1;
89
+ for (const placement of preference) {
90
+ const point = candidatePosition(placement, anchor, menuWidth, menuHeight, gap);
91
+ const horizontal = placement === "right" || placement === "left";
92
+ const vertical = placement === "top" || placement === "bottom";
93
+ if (horizontal && fitsHorizontally(point.x, menuWidth, padding)) {
94
+ return { ...clampForPlacement(placement, point.x, point.y, menuWidth, menuHeight, padding), placement };
95
+ }
96
+ if (vertical && fitsVertically(point.y, menuHeight, padding)) {
97
+ return { ...clampForPlacement(placement, point.x, point.y, menuWidth, menuHeight, padding), placement };
98
+ }
99
+ if (fitsViewport(point.x, point.y, menuWidth, menuHeight, padding)) {
100
+ return { ...point, placement };
101
+ }
102
+ const score = visibleArea(point.x, point.y, menuWidth, menuHeight, padding);
103
+ if (score > bestScore) {
104
+ bestScore = score;
105
+ best = placement;
106
+ bestPoint = point;
107
+ }
108
+ }
109
+ const clamped = clampForPlacement(best, bestPoint.x, bestPoint.y, menuWidth, menuHeight, padding);
110
+ return { ...clamped, placement: best };
111
+ }
112
+ function anchorRectFromPoint(x, y) {
113
+ return { top: y, right: x, bottom: y, left: x, width: 0, height: 0 };
114
+ }
115
+ function resolveMenuDropdownPosition(anchor, menuWidth, menuHeight, align, options = {}) {
116
+ const gap = options.gap ?? 4;
117
+ const padding = options.padding ?? 8;
118
+ const { width: viewportWidth, height: viewportHeight } = viewportSize();
119
+ let x = align === "end" ? anchor.right - menuWidth : anchor.left;
120
+ let y = anchor.bottom + gap;
121
+ const spaceBelow = viewportHeight - padding - anchor.bottom - gap;
122
+ const spaceAbove = anchor.top - gap - padding;
123
+ if (menuHeight > spaceBelow && spaceAbove > spaceBelow) {
124
+ y = anchor.top - gap - menuHeight;
125
+ }
126
+ x = Math.max(padding, Math.min(x, viewportWidth - padding - menuWidth));
127
+ y = Math.max(padding, Math.min(y, viewportHeight - padding - menuHeight));
128
+ return { x, y };
129
+ }
130
+
131
+ // packages/view-components/src/components.tsx
132
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
133
+ import { createElement } from "react";
134
+ var OverlayRootContext = createContext(null);
135
+ function OverlayRootProvider({ root, children }) {
136
+ return /* @__PURE__ */ jsx(OverlayRootContext.Provider, { value: root, children });
137
+ }
138
+ function useOverlayRoot() {
139
+ return useContext(OverlayRootContext);
140
+ }
141
+ function classes(...names) {
142
+ return names.filter(Boolean).join(" ");
143
+ }
144
+ function Text({
145
+ as: Component = "p",
146
+ variant = "ui",
147
+ tone = "primary",
148
+ className,
149
+ ...props
150
+ }) {
151
+ return /* @__PURE__ */ jsx(
152
+ Component,
153
+ {
154
+ ...props,
155
+ className: classes(
156
+ "fx-text",
157
+ `fx-text--${variant}`,
158
+ tone !== "primary" && `fx-text--${tone}`,
159
+ className
160
+ )
161
+ }
162
+ );
163
+ }
164
+ var Surface = forwardRef(function Surface2({ tone = "canvas", card = false, className, ...props }, ref) {
165
+ return /* @__PURE__ */ jsx(
166
+ "div",
167
+ {
168
+ ...props,
169
+ ref,
170
+ className: classes("fx-surface", `fx-surface--${tone}`, card && "fx-surface--card", className)
171
+ }
172
+ );
173
+ });
174
+ var Link = forwardRef(function Link2({ className, ...props }, ref) {
175
+ return /* @__PURE__ */ jsx("a", { ...props, ref, className: classes("fx-link", className) });
176
+ });
177
+ var Button = forwardRef(function Button2({
178
+ variant = "secondary",
179
+ size = "default",
180
+ loading = false,
181
+ leadingIcon,
182
+ trailingIcon,
183
+ disabled,
184
+ className,
185
+ children,
186
+ type = "button",
187
+ ...props
188
+ }, ref) {
189
+ return /* @__PURE__ */ jsxs(
190
+ "button",
191
+ {
192
+ ...props,
193
+ ref,
194
+ type,
195
+ disabled: disabled || loading,
196
+ "aria-busy": loading || void 0,
197
+ className: classes(
198
+ "fx-button",
199
+ `fx-button--${variant}`,
200
+ size !== "default" && `fx-button--${size}`,
201
+ className
202
+ ),
203
+ children: [
204
+ loading ? /* @__PURE__ */ jsx(LoaderCircle, { className: "fx-icon fx-button__spinner", "aria-hidden": true }) : leadingIcon,
205
+ children,
206
+ !loading && trailingIcon
207
+ ]
208
+ }
209
+ );
210
+ });
211
+ var IconButton = forwardRef(function IconButton2({ label, icon, className, ...props }, ref) {
212
+ return /* @__PURE__ */ jsx(
213
+ Button,
214
+ {
215
+ ...props,
216
+ ref,
217
+ "aria-label": label,
218
+ title: props.title ?? label,
219
+ className: classes("fx-button--icon", className),
220
+ children: icon
221
+ }
222
+ );
223
+ });
224
+ function Field({ label, htmlFor, note, error, children, className, ...props }) {
225
+ return /* @__PURE__ */ jsxs("div", { ...props, className: classes("fx-field", className), children: [
226
+ /* @__PURE__ */ jsx("label", { className: "fx-field__label", htmlFor, children: label }),
227
+ children,
228
+ (error || note) && /* @__PURE__ */ jsx("p", { className: classes("fx-field__note", Boolean(error) && "fx-field__error"), role: error ? "alert" : void 0, children: error ?? note })
229
+ ] });
230
+ }
231
+ var TextInput = forwardRef(
232
+ function TextInput2({ className, ...props }, ref) {
233
+ return /* @__PURE__ */ jsx("input", { ...props, ref, className: classes("fx-input", className) });
234
+ }
235
+ );
236
+ var Select = forwardRef(
237
+ function Select2({ className, children, ...props }, ref) {
238
+ return /* @__PURE__ */ jsx("select", { ...props, ref, className: classes("fx-input", className), children });
239
+ }
240
+ );
241
+ var TextArea = forwardRef(
242
+ function TextArea2({ className, ...props }, ref) {
243
+ return /* @__PURE__ */ jsx("textarea", { ...props, ref, className: classes("fx-input", className) });
244
+ }
245
+ );
246
+ function ChoiceText({ label, description, hideLabel }) {
247
+ return /* @__PURE__ */ jsxs("span", { className: "fx-choice__text", children: [
248
+ /* @__PURE__ */ jsx("span", { className: classes("fx-choice__label", hideLabel && "fx-visually-hidden"), children: label }),
249
+ description ? /* @__PURE__ */ jsx("span", { className: classes("fx-choice__description", hideLabel && "fx-visually-hidden"), children: description }) : null
250
+ ] });
251
+ }
252
+ var Checkbox = forwardRef(function Checkbox2({ label, description, hideLabel, className, indeterminate, ...props }, ref) {
253
+ const inputRef = useRef(null);
254
+ useImperativeHandle(ref, () => inputRef.current);
255
+ useEffect(() => {
256
+ if (inputRef.current) inputRef.current.indeterminate = Boolean(indeterminate);
257
+ }, [indeterminate]);
258
+ return /* @__PURE__ */ jsxs("label", { className: classes("fx-choice", "fx-choice--checkbox", className), children: [
259
+ /* @__PURE__ */ jsx("input", { ...props, ref: inputRef, type: "checkbox" }),
260
+ /* @__PURE__ */ jsx(ChoiceText, { label, description, hideLabel })
261
+ ] });
262
+ });
263
+ var Radio = forwardRef(function Radio2({ label, description, hideLabel, className, ...props }, ref) {
264
+ return /* @__PURE__ */ jsxs("label", { className: classes("fx-choice", "fx-choice--radio", className), children: [
265
+ /* @__PURE__ */ jsx("input", { ...props, ref, type: "radio" }),
266
+ /* @__PURE__ */ jsx(ChoiceText, { label, description, hideLabel })
267
+ ] });
268
+ });
269
+ var RangeInput = forwardRef(
270
+ function RangeInput2({ className, type, ...props }, ref) {
271
+ return /* @__PURE__ */ jsx("input", { ...props, ref, type: type ?? "range", className: classes("fx-range", className) });
272
+ }
273
+ );
274
+ var Switch = forwardRef(function Switch2({
275
+ checked,
276
+ defaultChecked,
277
+ onCheckedChange,
278
+ label,
279
+ hideLabel,
280
+ layout = "inline",
281
+ className,
282
+ disabled,
283
+ onClick,
284
+ ...props
285
+ }, ref) {
286
+ const [internalChecked, setInternalChecked] = useState(Boolean(defaultChecked));
287
+ const isChecked = checked ?? internalChecked;
288
+ const handleClick = (event) => {
289
+ onClick?.(event);
290
+ if (event.defaultPrevented || disabled) return;
291
+ const next = !isChecked;
292
+ if (checked === void 0) setInternalChecked(next);
293
+ onCheckedChange?.(next);
294
+ };
295
+ return /* @__PURE__ */ jsxs(
296
+ "button",
297
+ {
298
+ ...props,
299
+ ref,
300
+ type: "button",
301
+ role: "switch",
302
+ "aria-checked": isChecked,
303
+ disabled,
304
+ className: classes("fx-switch", layout === "row" && "fx-switch--row", className),
305
+ onClick: handleClick,
306
+ children: [
307
+ label ? /* @__PURE__ */ jsx("span", { className: classes("fx-switch__label", hideLabel && "fx-visually-hidden"), children: label }) : null,
308
+ /* @__PURE__ */ jsx("span", { className: "fx-switch__track", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "fx-switch__thumb" }) })
309
+ ]
310
+ }
311
+ );
312
+ });
313
+ function Spinner({ label = "\u6B63\u5728\u52A0\u8F7D", className }) {
314
+ return /* @__PURE__ */ jsx("span", { className: classes("fx-spinner", className), role: "status", "aria-label": label });
315
+ }
316
+ var statusIcons = {
317
+ success: CircleCheck,
318
+ warning: CircleAlert,
319
+ error: AlertCircle,
320
+ info: Info
321
+ };
322
+ function Status({
323
+ tone,
324
+ pill = false,
325
+ icon,
326
+ showIcon = true,
327
+ children,
328
+ className,
329
+ ...props
330
+ }) {
331
+ const Icon = statusIcons[tone];
332
+ return /* @__PURE__ */ jsxs(
333
+ "span",
334
+ {
335
+ ...props,
336
+ className: classes("fx-status", `fx-status--${tone}`, pill && "fx-status--pill", className),
337
+ children: [
338
+ showIcon ? icon ?? /* @__PURE__ */ jsx(Icon, { className: "fx-icon", "aria-hidden": true }) : null,
339
+ children
340
+ ]
341
+ }
342
+ );
343
+ }
344
+ function EmptyState({
345
+ title,
346
+ description,
347
+ icon,
348
+ action,
349
+ className,
350
+ ...props
351
+ }) {
352
+ return /* @__PURE__ */ jsxs("div", { ...props, className: classes("fx-empty", className), children: [
353
+ icon,
354
+ /* @__PURE__ */ jsx(Text, { as: "strong", variant: "heading", children: title }),
355
+ /* @__PURE__ */ jsx("p", { children: description }),
356
+ action
357
+ ] });
358
+ }
359
+ function LoadingState({
360
+ title = "\u6B63\u5728\u52A0\u8F7D",
361
+ description
362
+ }) {
363
+ return /* @__PURE__ */ jsxs("div", { className: "fx-empty", role: "status", "aria-live": "polite", children: [
364
+ /* @__PURE__ */ jsx(Spinner, { label: typeof title === "string" ? title : "\u6B63\u5728\u52A0\u8F7D" }),
365
+ /* @__PURE__ */ jsx(Text, { as: "strong", variant: "heading", children: title }),
366
+ description && /* @__PURE__ */ jsx("p", { children: description })
367
+ ] });
368
+ }
369
+ function PanelHeader({ start, center, end, className, ...props }) {
370
+ return /* @__PURE__ */ jsxs("header", { ...props, className: classes("fx-panel-header", className), children: [
371
+ /* @__PURE__ */ jsx("div", { className: "fx-panel-header__slot", children: start }),
372
+ /* @__PURE__ */ jsx("div", { className: "fx-panel-header__slot", children: center }),
373
+ /* @__PURE__ */ jsx("div", { className: "fx-panel-header__slot", children: end })
374
+ ] });
375
+ }
376
+ function Toolbar({ className, ...props }) {
377
+ return /* @__PURE__ */ jsx("div", { ...props, role: props.role ?? "toolbar", className: classes("fx-toolbar", className) });
378
+ }
379
+ var SearchField = forwardRef(function SearchField2({ label = "\u641C\u7D22", onClear, value, className, ...props }, ref) {
380
+ const hasValue = value != null && String(value).length > 0;
381
+ return /* @__PURE__ */ jsxs("div", { className: classes("fx-search", className), children: [
382
+ /* @__PURE__ */ jsx(Search, { className: "fx-icon fx-search__leading", "aria-hidden": true }),
383
+ /* @__PURE__ */ jsx(TextInput, { ...props, ref, type: "search", value, "aria-label": label }),
384
+ hasValue && onClear && /* @__PURE__ */ jsx(
385
+ IconButton,
386
+ {
387
+ className: "fx-search__clear",
388
+ label: "\u6E05\u9664\u641C\u7D22",
389
+ icon: /* @__PURE__ */ jsx(X, { className: "fx-icon" }),
390
+ variant: "quiet",
391
+ size: "compact",
392
+ onClick: onClear
393
+ }
394
+ )
395
+ ] });
396
+ });
397
+ function Menu({
398
+ items,
399
+ label = "\u83DC\u5355",
400
+ className
401
+ }) {
402
+ return /* @__PURE__ */ jsx("div", { className: classes("fx-menu", className), role: "menu", "aria-label": label, children: items.map((item, index) => {
403
+ if (item.type === "separator") {
404
+ return /* @__PURE__ */ jsx("div", { className: "fx-menu__separator", role: "separator" }, `separator-${index}`);
405
+ }
406
+ if (item.type === "title") {
407
+ return /* @__PURE__ */ jsx("div", { className: "fx-menu__title", children: item.label }, `title-${index}`);
408
+ }
409
+ const { className: itemClassName, ...buttonProps } = item.buttonProps ?? {};
410
+ return /* @__PURE__ */ createElement(
411
+ "button",
412
+ {
413
+ ...buttonProps,
414
+ type: "button",
415
+ role: "menuitem",
416
+ key: item.id,
417
+ disabled: item.disabled,
418
+ "aria-selected": item.selected || void 0,
419
+ className: classes(
420
+ "fx-menu__item",
421
+ item.selected && "fx-menu__item--selected",
422
+ item.danger && "fx-menu__item--danger",
423
+ itemClassName
424
+ ),
425
+ onClick: item.onSelect
426
+ },
427
+ /* @__PURE__ */ jsx("span", { className: "fx-menu__leading", "aria-hidden": true, children: item.selected ? /* @__PURE__ */ jsx(Check, { className: "fx-icon" }) : item.icon }),
428
+ /* @__PURE__ */ jsx("span", { className: "fx-menu__label", children: item.label }),
429
+ item.shortcut && /* @__PURE__ */ jsx("kbd", { className: "fx-menu__shortcut", children: item.shortcut })
430
+ );
431
+ }) });
432
+ }
433
+ function FloatingMenu({
434
+ open,
435
+ anchorRect,
436
+ onClose,
437
+ gap = 8,
438
+ className,
439
+ ignorePointerWithin,
440
+ containerProps,
441
+ children
442
+ }) {
443
+ const overlayRoot = useOverlayRoot();
444
+ const menuRef = useRef(null);
445
+ const [position, setPosition] = useState({ x: 0, y: 0 });
446
+ const [visible, setVisible] = useState(false);
447
+ const updatePosition = useCallback(() => {
448
+ if (!open || !anchorRect || !menuRef.current) return;
449
+ const { width, height } = menuRef.current.getBoundingClientRect();
450
+ const resolved = resolveFloatingMenuPosition(anchorRect, width, height, { gap });
451
+ setPosition({ x: resolved.x, y: resolved.y });
452
+ setVisible(true);
453
+ }, [anchorRect, gap, open]);
454
+ useLayoutEffect(() => {
455
+ if (!open) {
456
+ setVisible(false);
457
+ return;
458
+ }
459
+ setVisible(false);
460
+ updatePosition();
461
+ window.addEventListener("resize", updatePosition);
462
+ window.addEventListener("scroll", updatePosition, true);
463
+ return () => {
464
+ window.removeEventListener("resize", updatePosition);
465
+ window.removeEventListener("scroll", updatePosition, true);
466
+ };
467
+ }, [open, updatePosition, children]);
468
+ useEffect(() => {
469
+ if (!open || !onClose) return;
470
+ const close = (event) => {
471
+ const target = event.target;
472
+ if (menuRef.current?.contains(target)) return;
473
+ if (ignorePointerWithin?.some((ref) => ref.current?.contains(target))) return;
474
+ onClose();
475
+ };
476
+ const escape = (event) => {
477
+ if (event.key === "Escape") onClose();
478
+ };
479
+ window.addEventListener("pointerdown", close);
480
+ window.addEventListener("keydown", escape);
481
+ return () => {
482
+ window.removeEventListener("pointerdown", close);
483
+ window.removeEventListener("keydown", escape);
484
+ };
485
+ }, [ignorePointerWithin, onClose, open]);
486
+ if (!open || !anchorRect || typeof document === "undefined") return null;
487
+ const {
488
+ className: containerClassName,
489
+ style: containerStyle,
490
+ onPointerDown,
491
+ ...restContainerProps
492
+ } = containerProps ?? {};
493
+ return createPortal(
494
+ /* @__PURE__ */ jsx(
495
+ "div",
496
+ {
497
+ ...restContainerProps,
498
+ ref: menuRef,
499
+ className: classes("fx-menu-position", "fx-ui", className, containerClassName),
500
+ style: {
501
+ ...containerStyle,
502
+ left: position.x,
503
+ top: position.y,
504
+ visibility: visible ? "visible" : "hidden"
505
+ },
506
+ onPointerDown: (event) => {
507
+ event.stopPropagation();
508
+ onPointerDown?.(event);
509
+ },
510
+ children
511
+ }
512
+ ),
513
+ overlayRoot ?? document.body
514
+ );
515
+ }
516
+ function MenuDropdown({ label = "\u83DC\u5355", items, align = "end", className, trigger }) {
517
+ const overlayRoot = useOverlayRoot();
518
+ const anchorRef = useRef(null);
519
+ const menuRef = useRef(null);
520
+ const [open, setOpen] = useState(false);
521
+ const [position, setPosition] = useState({ x: 0, y: 0 });
522
+ const [visible, setVisible] = useState(false);
523
+ const menuItems = useMemo(
524
+ () => items.map(
525
+ (item) => item.type === void 0 || item.type === "item" ? {
526
+ ...item,
527
+ onSelect: () => {
528
+ item.onSelect?.();
529
+ setOpen(false);
530
+ }
531
+ } : item
532
+ ),
533
+ [items]
534
+ );
535
+ const repositionMenu = useCallback(() => {
536
+ if (!open || !anchorRef.current || !menuRef.current) return;
537
+ const anchor = anchorRef.current.getBoundingClientRect();
538
+ const { width, height } = menuRef.current.getBoundingClientRect();
539
+ if (width <= 0 || height <= 0) return;
540
+ const resolved = resolveMenuDropdownPosition(anchor, width, height, align, { gap: 4 });
541
+ setPosition(resolved);
542
+ setVisible(true);
543
+ }, [align, open]);
544
+ useLayoutEffect(() => {
545
+ if (!open) {
546
+ setVisible(false);
547
+ return;
548
+ }
549
+ setVisible(false);
550
+ repositionMenu();
551
+ const menuEl = menuRef.current;
552
+ const observer = menuEl ? new ResizeObserver(() => repositionMenu()) : null;
553
+ if (menuEl && observer) observer.observe(menuEl);
554
+ const onLayout = () => repositionMenu();
555
+ window.addEventListener("resize", onLayout);
556
+ window.addEventListener("scroll", onLayout, true);
557
+ return () => {
558
+ observer?.disconnect();
559
+ window.removeEventListener("resize", onLayout);
560
+ window.removeEventListener("scroll", onLayout, true);
561
+ };
562
+ }, [open, repositionMenu, menuItems]);
563
+ useEffect(() => {
564
+ if (!open) return;
565
+ const close = (event) => {
566
+ const target = event.target;
567
+ if (anchorRef.current?.contains(target)) return;
568
+ if (menuRef.current?.contains(target)) return;
569
+ setOpen(false);
570
+ };
571
+ const onKey = (event) => {
572
+ if (event.key === "Escape") setOpen(false);
573
+ };
574
+ window.addEventListener("pointerdown", close);
575
+ window.addEventListener("keydown", onKey);
576
+ return () => {
577
+ window.removeEventListener("pointerdown", close);
578
+ window.removeEventListener("keydown", onKey);
579
+ };
580
+ }, [open]);
581
+ const triggerElement = cloneElement(trigger, {
582
+ "aria-haspopup": "menu",
583
+ "aria-expanded": open,
584
+ onClick: (event) => {
585
+ trigger.props.onClick?.(event);
586
+ if (event.defaultPrevented) return;
587
+ setOpen((current) => !current);
588
+ }
589
+ });
590
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
591
+ /* @__PURE__ */ jsx("span", { className: "fx-menu-dropdown__anchor", ref: anchorRef, children: triggerElement }),
592
+ open && typeof document !== "undefined" && createPortal(
593
+ /* @__PURE__ */ jsx(
594
+ "div",
595
+ {
596
+ ref: menuRef,
597
+ className: classes("fx-menu-position", "fx-ui", className),
598
+ style: {
599
+ left: position.x,
600
+ top: position.y,
601
+ visibility: visible ? "visible" : "hidden"
602
+ },
603
+ onPointerDown: (event) => event.stopPropagation(),
604
+ children: /* @__PURE__ */ jsx(Menu, { label, items: menuItems })
605
+ }
606
+ ),
607
+ overlayRoot ?? document.body
608
+ )
609
+ ] });
610
+ }
611
+ function ContextMenu({
612
+ open,
613
+ x = 0,
614
+ y = 0,
615
+ anchorRect = null,
616
+ gap = 8,
617
+ items,
618
+ onClose,
619
+ label,
620
+ containerProps
621
+ }) {
622
+ const overlayRoot = useOverlayRoot();
623
+ useEffect(() => {
624
+ if (!open || anchorRect) return;
625
+ const close = () => onClose();
626
+ const escape = (event) => {
627
+ if (event.key === "Escape") onClose();
628
+ };
629
+ window.addEventListener("pointerdown", close);
630
+ window.addEventListener("keydown", escape);
631
+ return () => {
632
+ window.removeEventListener("pointerdown", close);
633
+ window.removeEventListener("keydown", escape);
634
+ };
635
+ }, [anchorRect, onClose, open]);
636
+ if (anchorRect) {
637
+ return /* @__PURE__ */ jsx(
638
+ FloatingMenu,
639
+ {
640
+ open,
641
+ anchorRect,
642
+ onClose,
643
+ gap,
644
+ containerProps,
645
+ children: /* @__PURE__ */ jsx(
646
+ Menu,
647
+ {
648
+ label,
649
+ items: items.map(
650
+ (item) => item.type === void 0 || item.type === "item" ? { ...item, onSelect: () => {
651
+ item.onSelect?.();
652
+ onClose();
653
+ } } : item
654
+ )
655
+ }
656
+ )
657
+ }
658
+ );
659
+ }
660
+ if (!open || typeof document === "undefined") return null;
661
+ const {
662
+ className: containerClassName,
663
+ style: containerStyle,
664
+ onPointerDown,
665
+ ...positionProps
666
+ } = containerProps ?? {};
667
+ return createPortal(
668
+ /* @__PURE__ */ jsx(
669
+ "div",
670
+ {
671
+ ...positionProps,
672
+ className: classes("fx-menu-position", "fx-ui", containerClassName),
673
+ style: { ...containerStyle, left: x, top: y },
674
+ onPointerDown: (event) => {
675
+ event.stopPropagation();
676
+ onPointerDown?.(event);
677
+ },
678
+ children: /* @__PURE__ */ jsx(
679
+ Menu,
680
+ {
681
+ items: items.map(
682
+ (item) => item.type === void 0 || item.type === "item" ? { ...item, onSelect: () => {
683
+ item.onSelect?.();
684
+ onClose();
685
+ } } : item
686
+ ),
687
+ label
688
+ }
689
+ )
690
+ }
691
+ ),
692
+ overlayRoot ?? document.body
693
+ );
694
+ }
695
+ function Dialog({
696
+ open,
697
+ title,
698
+ children,
699
+ footer,
700
+ className,
701
+ dismissible = true,
702
+ onClose,
703
+ initialFocusRef,
704
+ closeLabel = "\u5173\u95ED\u5F39\u7A97"
705
+ }) {
706
+ const ref = useRef(null);
707
+ const returnFocusRef = useRef(null);
708
+ const titleId = useId();
709
+ useEffect(() => {
710
+ const dialog = ref.current;
711
+ if (!dialog) return;
712
+ if (open && !dialog.open) {
713
+ returnFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
714
+ dialog.showModal();
715
+ requestAnimationFrame(() => initialFocusRef?.current?.focus());
716
+ }
717
+ if (!open && dialog.open) {
718
+ dialog.close();
719
+ returnFocusRef.current?.focus();
720
+ }
721
+ }, [initialFocusRef, open]);
722
+ return /* @__PURE__ */ jsxs(
723
+ "dialog",
724
+ {
725
+ ref,
726
+ className: classes("fx-dialog", "fx-ui", className),
727
+ "aria-labelledby": titleId,
728
+ "data-dismissible": dismissible ? "true" : "false",
729
+ closedby: dismissible ? "closerequest" : "none",
730
+ onCancel: (event) => {
731
+ event.preventDefault();
732
+ if (dismissible) onClose?.();
733
+ },
734
+ onClose: () => {
735
+ if (dismissible) {
736
+ onClose?.();
737
+ return;
738
+ }
739
+ requestAnimationFrame(() => {
740
+ const dialog = ref.current;
741
+ if (open && dialog && !dialog.open) {
742
+ dialog.showModal();
743
+ initialFocusRef?.current?.focus();
744
+ }
745
+ });
746
+ },
747
+ children: [
748
+ /* @__PURE__ */ jsxs("div", { className: "fx-dialog__header", children: [
749
+ /* @__PURE__ */ jsx(Text, { as: "h2", id: titleId, variant: "heading", children: title }),
750
+ dismissible ? /* @__PURE__ */ jsx(IconButton, { label: closeLabel, icon: /* @__PURE__ */ jsx(X, { className: "fx-icon" }), variant: "quiet", onClick: onClose }) : null
751
+ ] }),
752
+ /* @__PURE__ */ jsx("div", { className: "fx-dialog__body", children }),
753
+ footer && /* @__PURE__ */ jsx("div", { className: "fx-dialog__footer", children: footer })
754
+ ]
755
+ }
756
+ );
757
+ }
758
+ function TooltipBody({ title, description, content }) {
759
+ if (title != null || description != null) {
760
+ return /* @__PURE__ */ jsxs("div", { className: "fx-tooltip__content", children: [
761
+ title != null && /* @__PURE__ */ jsx("div", { className: "fx-tooltip__title", children: title }),
762
+ description != null && /* @__PURE__ */ jsx("div", { className: "fx-tooltip__description", children: description })
763
+ ] });
764
+ }
765
+ return /* @__PURE__ */ jsx("div", { className: "fx-tooltip__content", children: content });
766
+ }
767
+ var TOOLTIP_VIEWPORT_MARGIN = 12;
768
+ var TOOLTIP_ANCHOR_GAP = 10;
769
+ function clampTooltipPosition(anchor, tip, placement) {
770
+ let x = anchor.left + anchor.width / 2;
771
+ const half = tip.width / 2;
772
+ const minX = TOOLTIP_VIEWPORT_MARGIN + half;
773
+ const maxX = window.innerWidth - TOOLTIP_VIEWPORT_MARGIN - half;
774
+ x = Math.min(Math.max(x, minX), maxX);
775
+ let resolved = placement;
776
+ let y = placement === "top" ? anchor.top - TOOLTIP_ANCHOR_GAP : anchor.bottom + TOOLTIP_ANCHOR_GAP;
777
+ if (placement === "bottom") {
778
+ if (y + tip.height > window.innerHeight - TOOLTIP_VIEWPORT_MARGIN) {
779
+ resolved = "top";
780
+ y = anchor.top - TOOLTIP_ANCHOR_GAP;
781
+ }
782
+ } else if (y - tip.height < TOOLTIP_VIEWPORT_MARGIN) {
783
+ resolved = "bottom";
784
+ y = anchor.bottom + TOOLTIP_ANCHOR_GAP;
785
+ }
786
+ return { x, y, placement: resolved };
787
+ }
788
+ function Tooltip({
789
+ content,
790
+ title,
791
+ description,
792
+ children,
793
+ placement = "top",
794
+ portaled = false,
795
+ open = false
796
+ }) {
797
+ const overlayRoot = useOverlayRoot();
798
+ const anchorRef = useRef(null);
799
+ const tooltipRef = useRef(null);
800
+ const [hoverVisible, setHoverVisible] = useState(false);
801
+ const visible = open || hoverVisible;
802
+ const [coords, setCoords] = useState({ x: 0, y: 0 });
803
+ const [resolvedPlacement, setResolvedPlacement] = useState(placement);
804
+ const timer = useRef(null);
805
+ const updateCoords = useCallback(() => {
806
+ const anchor = anchorRef.current?.getBoundingClientRect();
807
+ if (!anchor) return;
808
+ const tip = tooltipRef.current?.getBoundingClientRect();
809
+ if (tip && tip.width > 0) {
810
+ const next = clampTooltipPosition(anchor, tip, placement);
811
+ setCoords({ x: next.x, y: next.y });
812
+ setResolvedPlacement(next.placement);
813
+ return;
814
+ }
815
+ setCoords({
816
+ x: anchor.left + anchor.width / 2,
817
+ y: placement === "top" ? anchor.top - TOOLTIP_ANCHOR_GAP : anchor.bottom + TOOLTIP_ANCHOR_GAP
818
+ });
819
+ setResolvedPlacement(placement);
820
+ }, [placement]);
821
+ useLayoutEffect(() => {
822
+ if (!visible) return;
823
+ updateCoords();
824
+ if (!portaled) return;
825
+ const onLayout = () => updateCoords();
826
+ window.addEventListener("resize", onLayout);
827
+ window.addEventListener("scroll", onLayout, true);
828
+ return () => {
829
+ window.removeEventListener("resize", onLayout);
830
+ window.removeEventListener("scroll", onLayout, true);
831
+ };
832
+ }, [portaled, updateCoords, visible]);
833
+ const show = () => {
834
+ if (open) return;
835
+ timer.current = setTimeout(() => {
836
+ setHoverVisible(true);
837
+ }, 400);
838
+ };
839
+ const hide = () => {
840
+ if (open) return;
841
+ if (timer.current) clearTimeout(timer.current);
842
+ setHoverVisible(false);
843
+ setResolvedPlacement(placement);
844
+ };
845
+ const effectivePlacement = portaled ? resolvedPlacement : placement;
846
+ const tooltipStyle = portaled ? {
847
+ left: coords.x,
848
+ top: coords.y,
849
+ transform: effectivePlacement === "top" ? "translate(-50%, -100%)" : "translate(-50%, 0)"
850
+ } : void 0;
851
+ const tooltip = visible ? /* @__PURE__ */ jsx(
852
+ "span",
853
+ {
854
+ ref: tooltipRef,
855
+ className: classes(
856
+ "fx-tooltip",
857
+ effectivePlacement === "bottom" ? "fx-tooltip--bottom" : "fx-tooltip--top",
858
+ portaled && "fx-tooltip--fixed",
859
+ open && "fx-tooltip--interactive"
860
+ ),
861
+ style: tooltipStyle,
862
+ role: "tooltip",
863
+ children: /* @__PURE__ */ jsx(TooltipBody, { title, description, content })
864
+ }
865
+ ) : null;
866
+ return /* @__PURE__ */ jsxs(
867
+ "span",
868
+ {
869
+ ref: anchorRef,
870
+ className: "fx-tooltip-anchor",
871
+ onMouseEnter: show,
872
+ onMouseLeave: hide,
873
+ onFocus: show,
874
+ onBlur: hide,
875
+ children: [
876
+ children,
877
+ portaled && typeof document !== "undefined" ? tooltip && createPortal(tooltip, overlayRoot ?? document.body) : tooltip
878
+ ]
879
+ }
880
+ );
881
+ }
882
+ var ToastContext = createContext(null);
883
+ function PropertyRow({
884
+ label,
885
+ children,
886
+ className
887
+ }) {
888
+ return /* @__PURE__ */ jsxs("div", { className: classes("fx-property-row", className), children: [
889
+ /* @__PURE__ */ jsx("span", { className: "fx-property-row__label", children: label }),
890
+ /* @__PURE__ */ jsx("span", { className: "fx-property-row__control", children })
891
+ ] });
892
+ }
893
+ function CollapsibleSection({
894
+ title,
895
+ children,
896
+ defaultOpen = true,
897
+ open,
898
+ onOpenChange,
899
+ trailing,
900
+ className,
901
+ triggerProps,
902
+ ...props
903
+ }) {
904
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
905
+ const expanded = open ?? internalOpen;
906
+ const contentId = useId();
907
+ const toggle = () => {
908
+ const next = !expanded;
909
+ if (open === void 0) setInternalOpen(next);
910
+ onOpenChange?.(next);
911
+ };
912
+ const {
913
+ className: triggerClassName,
914
+ onClick: onTriggerClick,
915
+ ...buttonProps
916
+ } = triggerProps ?? {};
917
+ return /* @__PURE__ */ jsxs("section", { ...props, className: classes("fx-collapsible", className), children: [
918
+ /* @__PURE__ */ jsxs("div", { className: "fx-collapsible__heading", children: [
919
+ /* @__PURE__ */ jsxs(
920
+ "button",
921
+ {
922
+ ...buttonProps,
923
+ type: "button",
924
+ className: classes("fx-collapsible__trigger", triggerClassName),
925
+ "aria-expanded": expanded,
926
+ "aria-controls": contentId,
927
+ onClick: (event) => {
928
+ onTriggerClick?.(event);
929
+ if (!event.defaultPrevented) toggle();
930
+ },
931
+ children: [
932
+ expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "fx-icon" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "fx-icon" }),
933
+ /* @__PURE__ */ jsx("span", { className: "fx-collapsible__title", children: title })
934
+ ]
935
+ }
936
+ ),
937
+ trailing && /* @__PURE__ */ jsx("div", { className: "fx-collapsible__actions", children: trailing })
938
+ ] }),
939
+ expanded && /* @__PURE__ */ jsx("div", { className: "fx-collapsible__content", id: contentId, children })
940
+ ] });
941
+ }
942
+
943
+ // packages/view-components/src/theme.tsx
944
+ import {
945
+ createContext as createContext2,
946
+ useCallback as useCallback2,
947
+ useContext as useContext2,
948
+ useEffect as useEffect2,
949
+ useMemo as useMemo2,
950
+ useState as useState2
951
+ } from "react";
952
+
953
+ // packages/view-components/src/tokens.ts
954
+ var themeNames = ["light", "dark"];
955
+ var colorTokens = {
956
+ surface: {
957
+ canvas: "--fx-color-surface-canvas",
958
+ sidebar: "--fx-color-surface-sidebar",
959
+ raised: "--fx-color-surface-raised",
960
+ inset: "--fx-color-surface-inset",
961
+ hover: "--fx-color-surface-hover",
962
+ selected: "--fx-color-surface-selected"
963
+ },
964
+ text: {
965
+ primary: "--fx-color-text-primary",
966
+ secondary: "--fx-color-text-secondary",
967
+ muted: "--fx-color-text-muted",
968
+ disabled: "--fx-color-text-disabled",
969
+ inverse: "--fx-color-text-inverse",
970
+ link: "--fx-color-text-link"
971
+ },
972
+ border: {
973
+ subtle: "--fx-color-border-subtle",
974
+ default: "--fx-color-border-default",
975
+ control: "--fx-color-border-control",
976
+ strong: "--fx-color-border-strong",
977
+ focus: "--fx-color-border-focus",
978
+ essential: "--fx-color-border-essential"
979
+ },
980
+ action: {
981
+ primaryBackground: "--fx-color-action-primary-bg",
982
+ primaryForeground: "--fx-color-action-primary-fg",
983
+ primaryHover: "--fx-color-action-primary-hover",
984
+ primaryPressed: "--fx-color-action-primary-pressed",
985
+ secondaryBackground: "--fx-color-action-secondary-bg",
986
+ secondaryForeground: "--fx-color-action-secondary-fg",
987
+ secondaryHover: "--fx-color-action-secondary-hover",
988
+ disabledBackground: "--fx-color-action-disabled-bg",
989
+ disabledForeground: "--fx-color-action-disabled-fg",
990
+ dangerBackground: "--fx-color-action-danger-bg",
991
+ dangerForeground: "--fx-color-action-danger-fg"
992
+ },
993
+ selection: {
994
+ background: "--fx-color-selection-bg",
995
+ foreground: "--fx-color-selection-fg",
996
+ indicator: "--fx-color-selection-indicator"
997
+ },
998
+ brand: {
999
+ accent: "--fx-color-brand-accent",
1000
+ text: "--fx-color-brand-text",
1001
+ soft: "--fx-color-brand-soft",
1002
+ onAccent: "--fx-color-brand-on-accent"
1003
+ },
1004
+ status: {
1005
+ successForeground: "--fx-color-status-success-fg",
1006
+ successBackground: "--fx-color-status-success-bg",
1007
+ warningForeground: "--fx-color-status-warning-fg",
1008
+ warningBackground: "--fx-color-status-warning-bg",
1009
+ errorForeground: "--fx-color-status-error-fg",
1010
+ errorBackground: "--fx-color-status-error-bg",
1011
+ infoForeground: "--fx-color-status-info-fg",
1012
+ infoBackground: "--fx-color-status-info-bg"
1013
+ },
1014
+ scrim: "--fx-color-scrim",
1015
+ choiceIndicator: "--fx-color-choice-indicator"
1016
+ };
1017
+ var surfaceTokens = colorTokens.surface;
1018
+
1019
+ // packages/view-components/src/theme.tsx
1020
+ import { jsx as jsx2 } from "react/jsx-runtime";
1021
+ var THEME_STORAGE_KEY = "forgeax-view-theme";
1022
+ var ThemeContext = createContext2(null);
1023
+ function isThemeName(value) {
1024
+ return typeof value === "string" && themeNames.includes(value);
1025
+ }
1026
+ function getStoredTheme(fallback = "light") {
1027
+ if (typeof window === "undefined") return fallback;
1028
+ const stored = window.localStorage.getItem(THEME_STORAGE_KEY);
1029
+ return isThemeName(stored) ? stored : fallback;
1030
+ }
1031
+ function applyTheme(theme, target) {
1032
+ const element = target ?? (typeof document === "undefined" ? void 0 : document.documentElement);
1033
+ if (element) element.dataset.theme = theme;
1034
+ }
1035
+ function initializeTheme(fallback = "light") {
1036
+ const theme = getStoredTheme(fallback);
1037
+ applyTheme(theme);
1038
+ return theme;
1039
+ }
1040
+ function ThemeProvider({
1041
+ children,
1042
+ defaultTheme = "light",
1043
+ theme: controlledTheme,
1044
+ onThemeChange,
1045
+ persist = false,
1046
+ applyToDocument = true,
1047
+ unstyled = false,
1048
+ className,
1049
+ ...props
1050
+ }) {
1051
+ const [internalTheme, setInternalTheme] = useState2(
1052
+ () => persist ? getStoredTheme(defaultTheme) : defaultTheme
1053
+ );
1054
+ const theme = controlledTheme ?? internalTheme;
1055
+ const setTheme = useCallback2(
1056
+ (nextTheme) => {
1057
+ if (!controlledTheme) setInternalTheme(nextTheme);
1058
+ if (persist && typeof window !== "undefined") {
1059
+ window.localStorage.setItem(THEME_STORAGE_KEY, nextTheme);
1060
+ }
1061
+ onThemeChange?.(nextTheme);
1062
+ },
1063
+ [controlledTheme, onThemeChange, persist]
1064
+ );
1065
+ useEffect2(() => {
1066
+ if (applyToDocument) applyTheme(theme);
1067
+ }, [applyToDocument, theme]);
1068
+ const value = useMemo2(
1069
+ () => ({
1070
+ theme,
1071
+ setTheme,
1072
+ toggleTheme: () => setTheme(theme === "light" ? "dark" : "light")
1073
+ }),
1074
+ [setTheme, theme]
1075
+ );
1076
+ return /* @__PURE__ */ jsx2(ThemeContext.Provider, { value, children: unstyled ? children : /* @__PURE__ */ jsx2(
1077
+ "div",
1078
+ {
1079
+ ...props,
1080
+ className: ["fx-ui", className].filter(Boolean).join(" "),
1081
+ "data-theme": applyToDocument ? void 0 : theme,
1082
+ children
1083
+ }
1084
+ ) });
1085
+ }
1086
+ function useTheme() {
1087
+ const context = useContext2(ThemeContext);
1088
+ if (!context) throw new Error("useTheme must be used inside ThemeProvider");
1089
+ return context;
1090
+ }
1091
+
1092
+ // packages/view-components/src/useWorkspaceClientConnected.ts
1093
+ import { useSyncExternalStore } from "react";
1094
+ function readConnected(client) {
1095
+ const transport = client?.transport;
1096
+ return Boolean(transport && typeof transport.request === "function" && transport.connected !== false);
1097
+ }
1098
+ function useWorkspaceClientConnected(client) {
1099
+ return useSyncExternalStore(
1100
+ (onChange) => client?.onDisconnect?.(onChange) ?? (() => {
1101
+ }),
1102
+ () => readConnected(client),
1103
+ () => readConnected(client)
1104
+ );
1105
+ }
1106
+
1107
+ // packages/view-components/src/inspector-form-model.mjs
1108
+ function formatInspectorFieldLabel(key) {
1109
+ if (key == null) return "";
1110
+ const text = String(key);
1111
+ if (!text) return "";
1112
+ return text.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[\s_-]+/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
1113
+ }
1114
+ function numericComponents(value) {
1115
+ if (!Array.isArray(value)) return null;
1116
+ if (value.length === 0) return null;
1117
+ if (!value.every((entry) => typeof entry === "number" && Number.isFinite(entry))) return null;
1118
+ return value;
1119
+ }
1120
+ function schemaTypeName(schema) {
1121
+ if (typeof schema === "string") return schema.toLowerCase();
1122
+ if (schema && typeof schema === "object" && typeof schema.type === "string") return schema.type.toLowerCase();
1123
+ return "";
1124
+ }
1125
+ var HEX_COLOR = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
1126
+ function isAssetRefRecord(value) {
1127
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1128
+ const record = (
1129
+ /** @type {Record<string, unknown>} */
1130
+ value
1131
+ );
1132
+ const identity = record.guid ?? record.id;
1133
+ if (typeof identity !== "string" || identity.trim() === "") return false;
1134
+ return Object.values(record).every((entry) => entry == null || typeof entry !== "object");
1135
+ }
1136
+ function resolveInspectorFieldKind(schema, value) {
1137
+ const type = schemaTypeName(schema);
1138
+ if (typeof value === "boolean" || type.includes("bool")) return "bool";
1139
+ if (typeof value === "number" || type === "f32" || type === "f64" || type === "i32" || type === "u32" || type === "number") {
1140
+ return "number";
1141
+ }
1142
+ const array = numericComponents(value);
1143
+ if (array?.length === 3) return "vector3";
1144
+ if (array?.length === 4) return "vector4";
1145
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1146
+ const record = (
1147
+ /** @type {Record<string, unknown>} */
1148
+ value
1149
+ );
1150
+ if (typeof record.x === "number" && typeof record.y === "number" && typeof record.z === "number") {
1151
+ return typeof record.w === "number" ? "vector4" : "vector3";
1152
+ }
1153
+ }
1154
+ if (type.includes("enum") || schema && typeof schema === "object" && Array.isArray(
1155
+ /** @type {Record<string, unknown>} */
1156
+ schema.enum
1157
+ )) {
1158
+ return "enum";
1159
+ }
1160
+ if (type.includes("color") || typeof value === "string" && HEX_COLOR.test(value)) return "color";
1161
+ if (type.includes("asset") || type.includes("guid") || type.includes("ref") || isAssetRefRecord(value)) return "asset";
1162
+ if (Array.isArray(value) || value && typeof value === "object") return "text";
1163
+ return "text";
1164
+ }
1165
+ function normalizeInspectorFieldValue(value, kind) {
1166
+ if (value === void 0) return "Unavailable";
1167
+ if (kind === "vector3") {
1168
+ const array = numericComponents(value);
1169
+ if (array?.length === 3) return { x: array[0], y: array[1], z: array[2] };
1170
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1171
+ const record = (
1172
+ /** @type {Record<string, number>} */
1173
+ value
1174
+ );
1175
+ return { x: record.x ?? 0, y: record.y ?? 0, z: record.z ?? 0 };
1176
+ }
1177
+ return { x: 0, y: 0, z: 0 };
1178
+ }
1179
+ if (kind === "vector4") {
1180
+ const array = numericComponents(value);
1181
+ if (array?.length === 4) return { x: array[0], y: array[1], z: array[2], w: array[3] };
1182
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1183
+ const record = (
1184
+ /** @type {Record<string, number>} */
1185
+ value
1186
+ );
1187
+ return { x: record.x ?? 0, y: record.y ?? 0, z: record.z ?? 0, w: record.w ?? 0 };
1188
+ }
1189
+ return { x: 0, y: 0, z: 0, w: 0 };
1190
+ }
1191
+ if (kind === "asset" && value && typeof value === "object" && !Array.isArray(value)) {
1192
+ const record = (
1193
+ /** @type {Record<string, unknown>} */
1194
+ value
1195
+ );
1196
+ return String(record.name ?? record.guid ?? record.id ?? "");
1197
+ }
1198
+ if (kind === "bool" || kind === "number") return value;
1199
+ if (typeof value === "object") return JSON.stringify(value);
1200
+ return value;
1201
+ }
1202
+ function freezeField(key, label, kind, value, options) {
1203
+ return Object.freeze({
1204
+ key,
1205
+ label,
1206
+ kind,
1207
+ value: normalizeInspectorFieldValue(value, kind),
1208
+ ...options === void 0 ? {} : { options: Object.freeze([...options]) }
1209
+ });
1210
+ }
1211
+ function freezeGroup(group) {
1212
+ return Object.freeze({
1213
+ key: group.key,
1214
+ name: group.name,
1215
+ category: group.category,
1216
+ fields: Object.freeze(group.fields),
1217
+ groups: Object.freeze(group.groups)
1218
+ });
1219
+ }
1220
+ function objectListItems(value) {
1221
+ if (!Array.isArray(value) || value.length === 0) return null;
1222
+ if (!value.every((entry) => entry && typeof entry === "object" && !Array.isArray(entry))) return null;
1223
+ return value;
1224
+ }
1225
+ function partitionRecord(record, keyPrefix) {
1226
+ const fields = [];
1227
+ const groups = [];
1228
+ for (const [key, value] of Object.entries(record)) {
1229
+ if (value === void 0 || value === null) continue;
1230
+ if (typeof value === "string" && value.trim() === "") continue;
1231
+ const path = keyPrefix ? `${keyPrefix}.${key}` : key;
1232
+ const name = formatInspectorFieldLabel(key);
1233
+ const listed = objectListItems(value);
1234
+ if (listed) {
1235
+ const child = arrayToGroup(listed, path, name);
1236
+ if (child) groups.push(child);
1237
+ continue;
1238
+ }
1239
+ const kind = resolveInspectorFieldKind(void 0, value);
1240
+ const nestedObject = value && typeof value === "object" && !Array.isArray(value) && kind !== "vector3" && kind !== "vector4" && kind !== "asset";
1241
+ if (nestedObject) {
1242
+ const child = recordToGroup(
1243
+ /** @type {Record<string, unknown>} */
1244
+ value,
1245
+ path,
1246
+ name,
1247
+ "all"
1248
+ );
1249
+ if (child) groups.push(child);
1250
+ continue;
1251
+ }
1252
+ fields.push(freezeField(key, name, kind, value));
1253
+ }
1254
+ return { fields, groups };
1255
+ }
1256
+ function recordToGroup(record, key, name, category) {
1257
+ const partitioned = partitionRecord(record, key);
1258
+ if (partitioned.fields.length === 0 && partitioned.groups.length === 0) return null;
1259
+ return freezeGroup({
1260
+ key,
1261
+ name,
1262
+ category,
1263
+ fields: partitioned.fields,
1264
+ groups: partitioned.groups
1265
+ });
1266
+ }
1267
+ function arrayToGroup(items, path, name) {
1268
+ const groups = [];
1269
+ for (const [index, item] of items.entries()) {
1270
+ const label = item.name ?? item.id ?? item.slotName ?? item.guid ?? String(index);
1271
+ const child = recordToGroup(item, `${path}.${index}`, formatInspectorFieldLabel(String(label)), "type");
1272
+ if (child) groups.push(child);
1273
+ }
1274
+ if (groups.length === 0) return null;
1275
+ return freezeGroup({
1276
+ key: path,
1277
+ name,
1278
+ category: "capability",
1279
+ fields: [],
1280
+ groups
1281
+ });
1282
+ }
1283
+ function identityFactFields(inspection) {
1284
+ const asset = inspection.asset && typeof inspection.asset === "object" ? inspection.asset : {};
1285
+ const facts = [
1286
+ ["guid", "GUID", inspection.guid ?? asset.guid],
1287
+ ["kind", "Kind", asset.kind],
1288
+ ["name", "Name", asset.name],
1289
+ ["path", "Path", asset.path],
1290
+ ["source", "Source", inspection.source?.path ?? asset.sourcePath],
1291
+ ["revision", "Revision", inspection.revision ?? asset.revision ?? inspection.source?.revision],
1292
+ ["package", "Package", asset.packageId ?? asset.packageUrl],
1293
+ ["ddc", "DDC", inspection.ddc?.state]
1294
+ ];
1295
+ const fields = [];
1296
+ for (const [key, label, value] of facts) {
1297
+ if (value === void 0 || value === null) continue;
1298
+ if (typeof value === "string" && value.trim() === "") continue;
1299
+ fields.push(freezeField(key, label, resolveInspectorFieldKind(void 0, value), value));
1300
+ }
1301
+ return fields;
1302
+ }
1303
+ function inspectorFormGroupsFromInspection(inspection, options = {}) {
1304
+ if (!inspection || typeof inspection !== "object" || Array.isArray(inspection)) {
1305
+ return Object.freeze([]);
1306
+ }
1307
+ const identityTitle = options.identityTitle ?? "Asset";
1308
+ const identityFields = identityFactFields(inspection);
1309
+ const meta = inspection.meta;
1310
+ let metaFields = [];
1311
+ let nested = [];
1312
+ if (meta && typeof meta === "object" && !Array.isArray(meta)) {
1313
+ const partitioned = partitionRecord(
1314
+ /** @type {Record<string, unknown>} */
1315
+ meta,
1316
+ "meta"
1317
+ );
1318
+ metaFields = partitioned.fields;
1319
+ nested = partitioned.groups;
1320
+ }
1321
+ const groups = [];
1322
+ const fields = [...identityFields, ...metaFields];
1323
+ if (fields.length) {
1324
+ groups.push(freezeGroup({
1325
+ key: "identity",
1326
+ name: identityTitle,
1327
+ category: "type",
1328
+ fields,
1329
+ groups: []
1330
+ }));
1331
+ }
1332
+ groups.push(...nested);
1333
+ return Object.freeze(groups);
1334
+ }
1335
+
1336
+ // packages/view-components/src/InspectorForm.tsx
1337
+ import { Box } from "lucide-react";
1338
+ import { useState as useState3 } from "react";
1339
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1340
+ var READ_ONLY = { readOnly: true, tabIndex: -1 };
1341
+ function VectorField({
1342
+ axes,
1343
+ vector
1344
+ }) {
1345
+ return /* @__PURE__ */ jsx3("span", { className: `fx-inspector-form__vec${axes.length > 3 ? " fx-inspector-form__vec--4" : ""}`, children: axes.map((axis) => /* @__PURE__ */ jsxs2("span", { className: `fx-inspector-form__vcell fx-inspector-form__vcell--${axis}`, children: [
1346
+ /* @__PURE__ */ jsx3("span", { className: "fx-inspector-form__axis", children: axis.toUpperCase() }),
1347
+ /* @__PURE__ */ jsx3("span", { className: "fx-inspector-form__numfield", children: /* @__PURE__ */ jsx3(
1348
+ TextInput,
1349
+ {
1350
+ className: "fx-inspector-form__input fx-inspector-form__input--number",
1351
+ type: "number",
1352
+ value: vector[axis],
1353
+ ...READ_ONLY
1354
+ }
1355
+ ) })
1356
+ ] }, axis)) });
1357
+ }
1358
+ function InspectorFieldControl({ field }) {
1359
+ if (field.kind === "vector3" && typeof field.value === "object" && field.value !== null) {
1360
+ const vector = field.value;
1361
+ return /* @__PURE__ */ jsx3(VectorField, { axes: ["x", "y", "z"], vector: { ...vector, w: 0 } });
1362
+ }
1363
+ if (field.kind === "vector4" && typeof field.value === "object" && field.value !== null) {
1364
+ const vector = field.value;
1365
+ return /* @__PURE__ */ jsx3(VectorField, { axes: ["x", "y", "z", "w"], vector });
1366
+ }
1367
+ if (field.kind === "bool") {
1368
+ return /* @__PURE__ */ jsx3(
1369
+ Checkbox,
1370
+ {
1371
+ className: "fx-inspector-form__checkbox",
1372
+ checked: field.value === true,
1373
+ disabled: true,
1374
+ hideLabel: true,
1375
+ label: field.label
1376
+ }
1377
+ );
1378
+ }
1379
+ if (field.kind === "enum") {
1380
+ return /* @__PURE__ */ jsx3("span", { className: "fx-inspector-form__select", children: /* @__PURE__ */ jsx3(Select, { className: "fx-inspector-form__input", value: String(field.value), disabled: true, children: (field.options ?? [String(field.value)]).map((option) => /* @__PURE__ */ jsx3("option", { value: option, children: option }, option)) }) });
1381
+ }
1382
+ if (field.kind === "color") {
1383
+ return /* @__PURE__ */ jsxs2("span", { className: "fx-inspector-form__color", children: [
1384
+ /* @__PURE__ */ jsx3("span", { className: "fx-inspector-form__swatch", "aria-hidden": true, style: { background: String(field.value) } }),
1385
+ /* @__PURE__ */ jsx3(TextInput, { className: "fx-inspector-form__input fx-inspector-form__input--hex", value: String(field.value), ...READ_ONLY })
1386
+ ] });
1387
+ }
1388
+ if (field.kind === "asset") {
1389
+ const empty = !String(field.value);
1390
+ return /* @__PURE__ */ jsxs2("span", { className: "fx-inspector-form__asset", children: [
1391
+ /* @__PURE__ */ jsx3("span", { className: `fx-inspector-form__asset-thumb${empty ? " is-empty" : ""}`, children: empty ? null : /* @__PURE__ */ jsx3(Box, { size: 16 }) }),
1392
+ /* @__PURE__ */ jsx3("span", { className: "fx-inspector-form__asset-body", children: /* @__PURE__ */ jsx3("span", { className: "fx-inspector-form__asset-combo", children: /* @__PURE__ */ jsx3("span", { className: `fx-inspector-form__asset-label${empty ? " is-empty" : ""}`, children: empty ? "None" : String(field.value) }) }) })
1393
+ ] });
1394
+ }
1395
+ return /* @__PURE__ */ jsx3("span", { className: field.kind === "number" ? "fx-inspector-form__numfield fx-inspector-form__numfield--solo" : void 0, children: /* @__PURE__ */ jsx3(
1396
+ TextInput,
1397
+ {
1398
+ className: `fx-inspector-form__input ${field.kind === "number" ? "fx-inspector-form__input--number" : "fx-inspector-form__input--text"}`,
1399
+ type: field.kind === "number" ? "number" : "text",
1400
+ value: String(field.value),
1401
+ ...READ_ONLY
1402
+ }
1403
+ ) });
1404
+ }
1405
+ function FormGroup({
1406
+ group,
1407
+ nested = false
1408
+ }) {
1409
+ const [open, setOpen] = useState3(true);
1410
+ const category = group.category === "all" ? "all" : group.category === "capability" ? "cap" : "type";
1411
+ return /* @__PURE__ */ jsx3("div", { className: `fx-inspector-form__group fx-inspector-form__group--${category}${nested ? " is-nested" : ""}`, children: /* @__PURE__ */ jsx3(
1412
+ CollapsibleSection,
1413
+ {
1414
+ open,
1415
+ onOpenChange: setOpen,
1416
+ title: /* @__PURE__ */ jsxs2("span", { className: "fx-inspector-form__title", children: [
1417
+ /* @__PURE__ */ jsx3("span", { className: "fx-inspector-form__icon", children: /* @__PURE__ */ jsx3(Box, { size: 13, strokeWidth: 1.7 }) }),
1418
+ /* @__PURE__ */ jsx3("span", { children: group.name })
1419
+ ] }),
1420
+ children: /* @__PURE__ */ jsxs2("div", { className: "fx-inspector-form__fields", children: [
1421
+ group.fields.map((field) => /* @__PURE__ */ jsx3("div", { className: "fx-inspector-form__row", "data-testid": `inspector-form-field-${group.key}-${field.key}`, children: /* @__PURE__ */ jsx3(PropertyRow, { className: "fx-inspector-form__property", label: /* @__PURE__ */ jsx3("span", { title: field.key, children: field.label }), children: /* @__PURE__ */ jsx3(InspectorFieldControl, { field }) }) }, field.key)),
1422
+ (group.groups ?? []).map((child) => /* @__PURE__ */ jsx3(FormGroup, { group: child, nested: true }, child.key))
1423
+ ] })
1424
+ }
1425
+ ) });
1426
+ }
1427
+ function InspectorForm({
1428
+ groups,
1429
+ inspection,
1430
+ identityTitle,
1431
+ className,
1432
+ empty
1433
+ }) {
1434
+ const resolved = groups ?? inspectorFormGroupsFromInspection(inspection, { identityTitle });
1435
+ if (resolved.length === 0) return empty ?? null;
1436
+ return /* @__PURE__ */ jsx3("div", { className: ["fx-inspector-form", className].filter(Boolean).join(" "), "data-view-readonly": "true", children: resolved.map((group) => /* @__PURE__ */ jsx3(FormGroup, { group }, group.key)) });
1437
+ }
1438
+
1439
+ // packages/view-components/src/ErrorNotice.tsx
1440
+ import { AlertCircle as AlertCircle2, Check as Check2, Copy, X as X2 } from "lucide-react";
1441
+ import {
1442
+ useCallback as useCallback3,
1443
+ useEffect as useEffect3,
1444
+ useLayoutEffect as useLayoutEffect2,
1445
+ useMemo as useMemo3,
1446
+ useRef as useRef2,
1447
+ useState as useState4,
1448
+ useSyncExternalStore as useSyncExternalStore2
1449
+ } from "react";
1450
+ import { createPortal as createPortal2 } from "react-dom";
1451
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1452
+ var nextId = 0;
1453
+ var notices = [];
1454
+ var listeners = /* @__PURE__ */ new Set();
1455
+ var timers = /* @__PURE__ */ new Map();
1456
+ function emit() {
1457
+ for (const listener of listeners) listener();
1458
+ }
1459
+ function subscribeErrorNotices(listener) {
1460
+ listeners.add(listener);
1461
+ return () => {
1462
+ listeners.delete(listener);
1463
+ };
1464
+ }
1465
+ function getErrorNotices() {
1466
+ return notices;
1467
+ }
1468
+ function showErrorNotice(input) {
1469
+ const id = ++nextId;
1470
+ const persistent = input.persistent !== false;
1471
+ notices = [...notices, { ...input, id, persistent }];
1472
+ emit();
1473
+ if (!persistent) {
1474
+ const duration = input.duration ?? 8e3;
1475
+ if (duration > 0) {
1476
+ timers.set(
1477
+ id,
1478
+ setTimeout(() => {
1479
+ timers.delete(id);
1480
+ dismissErrorNotice(id);
1481
+ }, duration)
1482
+ );
1483
+ }
1484
+ }
1485
+ return id;
1486
+ }
1487
+ function dismissErrorNotice(id) {
1488
+ const timer = timers.get(id);
1489
+ if (timer !== void 0) {
1490
+ clearTimeout(timer);
1491
+ timers.delete(id);
1492
+ }
1493
+ const current = notices.find((notice) => notice.id === id);
1494
+ if (!current) return;
1495
+ notices = notices.filter((notice) => notice.id !== id);
1496
+ emit();
1497
+ current.onDismiss?.();
1498
+ }
1499
+ function resolveCopyText(copyText, details) {
1500
+ if (typeof copyText === "string" && copyText.trim() !== "") return copyText;
1501
+ if (typeof details === "string" && details.trim() !== "") return details;
1502
+ return void 0;
1503
+ }
1504
+ function ErrorNotice({
1505
+ title,
1506
+ description,
1507
+ hint,
1508
+ code,
1509
+ details,
1510
+ detailsLabel = "\u8BE6\u7EC6\u4FE1\u606F",
1511
+ copyText,
1512
+ copyLabel = "\u590D\u5236\u8BE6\u7EC6\u4FE1\u606F",
1513
+ copiedLabel = "\u5DF2\u590D\u5236",
1514
+ closeLabel = "\u5173\u95ED\u9519\u8BEF\u63D0\u793A",
1515
+ onClose
1516
+ }) {
1517
+ const [copied, setCopied] = useState4(false);
1518
+ const clipboardText = resolveCopyText(copyText, details);
1519
+ useEffect3(() => {
1520
+ if (!copied) return void 0;
1521
+ const timer = setTimeout(() => setCopied(false), 2e3);
1522
+ return () => clearTimeout(timer);
1523
+ }, [copied]);
1524
+ async function handleCopyDetails() {
1525
+ if (!clipboardText) return;
1526
+ try {
1527
+ await navigator.clipboard.writeText(clipboardText);
1528
+ setCopied(true);
1529
+ } catch {
1530
+ }
1531
+ }
1532
+ return /* @__PURE__ */ jsxs3("div", { className: "fx-error-notice fx-status--error", role: "alert", children: [
1533
+ /* @__PURE__ */ jsx4(AlertCircle2, { className: "fx-icon fx-error-notice__icon", "aria-hidden": true }),
1534
+ /* @__PURE__ */ jsxs3("div", { className: "fx-error-notice__body", children: [
1535
+ /* @__PURE__ */ jsx4("strong", { className: "fx-error-notice__title", children: title }),
1536
+ code ? /* @__PURE__ */ jsx4(Text, { as: "code", variant: "code", className: "fx-error-notice__code", children: code }) : null,
1537
+ description ? /* @__PURE__ */ jsx4(Text, { variant: "body", className: "fx-error-notice__description", children: description }) : null,
1538
+ hint ? /* @__PURE__ */ jsx4(Text, { variant: "caption", className: "fx-error-notice__hint", children: hint }) : null,
1539
+ details ? /* @__PURE__ */ jsxs3("details", { className: "fx-error-notice__details", open: true, children: [
1540
+ /* @__PURE__ */ jsxs3("summary", { className: "fx-error-notice__details-summary", children: [
1541
+ /* @__PURE__ */ jsx4("span", { children: detailsLabel }),
1542
+ clipboardText ? /* @__PURE__ */ jsx4(
1543
+ Button,
1544
+ {
1545
+ type: "button",
1546
+ variant: "quiet",
1547
+ size: "compact",
1548
+ className: "fx-error-notice__copy",
1549
+ leadingIcon: copied ? /* @__PURE__ */ jsx4(Check2, { className: "fx-icon", "aria-hidden": true }) : /* @__PURE__ */ jsx4(Copy, { className: "fx-icon", "aria-hidden": true }),
1550
+ onClick: (event) => {
1551
+ event.preventDefault();
1552
+ event.stopPropagation();
1553
+ void handleCopyDetails();
1554
+ },
1555
+ children: copied ? copiedLabel : copyLabel
1556
+ }
1557
+ ) : null
1558
+ ] }),
1559
+ /* @__PURE__ */ jsx4("pre", { className: "fx-error-notice__details-body", children: details })
1560
+ ] }) : null
1561
+ ] }),
1562
+ /* @__PURE__ */ jsx4(
1563
+ IconButton,
1564
+ {
1565
+ label: closeLabel,
1566
+ icon: /* @__PURE__ */ jsx4(X2, { className: "fx-icon" }),
1567
+ variant: "quiet",
1568
+ size: "compact",
1569
+ onClick: onClose
1570
+ }
1571
+ )
1572
+ ] });
1573
+ }
1574
+ var STACK_PEEK = 8;
1575
+ var STACK_GAP = 8;
1576
+ var STACK_MAX_BEHIND = 2;
1577
+ function stackMetrics(items, heights, expanded) {
1578
+ const heightOf = (id) => heights[id] ?? 0;
1579
+ const frontHeight = items[0] ? heightOf(items[0].id) : 0;
1580
+ let y = 0;
1581
+ const slots = items.map((item, index) => {
1582
+ const height = heightOf(item.id);
1583
+ const peekIndex = Math.min(index, STACK_MAX_BEHIND);
1584
+ const slotY = expanded ? y : Math.max(0, frontHeight - height + peekIndex * STACK_PEEK);
1585
+ if (expanded) y += height + STACK_GAP;
1586
+ return {
1587
+ id: item.id,
1588
+ y: slotY,
1589
+ z: items.length - index,
1590
+ interactive: expanded || index === 0
1591
+ };
1592
+ });
1593
+ const stackHeight = expanded ? items.reduce((sum, item, index) => sum + heightOf(item.id) + (index > 0 ? STACK_GAP : 0), 0) : frontHeight + Math.min(Math.max(items.length - 1, 0), STACK_MAX_BEHIND) * STACK_PEEK;
1594
+ return { slots, stackHeight };
1595
+ }
1596
+ function ErrorNoticeStack({
1597
+ items,
1598
+ inline = false,
1599
+ onClose
1600
+ }) {
1601
+ const [expanded, setExpanded] = useState4(false);
1602
+ const [heights, setHeights] = useState4({});
1603
+ const slotNodes = useRef2(/* @__PURE__ */ new Map());
1604
+ const stacked = items.length > 1;
1605
+ const open = stacked && expanded;
1606
+ const measure = useCallback3(() => {
1607
+ setHeights((current) => {
1608
+ let changed = Object.keys(current).length !== items.length;
1609
+ const next = {};
1610
+ for (const item of items) {
1611
+ const height = slotNodes.current.get(item.id)?.offsetHeight ?? 0;
1612
+ next[item.id] = height;
1613
+ if (current[item.id] !== height) changed = true;
1614
+ }
1615
+ return changed ? next : current;
1616
+ });
1617
+ }, [items]);
1618
+ useLayoutEffect2(() => {
1619
+ measure();
1620
+ const observer = new ResizeObserver(measure);
1621
+ for (const item of items) {
1622
+ const node = slotNodes.current.get(item.id);
1623
+ if (node) observer.observe(node);
1624
+ }
1625
+ return () => observer.disconnect();
1626
+ }, [items, measure]);
1627
+ const { slots, stackHeight } = useMemo3(
1628
+ () => stackMetrics(items, heights, open),
1629
+ [items, heights, open]
1630
+ );
1631
+ if (items.length === 0) return null;
1632
+ return /* @__PURE__ */ jsx4(
1633
+ "div",
1634
+ {
1635
+ className: ["fx-error-notice-region", "fx-ui", inline && "fx-error-notice-region--inline"].filter(Boolean).join(" "),
1636
+ "aria-live": "assertive",
1637
+ "data-count": items.length,
1638
+ "data-expanded": open ? "" : void 0,
1639
+ "data-ready": items.every((item) => (heights[item.id] ?? 0) > 0) ? "" : void 0,
1640
+ onMouseEnter: stacked ? () => setExpanded(true) : void 0,
1641
+ onMouseLeave: stacked ? () => setExpanded(false) : void 0,
1642
+ onFocus: stacked ? () => setExpanded(true) : void 0,
1643
+ onBlur: stacked ? (event) => {
1644
+ if (!event.currentTarget.contains(event.relatedTarget)) {
1645
+ setExpanded(false);
1646
+ }
1647
+ } : void 0,
1648
+ style: {
1649
+ "--fx-error-notice-stack-height": `${stackHeight}px`
1650
+ },
1651
+ children: items.map((notice) => {
1652
+ const slot = slots.find((entry) => entry.id === notice.id);
1653
+ return /* @__PURE__ */ jsx4(
1654
+ "div",
1655
+ {
1656
+ className: "fx-error-notice-slot",
1657
+ ref: (node) => {
1658
+ if (node) slotNodes.current.set(notice.id, node);
1659
+ else slotNodes.current.delete(notice.id);
1660
+ },
1661
+ "data-inert": slot.interactive ? void 0 : "",
1662
+ style: {
1663
+ "--fx-error-notice-y": `${slot.y}px`,
1664
+ "--fx-error-notice-z": slot.z
1665
+ },
1666
+ children: /* @__PURE__ */ jsx4(
1667
+ ErrorNotice,
1668
+ {
1669
+ ...notice,
1670
+ closeLabel: notice.closeLabel,
1671
+ onClose: () => onClose(notice.id)
1672
+ }
1673
+ )
1674
+ },
1675
+ notice.id
1676
+ );
1677
+ })
1678
+ }
1679
+ );
1680
+ }
1681
+ function ErrorNoticeHost() {
1682
+ const items = useSyncExternalStore2(subscribeErrorNotices, getErrorNotices, getErrorNotices);
1683
+ const ordered = useMemo3(() => [...items].reverse(), [items]);
1684
+ if (typeof document === "undefined" || ordered.length === 0) return null;
1685
+ return createPortal2(
1686
+ /* @__PURE__ */ jsx4(ErrorNoticeStack, { items: ordered, onClose: dismissErrorNotice }),
1687
+ document.body
1688
+ );
1689
+ }
1690
+
1691
+ // packages/view-components/src/PageTabStrip.tsx
1692
+ import {
1693
+ ChevronsRight,
1694
+ Minus,
1695
+ Pin,
1696
+ Plus,
1697
+ X as X3
1698
+ } from "lucide-react";
1699
+ import {
1700
+ useCallback as useCallback4,
1701
+ useEffect as useEffect4,
1702
+ useId as useId2,
1703
+ useRef as useRef3,
1704
+ useState as useState5
1705
+ } from "react";
1706
+
1707
+ // packages/view-components/src/page-tab-icons.ts
1708
+ import {
1709
+ Box as Box2,
1710
+ Clapperboard,
1711
+ File,
1712
+ FileCode2,
1713
+ FileText,
1714
+ Image,
1715
+ Music,
1716
+ Package,
1717
+ Puzzle,
1718
+ Settings2,
1719
+ Type
1720
+ } from "lucide-react";
1721
+ var ICON_BY_KIND = {
1722
+ scene: Clapperboard,
1723
+ model: Box2,
1724
+ image: Image,
1725
+ audio: Music,
1726
+ font: Type,
1727
+ pack: Package,
1728
+ code: FileCode2,
1729
+ doc: FileText,
1730
+ config: Settings2,
1731
+ plugin: Puzzle
1732
+ };
1733
+ var EXT_KIND = [
1734
+ [["ts", "tsx", "js", "jsx", "mjs", "cjs", "py"], "code"],
1735
+ [["md", "markdown", "txt"], "doc"],
1736
+ [["png", "jpg", "jpeg", "webp", "gif", "svg", "ico", "hdr"], "image"],
1737
+ [["mp3", "wav", "ogg", "flac", "aac", "m4a", "opus"], "audio"],
1738
+ [["glb", "gltf", "fbx"], "model"],
1739
+ [["ttf", "otf", "woff2"], "font"]
1740
+ ];
1741
+ function pageKindOf(input) {
1742
+ const path = (input.resourcePath ?? "").toLowerCase();
1743
+ if (path) {
1744
+ if (path.endsWith(".scene.json")) return "scene";
1745
+ if (path.endsWith(".pack.json")) return path.includes("scene") ? "scene" : "pack";
1746
+ const ext = path.split(/[?#]/u, 1)[0]?.split(".").pop() ?? "";
1747
+ for (const [exts, kind] of EXT_KIND) if (exts.includes(ext)) return kind;
1748
+ if (path.endsWith("forge.json") || path.endsWith("package.json")) return "config";
1749
+ }
1750
+ const id = input.typeId.toLowerCase();
1751
+ for (const kind of Object.keys(ICON_BY_KIND)) {
1752
+ if (id.includes(kind)) return kind;
1753
+ }
1754
+ if (id.includes("scene") || id.includes("level")) return "scene";
1755
+ if (id.includes("workbench") || id.includes("wb-") || id.includes("plugin")) return "plugin";
1756
+ return "config";
1757
+ }
1758
+ function iconForPage(input) {
1759
+ const path = (input.resourcePath ?? "").toLowerCase();
1760
+ const kind = pageKindOf(input);
1761
+ if (!path && kind === "config" && !input.typeId.toLowerCase().includes("config")) return File;
1762
+ return ICON_BY_KIND[kind];
1763
+ }
1764
+
1765
+ // packages/view-components/src/PageTabStrip.tsx
1766
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1767
+ var DEFAULT_LABELS = {
1768
+ tabList: "\u5DF2\u6253\u5F00\u7684\u9875\u9762",
1769
+ newPage: "\u65B0\u5EFA\u9875\u9762",
1770
+ allPages: "\u5168\u90E8\u9875\u9762",
1771
+ noOpenableTypes: "\u6CA1\u6709\u53EF\u65B0\u5EFA\u7684\u7C7B\u578B",
1772
+ closeTab: "\u5173\u95ED\u6807\u7B7E\u9875",
1773
+ contextClose: "\u5173\u95ED",
1774
+ contextCloseOthers: "\u5173\u95ED\u5176\u4ED6",
1775
+ contextCloseToRight: "\u5173\u95ED\u53F3\u4FA7"
1776
+ };
1777
+ function classes2(...names) {
1778
+ return names.filter(Boolean).join(" ");
1779
+ }
1780
+ function useAnchoredMenu(anchorRef) {
1781
+ const [open, setOpen] = useState5(false);
1782
+ const [position, setPosition] = useState5({ x: 0, y: 0 });
1783
+ const openAtAnchor = useCallback4(
1784
+ (align = "start") => {
1785
+ const el = anchorRef.current;
1786
+ if (!el) return;
1787
+ const rect = el.getBoundingClientRect();
1788
+ setPosition({
1789
+ x: align === "end" ? rect.right : rect.left,
1790
+ y: rect.bottom + 4
1791
+ });
1792
+ setOpen(true);
1793
+ },
1794
+ [anchorRef]
1795
+ );
1796
+ return { open, setOpen, position, openAtAnchor };
1797
+ }
1798
+ function PageTabStrip({
1799
+ pages,
1800
+ activePageId,
1801
+ onSelect,
1802
+ onClose,
1803
+ onCloseOthers,
1804
+ onCloseToRight,
1805
+ onReorder,
1806
+ newPageTypes = [],
1807
+ onNewPage,
1808
+ labels: labelOverrides,
1809
+ className
1810
+ }) {
1811
+ const labels = { ...DEFAULT_LABELS, ...labelOverrides };
1812
+ const listRef = useRef3(null);
1813
+ const newButtonRef = useRef3(null);
1814
+ const overflowButtonRef = useRef3(null);
1815
+ const dragKeyRef = useRef3(null);
1816
+ const [draggingKey, setDraggingKey] = useState5(null);
1817
+ const [overflowing, setOverflowing] = useState5(false);
1818
+ const [contextMenu, setContextMenu] = useState5(
1819
+ null
1820
+ );
1821
+ const newMenu = useAnchoredMenu(newButtonRef);
1822
+ const overflowMenu = useAnchoredMenu(overflowButtonRef);
1823
+ const menuId = useId2();
1824
+ useEffect4(() => {
1825
+ if (!activePageId) return;
1826
+ listRef.current?.querySelector(`[data-page-id="${CSS.escape(activePageId)}"]`)?.scrollIntoView({ block: "nearest", inline: "nearest" });
1827
+ }, [activePageId]);
1828
+ useEffect4(() => {
1829
+ const el = listRef.current;
1830
+ if (!el) return;
1831
+ const measure = () => setOverflowing(el.scrollWidth - el.clientWidth > 1);
1832
+ measure();
1833
+ const ro = new ResizeObserver(measure);
1834
+ ro.observe(el);
1835
+ return () => ro.disconnect();
1836
+ }, [pages.length]);
1837
+ useEffect4(() => {
1838
+ const end = () => {
1839
+ dragKeyRef.current = null;
1840
+ setDraggingKey(null);
1841
+ };
1842
+ window.addEventListener("pointerup", end);
1843
+ return () => window.removeEventListener("pointerup", end);
1844
+ }, []);
1845
+ const handleTabClick = useCallback4(
1846
+ (pageId) => {
1847
+ if (pageId === activePageId) return;
1848
+ onSelect(pageId);
1849
+ },
1850
+ [activePageId, onSelect]
1851
+ );
1852
+ const handlePointerDown = useCallback4((event, pageId) => {
1853
+ if (event.button !== 0) return;
1854
+ if (event.target.closest("[data-page-close]")) return;
1855
+ dragKeyRef.current = pageId;
1856
+ }, []);
1857
+ const handlePointerMove = useCallback4(
1858
+ (event) => {
1859
+ const dragKey = dragKeyRef.current;
1860
+ if (!dragKey || event.buttons !== 1 || !onReorder) return;
1861
+ const overId = event.target.closest("[data-page-id]")?.getAttribute("data-page-id");
1862
+ if (!overId || overId === dragKey) return;
1863
+ const toIndex = pages.findIndex((page) => page.id === overId);
1864
+ if (toIndex < 0) return;
1865
+ setDraggingKey(dragKey);
1866
+ onReorder(dragKey, toIndex);
1867
+ },
1868
+ [onReorder, pages]
1869
+ );
1870
+ const closePage = useCallback4(
1871
+ (pageId) => {
1872
+ onClose?.(pageId);
1873
+ },
1874
+ [onClose]
1875
+ );
1876
+ if (pages.length === 0) return null;
1877
+ const contextPage = contextMenu ? pages.find((page) => page.id === contextMenu.pageId) : void 0;
1878
+ const contextItems = contextMenu && contextPage ? [
1879
+ {
1880
+ id: "close",
1881
+ label: labels.contextClose,
1882
+ icon: /* @__PURE__ */ jsx5(X3, { className: "fx-icon", "aria-hidden": true }),
1883
+ disabled: !contextPage.closable,
1884
+ onSelect: () => closePage(contextMenu.pageId)
1885
+ },
1886
+ {
1887
+ id: "close-others",
1888
+ label: labels.contextCloseOthers,
1889
+ icon: /* @__PURE__ */ jsx5(Minus, { className: "fx-icon", "aria-hidden": true }),
1890
+ onSelect: () => {
1891
+ onCloseOthers?.(contextMenu.pageId);
1892
+ onSelect(contextMenu.pageId);
1893
+ }
1894
+ },
1895
+ {
1896
+ id: "close-right",
1897
+ label: labels.contextCloseToRight,
1898
+ icon: /* @__PURE__ */ jsx5(ChevronsRight, { className: "fx-icon", "aria-hidden": true }),
1899
+ onSelect: () => onCloseToRight?.(contextMenu.pageId)
1900
+ }
1901
+ ] : [];
1902
+ const newPageMenuItems = newPageTypes.length === 0 ? [{ id: "empty", label: labels.noOpenableTypes, disabled: true }] : newPageTypes.map((type) => {
1903
+ const Icon = iconForPage({ typeId: type.typeId });
1904
+ return {
1905
+ id: type.typeId,
1906
+ label: type.title,
1907
+ icon: /* @__PURE__ */ jsx5(Icon, { className: "fx-icon", "aria-hidden": true }),
1908
+ onSelect: () => onNewPage?.(type.typeId)
1909
+ };
1910
+ });
1911
+ const overflowMenuItems = pages.map((page) => {
1912
+ const Icon = page.icon ?? iconForPage({ typeId: page.typeId, resourcePath: page.resourcePath });
1913
+ const mark = activePageId === page.id ? "\u25CF" : "\u25CB";
1914
+ const label = page.dirty ? `${page.title} *` : page.title;
1915
+ return {
1916
+ id: page.id,
1917
+ label: /* @__PURE__ */ jsxs4(Fragment2, { children: [
1918
+ /* @__PURE__ */ jsx5("span", { className: "fx-page-tab-menu__mark", children: mark }),
1919
+ /* @__PURE__ */ jsx5("span", { className: "fx-page-tab-menu__label", children: label })
1920
+ ] }),
1921
+ icon: /* @__PURE__ */ jsx5(Icon, { className: "fx-icon", "aria-hidden": true }),
1922
+ selected: activePageId === page.id,
1923
+ onSelect: () => onSelect(page.id)
1924
+ };
1925
+ });
1926
+ return /* @__PURE__ */ jsxs4("div", { className: classes2("fx-page-tab-strip", "fx-ui", className), "data-fx-slot": "PageTabs", children: [
1927
+ /* @__PURE__ */ jsxs4("div", { className: "fx-page-tab-strip__scope", children: [
1928
+ /* @__PURE__ */ jsx5(
1929
+ "div",
1930
+ {
1931
+ ref: listRef,
1932
+ className: "fx-page-tab-strip__list",
1933
+ role: "tablist",
1934
+ "aria-label": labels.tabList,
1935
+ onPointerMove: handlePointerMove,
1936
+ children: pages.map((page) => {
1937
+ const active = activePageId === page.id;
1938
+ const Icon = page.icon ?? iconForPage({ typeId: page.typeId, resourcePath: page.resourcePath });
1939
+ const closable = page.closable !== false;
1940
+ const tabClass = classes2(
1941
+ "fx-page-tab",
1942
+ active && "is-active",
1943
+ !closable && "is-pinned",
1944
+ page.dirty && "is-dirty",
1945
+ draggingKey === page.id && "is-drag"
1946
+ );
1947
+ return /* @__PURE__ */ jsxs4(
1948
+ "button",
1949
+ {
1950
+ type: "button",
1951
+ className: tabClass,
1952
+ role: "tab",
1953
+ "aria-selected": active,
1954
+ "data-page-id": page.id,
1955
+ "data-dirty": page.dirty ? "1" : void 0,
1956
+ title: page.tooltip ?? page.resourcePath ?? page.title,
1957
+ onClick: () => handleTabClick(page.id),
1958
+ onAuxClick: (event) => {
1959
+ if (event.button === 1 && closable) {
1960
+ event.preventDefault();
1961
+ closePage(page.id);
1962
+ }
1963
+ },
1964
+ onContextMenu: (event) => {
1965
+ event.preventDefault();
1966
+ setContextMenu({ x: event.clientX, y: event.clientY, pageId: page.id });
1967
+ },
1968
+ onPointerDown: (event) => handlePointerDown(event, page.id),
1969
+ children: [
1970
+ /* @__PURE__ */ jsx5(Icon, { className: "fx-page-tab__icon", "aria-hidden": true }),
1971
+ /* @__PURE__ */ jsx5("span", { className: "fx-page-tab__label", children: page.title }),
1972
+ page.dirty ? /* @__PURE__ */ jsx5("span", { className: "fx-page-tab__dirty", "aria-hidden": true, children: "*" }) : null,
1973
+ closable ? /* @__PURE__ */ jsx5(
1974
+ "span",
1975
+ {
1976
+ className: "fx-page-tab__close",
1977
+ role: "button",
1978
+ "aria-label": labels.closeTab,
1979
+ "data-page-close": page.id,
1980
+ onClick: (event) => {
1981
+ event.stopPropagation();
1982
+ closePage(page.id);
1983
+ },
1984
+ children: /* @__PURE__ */ jsx5(X3, { className: "fx-page-tab__close-icon", "aria-hidden": true })
1985
+ }
1986
+ ) : /* @__PURE__ */ jsx5(Pin, { className: "fx-page-tab__pin", "aria-hidden": true })
1987
+ ]
1988
+ },
1989
+ page.id
1990
+ );
1991
+ })
1992
+ }
1993
+ ),
1994
+ /* @__PURE__ */ jsx5(
1995
+ "button",
1996
+ {
1997
+ ref: newButtonRef,
1998
+ type: "button",
1999
+ className: "fx-page-tab-btn fx-page-tab-btn--new",
2000
+ title: labels.newPage,
2001
+ "aria-label": labels.newPage,
2002
+ "aria-haspopup": "menu",
2003
+ "aria-expanded": newMenu.open,
2004
+ "aria-controls": `${menuId}-new`,
2005
+ onClick: () => {
2006
+ if (newMenu.open) newMenu.setOpen(false);
2007
+ else newMenu.openAtAnchor("start");
2008
+ },
2009
+ children: /* @__PURE__ */ jsx5(Plus, { className: "fx-page-tab-btn__icon", "aria-hidden": true })
2010
+ }
2011
+ ),
2012
+ /* @__PURE__ */ jsx5("div", { className: "fx-page-tab-strip__actions", children: overflowing ? /* @__PURE__ */ jsxs4(
2013
+ "button",
2014
+ {
2015
+ ref: overflowButtonRef,
2016
+ type: "button",
2017
+ className: "fx-page-tab-btn",
2018
+ title: labels.allPages,
2019
+ "aria-haspopup": "menu",
2020
+ "aria-expanded": overflowMenu.open,
2021
+ "aria-controls": `${menuId}-overflow`,
2022
+ onClick: () => {
2023
+ if (overflowMenu.open) overflowMenu.setOpen(false);
2024
+ else overflowMenu.openAtAnchor("end");
2025
+ },
2026
+ children: [
2027
+ /* @__PURE__ */ jsx5(ChevronsRight, { className: "fx-page-tab-btn__icon", "aria-hidden": true }),
2028
+ /* @__PURE__ */ jsx5("span", { children: pages.length })
2029
+ ]
2030
+ }
2031
+ ) : null })
2032
+ ] }),
2033
+ /* @__PURE__ */ jsx5(
2034
+ ContextMenu,
2035
+ {
2036
+ open: contextMenu !== null,
2037
+ x: contextMenu?.x ?? 0,
2038
+ y: contextMenu?.y ?? 0,
2039
+ items: contextItems,
2040
+ onClose: () => setContextMenu(null),
2041
+ label: contextPage?.title ?? labels.tabList
2042
+ }
2043
+ ),
2044
+ /* @__PURE__ */ jsx5(
2045
+ ContextMenu,
2046
+ {
2047
+ open: newMenu.open,
2048
+ x: newMenu.position.x,
2049
+ y: newMenu.position.y,
2050
+ items: newPageMenuItems,
2051
+ onClose: () => newMenu.setOpen(false),
2052
+ label: labels.newPage,
2053
+ containerProps: { id: `${menuId}-new` }
2054
+ }
2055
+ ),
2056
+ /* @__PURE__ */ jsx5(
2057
+ ContextMenu,
2058
+ {
2059
+ open: overflowMenu.open,
2060
+ x: overflowMenu.position.x,
2061
+ y: overflowMenu.position.y,
2062
+ items: overflowMenuItems,
2063
+ onClose: () => overflowMenu.setOpen(false),
2064
+ label: labels.allPages,
2065
+ containerProps: { id: `${menuId}-overflow` }
2066
+ }
2067
+ )
2068
+ ] });
2069
+ }
2070
+
2071
+ export {
2072
+ useWorkspaceClientConnected,
2073
+ anchorRectFromPoint,
2074
+ OverlayRootProvider,
2075
+ useOverlayRoot,
2076
+ Text,
2077
+ Surface,
2078
+ Button,
2079
+ IconButton,
2080
+ Field,
2081
+ TextInput,
2082
+ Checkbox,
2083
+ RangeInput,
2084
+ Switch,
2085
+ Spinner,
2086
+ Status,
2087
+ EmptyState,
2088
+ LoadingState,
2089
+ PanelHeader,
2090
+ Toolbar,
2091
+ SearchField,
2092
+ Menu,
2093
+ FloatingMenu,
2094
+ MenuDropdown,
2095
+ ContextMenu,
2096
+ Dialog,
2097
+ Tooltip,
2098
+ PropertyRow,
2099
+ CollapsibleSection,
2100
+ formatInspectorFieldLabel,
2101
+ resolveInspectorFieldKind,
2102
+ normalizeInspectorFieldValue,
2103
+ InspectorFieldControl,
2104
+ InspectorForm,
2105
+ showErrorNotice,
2106
+ ErrorNoticeHost,
2107
+ PageTabStrip,
2108
+ themeNames,
2109
+ initializeTheme,
2110
+ ThemeProvider,
2111
+ useTheme
2112
+ };
2113
+ //# sourceMappingURL=chunk-NJH2OJFC.mjs.map