@forsion/unit 2.13.4 → 2.13.5

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 (308) hide show
  1. package/main.mjs +112 -9
  2. package/package.json +1 -1
  3. package/release.json +5 -5
  4. package/web/assets/ArtificialView-BD1yHz1N.js +1 -0
  5. package/web/assets/AutomationBuilder-B09c-5Bi.js +1 -0
  6. package/web/assets/CalendarConfigView-Bd-ZDGPO.js +1 -0
  7. package/web/assets/CalendarSide-B0RVbOsg.js +1 -0
  8. package/web/assets/CalendarView-BHio-n_r.js +3 -0
  9. package/web/assets/CalendarView-t91KpUG7.css +1 -0
  10. package/web/assets/CapabilityMenu-DyHTEYLr.js +1 -0
  11. package/web/assets/Chrome-C7F6fdDp.js +1 -0
  12. package/web/assets/{CodeView-GZ0BAgoW.js → CodeView-BGOnrGhB.js} +3 -3
  13. package/web/assets/CtxMenuButtons-BYjrbUKS.js +1 -0
  14. package/web/assets/DashboardGridView-CR-R_qV8.js +25 -0
  15. package/web/assets/DashboardGridView-RoVFSkNO.css +1 -0
  16. package/web/assets/EventCard-QyYorE1_.js +1 -0
  17. package/web/assets/ExcalidrawCanvas-BgcFPMpU.css +1 -0
  18. package/web/assets/ExcalidrawCanvas-lwJCN6uB.js +1 -0
  19. package/web/assets/FloatingToc-DO7SH8Ku.js +1 -0
  20. package/web/assets/GitCloneDialog-CbW-RJak.js +1 -0
  21. package/web/assets/{GitCloneDialog-Bj9G3o-n.css → GitCloneDialog-DOxZk2K0.css} +1 -1
  22. package/web/assets/HomepageView-Bx8FbWlY.css +1 -0
  23. package/web/assets/HomepageView-CHJEhf9c.js +4 -0
  24. package/web/assets/ImageStudioPanels-CgVf0wiq.js +3 -0
  25. package/web/assets/ImageStudioView-4WcX0_V4.js +1 -0
  26. package/web/assets/InlineAiPanel-CdIPINsA.js +1 -0
  27. package/web/assets/InlineFiles-CAIyTk1n.js +1 -0
  28. package/web/assets/{MarkdownBlock-DQTuoen3.css → MarkdownBlock-Cqfk5DhC.css} +1 -1
  29. package/web/assets/MarkdownBlock-DSItkLhu.js +58 -0
  30. package/web/assets/ModelPill--CU3XTIQ.js +2 -0
  31. package/web/assets/{ModelPill-CzdNh7Mt.css → ModelPill-BiUsuhy3.css} +1 -1
  32. package/web/assets/MuseLibraryView-PlS7HAlV.js +2 -0
  33. package/web/assets/MuseView-CvsO62Fo.js +7 -0
  34. package/web/assets/{PageHistoryPanel-Bn4-XmdK.js → PageHistoryPanel-CDh7nm78.js} +2 -2
  35. package/web/assets/{PdfAnnotator-Cq8cklTz.js → PdfAnnotator-DafvjP3U.js} +3 -3
  36. package/web/assets/PenRow-CEy-s6SF.js +1 -0
  37. package/web/assets/PluginToolCard-BmTRr5JT.css +1 -0
  38. package/web/assets/PluginToolCard-DCzLhsCA.js +2 -0
  39. package/web/assets/ProductView-AUqnTwmQ.js +1 -0
  40. package/web/assets/SettingsPage-B9mmkWaM.js +3 -0
  41. package/web/assets/StudioGuestSurface-OOhRA8nt.js +1 -0
  42. package/web/assets/TodoListView-BkgMe44I.js +1 -0
  43. package/web/assets/Tooltip-DOYi44eY.js +1 -0
  44. package/web/assets/UnifiedPage-CTmQpf2T.css +1 -0
  45. package/web/assets/UnifiedPage-s7-tDSwG.js +712 -0
  46. package/web/assets/ViewSelectionBar-WmSWMFsR.js +2 -0
  47. package/web/assets/appStore-DDOkzWDA.js +456 -0
  48. package/web/assets/appStore-iy8_Tmac.css +1 -0
  49. package/web/assets/arrow-up-right-BptN64d-.js +1 -0
  50. package/web/assets/{artificial-BzLFkChP.css → artificial-BubVxExB.css} +1 -1
  51. package/web/assets/astryxBridge-BL56QfEv.js +69 -0
  52. package/web/assets/astryxBridge-djzCiy4v.css +1 -0
  53. package/web/assets/automationListSource-B1jz6q0t.js +1 -0
  54. package/web/assets/boardSurface-CP4HNmcm.js +1 -0
  55. package/web/assets/calendarNavStore-DCi7VBmM.js +1 -0
  56. package/web/assets/canvasPrefs-ArsX3NFO.js +1 -0
  57. package/web/assets/chatBoxSurface-DRsDr-MT.js +1 -0
  58. package/web/assets/chevron-up-ChXNh14u.js +1 -0
  59. package/web/assets/{client-CaivGZFR.js → client-fKy9CWk0.js} +5 -5
  60. package/web/assets/code-xml-DCCD9eCS.js +1 -0
  61. package/web/assets/{codeStudioStore-DhyMazGT.js → codeStudioStore-BgLfCDK2.js} +8 -8
  62. package/web/assets/codingNavigation-BrkLENBZ.css +1 -0
  63. package/web/assets/contextMenuSurface-BF593l2M.js +1 -0
  64. package/web/assets/copy-plus-ClKrSgM7.js +1 -0
  65. package/web/assets/create-DYmVT68X.js +14 -0
  66. package/web/assets/dashboardSurface-C6cbR3oG.js +1 -0
  67. package/web/assets/dbStore-BIG5Mfh2.js +1 -0
  68. package/web/assets/deskCapture-q-jRDIcc.js +1 -0
  69. package/web/assets/{diff2html-Daje9Kkm.js → diff2html-Di8qIz6O.js} +2 -2
  70. package/web/assets/{docx-preview-CABR7n30.js → docx-preview-B-URZXdP.js} +1 -1
  71. package/web/assets/draft-CBSW5tHx.js +2 -0
  72. package/web/assets/drawingStore-CGvTqqYW.js +7 -0
  73. package/web/assets/file-down-Z913cCyQ.js +1 -0
  74. package/web/assets/floatingTocSurface-DGwTiqvU.js +1 -0
  75. package/web/assets/foldActions-DGIPTmE1.js +1 -0
  76. package/web/assets/folder-1OJQeDI1.js +1 -0
  77. package/web/assets/folder-minus-D_j1SwHu.js +1 -0
  78. package/web/assets/folder-plus-DP9sFr26.js +1 -0
  79. package/web/assets/gestures-ZhFAENNZ.js +1 -0
  80. package/web/assets/git-branch-BMajF2cu.js +1 -0
  81. package/web/assets/homeCardStatus-5R7XkxFL.js +1 -0
  82. package/web/assets/i18n-CAf4PT1o.css +1 -0
  83. package/web/assets/i18n.generated-DW_l6CkR.js +15 -0
  84. package/web/assets/imageStudio-CwG21Bat.css +1 -0
  85. package/web/assets/imageStudio-DC_syDtx.js +4 -0
  86. package/web/assets/index-B8A3nKeL.js +1 -0
  87. package/web/assets/{index-BGfvNj7R.js → index-BDZIQnEx.js} +2 -2
  88. package/web/assets/index-BYKR7EVg.js +1 -0
  89. package/web/assets/index-BeW45J9J.js +7 -0
  90. package/web/assets/index-BnJguNqI.js +1 -0
  91. package/web/assets/index-BniT-A2n.js +1 -0
  92. package/web/assets/index-C--E96Ul.js +1 -0
  93. package/web/assets/index-CI2esW1X.js +1 -0
  94. package/web/assets/index-CIKPZc3Q.js +1 -0
  95. package/web/assets/index-COzdD7mZ.js +13 -0
  96. package/web/assets/index-CPfmhZ3Z.js +1 -0
  97. package/web/assets/index-CVLDDD5Z.js +1 -0
  98. package/web/assets/index-CWXpOSI2.js +1 -0
  99. package/web/assets/index-Cg1FWM_p.js +1 -0
  100. package/web/assets/index-CmsN2Zm2.js +1 -0
  101. package/web/assets/index-CtCYv9bF.js +1 -0
  102. package/web/assets/index-CtRdzpNh.js +1 -0
  103. package/web/assets/index-D-ClOPbg.js +1 -0
  104. package/web/assets/{index-gt5JBIFf.js → index-DfhEDV2T.js} +2 -2
  105. package/web/assets/index-Dr6YmrrT.js +1 -0
  106. package/web/assets/index-SpegRFQV.js +1 -0
  107. package/web/assets/index-bF04pF8q.js +3 -0
  108. package/web/assets/index-fDB1l4d-.js +3398 -0
  109. package/web/assets/index-jzlU5luC.js +1 -0
  110. package/web/assets/{index-O05r2Ty6.js → index-uhvJ8AiJ.js} +1 -1
  111. package/web/assets/{invitePage-Bgveo6Hj.js → invitePage-iOT1zBvp.js} +1 -1
  112. package/web/assets/{ipc-B6hkgxQL.js → ipc-SAPDwyQ4.js} +1 -1
  113. package/web/assets/{jszip.min-eU-k-vEy.js → jszip.min-B3n1FGCb.js} +1 -1
  114. package/web/assets/launchpad-C9U9hpWJ.css +1 -0
  115. package/web/assets/launchpad-CcmSwlJl.js +2 -0
  116. package/web/assets/layout-grid-oIyIGbc5.js +1 -0
  117. package/web/assets/linkFollow-uke1Xtit.js +8 -0
  118. package/web/assets/listFold-BeNv2v6M.js +1 -0
  119. package/web/assets/lock-open-D2nMg0ga.js +1 -0
  120. package/web/assets/log-out-D70NCXC4.js +1 -0
  121. package/web/assets/magnet-Cqmm97W8.js +1 -0
  122. package/web/assets/main-B9aT0WXG.js +15 -0
  123. package/web/assets/main-BlVApHpj.css +1 -0
  124. package/web/assets/markdownEditorSurface-BiDH0__r.css +1 -0
  125. package/web/assets/markdownEditorSurface-zUzFity2.js +3 -0
  126. package/web/assets/mediaPlayer-DB4KUvua.js +1 -0
  127. package/web/assets/message-square-plus-BvUfAAZm.js +1 -0
  128. package/web/assets/{messages-CKtabOqy.js → messages-GQUjmbwW.js} +1 -1
  129. package/web/assets/minimize-2-CMhzL6ZW.js +1 -0
  130. package/web/assets/mobileEntry-6u7TYC4s.css +1 -0
  131. package/web/assets/mobileEntry-BnHzrdoC.js +13 -0
  132. package/web/assets/modelPickerSurface-Dtz40Ae2.js +1 -0
  133. package/web/assets/nativeDownload-DsGyUSJ5.js +1 -0
  134. package/web/assets/nativeSheetMenu--iihXNVd.js +1 -0
  135. package/web/assets/pageStore-CyvNZEYX.js +13 -0
  136. package/web/assets/pageStore-ys8L4rjF.css +1 -0
  137. package/web/assets/{pageTree-BYYPgZm_.js → pageTree-Ci2qzrs1.js} +3 -3
  138. package/web/assets/pen-line-DC3lbEY1.js +1 -0
  139. package/web/assets/pen-tool-DD5_N4lZ.js +1 -0
  140. package/web/assets/pencil--sWwxHdP.js +1 -0
  141. package/web/assets/phoneList-BpLxxdq6.css +1 -0
  142. package/web/assets/phoneList-DKRMxQHf.js +1 -0
  143. package/web/assets/pluginChat-82zZt47Y.js +2 -0
  144. package/web/assets/react-b7FrqRQR.js +1 -0
  145. package/web/assets/recordSurface-vUX25Z8R.js +1 -0
  146. package/web/assets/redo-2-CqlqhWrI.js +1 -0
  147. package/web/assets/rotate-ccw-D8kni6Ni.js +1 -0
  148. package/web/assets/selectionActions-DIq0xDm8.js +2 -0
  149. package/web/assets/selectionBarSurface-B94e5JW_.js +1 -0
  150. package/web/assets/sessionTitle-Ctp4iNKu.js +1 -0
  151. package/web/assets/settingsPageSurface-C9TA3mJg.js +1 -0
  152. package/web/assets/sharePage-CY04XCAf.js +2 -0
  153. package/web/assets/{shareViewer-BiMqIBxP.js → shareViewer-DweNF8Ch.js} +2 -2
  154. package/web/assets/star-B0sZEmbj.js +1 -0
  155. package/web/assets/tableSurface-CSBYBw5P.js +1 -0
  156. package/web/assets/tanguProbe-B8Qv2vcm.js +6 -0
  157. package/web/assets/{terminalView-lbcBgG0c.js → terminalView-BLGdmdl7.js} +3 -3
  158. package/web/assets/type-Dt7RNB9g.js +1 -0
  159. package/web/assets/undo-2-QimgpLBn.js +1 -0
  160. package/web/assets/{unitAccount-DGwGsmC3.js → unitAccount-DL3jfd84.js} +1 -1
  161. package/web/assets/{unitBridge-CE2yAvm0.js → unitBridge-BSsCy1zP.js} +1 -1
  162. package/web/assets/{unitCloudTransport-BGFwkaDM.js → unitCloudTransport-CI_6H0TU.js} +1 -1
  163. package/web/assets/unitOwnerAccess-CiQ7nD7E.js +1 -0
  164. package/web/assets/unitShim-Dl2ksNp-.js +5 -0
  165. package/web/assets/upload-Dy7svciS.js +1 -0
  166. package/web/assets/userSpaces-oMHIWgYe.js +1 -0
  167. package/web/assets/viewportLock-B0l1GU_k.css +1 -0
  168. package/web/assets/viewportLock-BZq5PTeN.js +738 -0
  169. package/web/assets/zoom-in-DDEtY_Go.js +1 -0
  170. package/web/excalidraw/excalidraw.js +4 -2
  171. package/web/index.html +12 -13
  172. package/web/assets/ArtificialView-DLh75dAI.js +0 -1
  173. package/web/assets/AutomationBuilder-DNWWGnFr.js +0 -1
  174. package/web/assets/CalendarConfigView-G7je7k9-.js +0 -1
  175. package/web/assets/CalendarView-B2MtaOJk.js +0 -1
  176. package/web/assets/CapabilityMenu-DJaZ_Cyt.js +0 -1
  177. package/web/assets/CheckboxInput-FYXLaZke.js +0 -1
  178. package/web/assets/Chrome-CFonajM4.js +0 -1
  179. package/web/assets/DashboardGridView-D9s9pez_.css +0 -1
  180. package/web/assets/DashboardGridView-Xgw4wa0_.js +0 -17
  181. package/web/assets/EventCard-_39F_I5M.js +0 -1
  182. package/web/assets/ExcalidrawCanvas-4uYrLYin.css +0 -1
  183. package/web/assets/ExcalidrawCanvas-rXujil36.js +0 -1
  184. package/web/assets/FloatingToc-DNqAkkI0.js +0 -1
  185. package/web/assets/GitCloneDialog-CQx-O4j1.js +0 -1
  186. package/web/assets/HomepageView-DcWmTPQO.css +0 -1
  187. package/web/assets/HomepageView-MYEk3RCs.js +0 -3
  188. package/web/assets/ImageStudioPanels-4wnb2XF4.js +0 -3
  189. package/web/assets/ImageStudioView-qrmW8pfx.js +0 -1
  190. package/web/assets/InlineAiPanel-B3kd1ob2.js +0 -1
  191. package/web/assets/InlineFiles-Clnqh9jD.js +0 -1
  192. package/web/assets/MarkdownBlock-DT_wsaja.js +0 -58
  193. package/web/assets/ModelPill-JaIH3ffZ.js +0 -2
  194. package/web/assets/MuseLibraryView-DOJVVeU6.js +0 -2
  195. package/web/assets/MuseView-uxTmjVQa.js +0 -6
  196. package/web/assets/PenRow-COOYAaxx.js +0 -1
  197. package/web/assets/ProductView-DPTveulg.js +0 -1
  198. package/web/assets/RightPanel-BJUacrsf.js +0 -4
  199. package/web/assets/RightPanel-D0zk1g3I.css +0 -1
  200. package/web/assets/SketchCard-B_UU5sxV.js +0 -641
  201. package/web/assets/StudioGuestSurface-yBa4QKfX.js +0 -1
  202. package/web/assets/TargetHealthNotice-BLzDB-Xl.css +0 -1
  203. package/web/assets/TargetHealthNotice-CgkdTdhB.js +0 -47
  204. package/web/assets/TodoListView-CricdCfW.js +0 -1
  205. package/web/assets/Tooltip-o8ZqIb3L.js +0 -1
  206. package/web/assets/UnifiedPage-BWAyqj65.js +0 -69
  207. package/web/assets/UnifiedPage-CWXc_mo1.css +0 -1
  208. package/web/assets/ViewSelectionBar-35x8TiLA.js +0 -2
  209. package/web/assets/appStore-CI1_L5OS.js +0 -3357
  210. package/web/assets/appStore-DQc2marq.css +0 -1
  211. package/web/assets/approvalText-Cy2UAUAQ.js +0 -2
  212. package/web/assets/arrow-up-right-BDsMFoNQ.js +0 -1
  213. package/web/assets/astryxBridge-CF_hpqC2.css +0 -1
  214. package/web/assets/astryxBridge-CH_c5xjo.js +0 -70
  215. package/web/assets/automationListSource-CB6AWkL_.js +0 -1
  216. package/web/assets/boardSurface-CLvEUjbF.js +0 -1
  217. package/web/assets/book-open-BLzEdGfu.js +0 -1
  218. package/web/assets/calendarNavStore-BHUNxDx8.js +0 -1
  219. package/web/assets/canvasPrefs-CvE7mgyq.js +0 -1
  220. package/web/assets/chatBoxSurface-CuuHLzs5.js +0 -1
  221. package/web/assets/circle-question-mark-BM4ZRxQS.js +0 -1
  222. package/web/assets/circle-x-DTcNGZDT.js +0 -1
  223. package/web/assets/code-xml-AE3mT4T5.js +0 -1
  224. package/web/assets/codingNavigation-B0kVsy4x.js +0 -53
  225. package/web/assets/codingNavigation-DHCidM4N.css +0 -1
  226. package/web/assets/create-1JI2I47p.js +0 -14
  227. package/web/assets/dashboardSurface-CIE5HybN.js +0 -1
  228. package/web/assets/deskCapture-COW7aG5Y.js +0 -1
  229. package/web/assets/emoji-DZ9CA_3l.css +0 -1
  230. package/web/assets/emoji-DphwSxPx.js +0 -1
  231. package/web/assets/floatingTocSurface-BOm2QYBK.js +0 -1
  232. package/web/assets/foldActions-DNbJPlPl.js +0 -1
  233. package/web/assets/folder-DotgUhYD.js +0 -1
  234. package/web/assets/folder-plus-aJgL9NeP.js +0 -1
  235. package/web/assets/gestures-dqncPOwo.js +0 -1
  236. package/web/assets/git-branch-CwR2qic6.js +0 -1
  237. package/web/assets/hack2gate-dark-Dx2RtDRI.jpg +0 -0
  238. package/web/assets/hack2gate-light-DRKq9tyS.jpg +0 -0
  239. package/web/assets/hand-XNkzNiW2.js +0 -1
  240. package/web/assets/hard-drive-CfWKRoAE.js +0 -1
  241. package/web/assets/i18n-CykmULlm.css +0 -1
  242. package/web/assets/i18n.generated-BwynSSMk.js +0 -15
  243. package/web/assets/imageStudio-CWgLpC_d.js +0 -2
  244. package/web/assets/imageStudio-DZ0qGU2s.css +0 -1
  245. package/web/assets/index-B65ULikK.js +0 -1
  246. package/web/assets/index-BIIeiIap.js +0 -1
  247. package/web/assets/index-BOzsniE1.js +0 -297
  248. package/web/assets/index-BfrjVzia.js +0 -13
  249. package/web/assets/index-Bi9UtjVz.js +0 -1
  250. package/web/assets/index-C1uilc9i.js +0 -1
  251. package/web/assets/index-C3Dc3Ivz.js +0 -1
  252. package/web/assets/index-CJF_Ld1Y.js +0 -1
  253. package/web/assets/index-CMARP4oV.js +0 -1
  254. package/web/assets/index-C_RsQVNm.js +0 -7
  255. package/web/assets/index-ChyxZMm8.js +0 -1
  256. package/web/assets/index-CoKcOaZg.js +0 -1
  257. package/web/assets/index-CuviSCbk.js +0 -1
  258. package/web/assets/index-Cw43kua8.js +0 -1
  259. package/web/assets/index-D1fu6XQN.js +0 -3
  260. package/web/assets/index-DG-hXb63.js +0 -1
  261. package/web/assets/index-DjnTfJpN.js +0 -1
  262. package/web/assets/index-Dtw0abst.js +0 -1
  263. package/web/assets/index-W3ErfZiX.js +0 -1
  264. package/web/assets/index-Yc56b3XX.js +0 -1
  265. package/web/assets/index-d4jCdYJH.js +0 -1
  266. package/web/assets/index-siHtlYTM.js +0 -1
  267. package/web/assets/launchpad-C2c1MSVX.css +0 -1
  268. package/web/assets/layout-grid-CraV7nhh.js +0 -1
  269. package/web/assets/linkFollow-BpvDWzUx.js +0 -8
  270. package/web/assets/list-tree-cLJw-jYQ.js +0 -1
  271. package/web/assets/listFold-M8s5JYEC.js +0 -1
  272. package/web/assets/lock-DBkXXwaI.js +0 -1
  273. package/web/assets/lock-open-C-9-AWct.js +0 -1
  274. package/web/assets/log-out-C8bDXj9P.js +0 -1
  275. package/web/assets/main-BiS_5wrB.css +0 -1
  276. package/web/assets/main-CMk6twzA.js +0 -20
  277. package/web/assets/markdownEditorSurface-Bql20IAf.css +0 -1
  278. package/web/assets/markdownEditorSurface-DgQ0TUWH.js +0 -3
  279. package/web/assets/message-square-plus-8pfimvem.js +0 -1
  280. package/web/assets/minus-CfA9fAN3.js +0 -1
  281. package/web/assets/mobileEntry-DS1vohuL.css +0 -1
  282. package/web/assets/mobileEntry-NcMcK0LV.js +0 -13
  283. package/web/assets/nativeDownload-CNtwSCy0.js +0 -1
  284. package/web/assets/pageChrome-BR4cfIaA.js +0 -1
  285. package/web/assets/pageChrome-BbUhILy0.css +0 -1
  286. package/web/assets/pen-tool-C5ftHCnm.js +0 -1
  287. package/web/assets/pencil-ehhM9_9k.js +0 -1
  288. package/web/assets/phoneList-B6gwUJZF.js +0 -9
  289. package/web/assets/phoneList-iRdfiKA8.css +0 -1
  290. package/web/assets/pluginChat-DTTWWiUS.js +0 -2
  291. package/web/assets/redo-2-DCEAgQlN.js +0 -1
  292. package/web/assets/rotate-ccw-DdkrbRAB.js +0 -1
  293. package/web/assets/selectionActions-BQD2kox1.js +0 -2
  294. package/web/assets/selectionBarSurface-CzUZmJDJ.js +0 -1
  295. package/web/assets/server-Ddu9f1k3.js +0 -1
  296. package/web/assets/sharePage-CNrm2xTC.js +0 -2
  297. package/web/assets/star-Dxv7XANS.js +0 -1
  298. package/web/assets/tableSurface-Bly1iCXc.js +0 -1
  299. package/web/assets/terminal-CAmmC9cV.js +0 -1
  300. package/web/assets/type-Dz6rnTvG.js +0 -1
  301. package/web/assets/undo-2-B7izWNb_.js +0 -1
  302. package/web/assets/unitOwnerAccess-D4nKS6Gg.js +0 -1
  303. package/web/assets/unitShim-2_2hhGxS.js +0 -5
  304. package/web/assets/upload-DqpRRAhG.js +0 -1
  305. package/web/assets/userSpaces-VFu4s05v.js +0 -1
  306. package/web/assets/viewportLock-3AOdDmwi.js +0 -631
  307. package/web/assets/viewportLock-djvL8fUQ.css +0 -1
  308. package/web/assets/zoom-in-Bf-eKTnH.js +0 -1
@@ -1,641 +0,0 @@
1
- import{J as V}from"./appStore-CI1_L5OS.js";import{j as l,u as U,d as a}from"./index-BOzsniE1.js";const rt=[["path",{d:"M4 11V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-1",key:"1q9hii"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M2 15h10",key:"jfw4w8"}],["path",{d:"m9 18 3-3-3-3",key:"112psh"}]],Pt=V("file-input",rt);const it=[["path",{d:"M15 12h-5",key:"r7krc0"}],["path",{d:"M15 8h-5",key:"1khuty"}],["path",{d:"M19 17V5a2 2 0 0 0-2-2H4",key:"zz82l3"}],["path",{d:"M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3",key:"1ph1d7"}]],Kt=V("scroll-text",it),ot="forsion-sketch";function Jt(t){const e=Math.max(0,...(t.match(/`+/g)??[]).map(s=>s.length)),n="`".repeat(Math.max(3,e+1));return`${n}${ot}
2
- ${t.replace(/\s+$/,"")}
3
- ${n}`}const ct=`/* The sketch document is isolated. All colors inherit Forsion's current theme. */
4
- html, body { margin: 0; padding: 0; }
5
- *, *::before, *::after { box-sizing: border-box; }
6
- body {
7
- font-family: var(--fs-font); background: var(--fs-bg); color: var(--fs-text);
8
- font-size: 14px; line-height: 1.5; padding: 16px 20px;
9
- overflow-wrap: anywhere; -webkit-font-smoothing: antialiased;
10
- }
11
- [hidden] { display: none !important; }
12
- header, figure, figcaption, footer { margin: 0; }
13
- h1, h2, h3, h4 { margin: 0 0 .5em; font-weight: 500; line-height: 1.3; text-wrap: balance; }
14
- h1 { font-size: 20px; } h2 { font-size: 18px; } h3 { font-size: 15px; } h4 { font-size: 14px; }
15
- p { margin: 0 0 .7em; } p:last-child { margin-bottom: 0; }
16
- small { font-size: 12px; color: var(--fs-muted); }
17
- a { color: var(--fs-accent); }
18
- hr { border: 0; border-top: 1px solid var(--fs-rule); margin: 16px 0; }
19
- code, pre, kbd { font-family: var(--fs-mono); font-size: 12px; }
20
- pre { overflow-x: auto; background: var(--fs-surface); border-radius: var(--fs-radius); padding: 10px; }
21
- table { border-collapse: collapse; width: 100%; font-size: 13px; font-variant-numeric: tabular-nums; }
22
- th, td { text-align: left; padding: 8px 12px 8px 0; border-bottom: 1px solid var(--fs-rule); vertical-align: top; }
23
- th { font-weight: 500; color: var(--fs-muted); }
24
- th:last-child, td:last-child { padding-right: 0; }
25
- tr:last-child td { border-bottom: 0; }
26
- svg { display: block; width: 100%; max-width: 100%; height: auto; }
27
- svg text { font-family: var(--fs-font); fill: var(--fs-text); }
28
- img, canvas { display: block; max-width: 100%; }
29
- img { height: auto; }
30
- button, input, select, textarea { font: inherit; color: inherit; max-width: 100%; }
31
- button {
32
- border: 1px solid var(--fs-border); border-radius: var(--fs-radius);
33
- background: transparent; padding: 6px 10px; cursor: pointer;
34
- }
35
- button:hover { background: var(--fs-surface); }
36
- button:disabled { opacity: .5; cursor: default; }
37
- button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
38
- outline: 2px solid var(--fs-accent); outline-offset: 2px;
39
- }
40
- input, select, textarea { accent-color: var(--fs-accent); }
41
- .fs-header { display: grid; gap: 4px; margin: 0 0 16px; }
42
- .fs-title { margin: 0; font-size: 20px; font-weight: 500; line-height: 1.3; text-wrap: balance; }
43
- .fs-eyebrow, .fs-subtitle, .fs-caption, .fs-source, .fs-label { font-size: 12px; color: var(--fs-muted); }
44
- .fs-eyebrow { font-weight: 500; }
45
- .fs-subtitle { max-width: 62ch; }
46
- .fs-plot { position: relative; min-width: 0; margin: 0; }
47
- .fs-caption, .fs-source { margin-top: 10px; }
48
- .fs-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr)); gap: 12px; margin: 4px 0 16px; }
49
- .fs-stat { display: grid; align-content: start; gap: 3px; min-width: 0; }
50
- .fs-value { font-size: 26px; font-weight: 500; line-height: 1.2; font-variant-numeric: tabular-nums; }
51
- .fs-panel { padding: 12px 14px; border-radius: var(--fs-radius); background: var(--fs-surface); }
52
- .fs-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; min-width: 0; }
53
- .fs-chip { display: inline-flex; align-items: center; padding: 3px 8px; border-radius: 999px; background: var(--fs-surface); font-size: 12px; color: var(--fs-muted); }
54
- .fs-bar-track { height: 9px; overflow: hidden; border-radius: 999px; background: var(--fs-surface); }
55
- .fs-bar-fill { height: 100%; border-radius: inherit; background: var(--fs-accent); transform-origin: left center; }
56
- .fs-controls { display: flex; flex-wrap: wrap; align-items: end; gap: 12px 16px; margin-bottom: 16px; }
57
- .fs-field { display: grid; gap: 6px; flex: 1 1 200px; min-width: 0; }
58
- .fs-field > span { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px; }
59
- .fs-field output { font-variant-numeric: tabular-nums; }
60
- .fs-input, .fs-select { width: 100%; min-width: 0; border: 1px solid var(--fs-border); border-radius: var(--fs-radius); padding: 6px 9px; background: var(--fs-surface); }
61
- .fs-range { width: 100%; min-width: 0; margin: 4px 0; }
62
- .fs-check { display: inline-flex; align-items: center; gap: 8px; }
63
- .fs-check input { margin: 0; }
64
- .fs-button[aria-pressed="true"], .fs-tabs [aria-selected="true"] { background: var(--fs-accent-soft); color: var(--fs-accent); border-color: transparent; }
65
- .fs-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 12px; }
66
- .fs-tabs button { border-color: transparent; }
67
- .fs-number { font-variant-numeric: tabular-nums; }
68
- .fs-muted { color: var(--fs-muted); }
69
- .fs-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
70
- /* Figure primitives: direct labels, quiet structure and one focus accent. */
71
- fs-chart, fs-flow { display: block; min-width: 0; }
72
- fs-chart + fs-flow, fs-flow + fs-chart, fs-chart + fs-chart { margin-top: 28px; }
73
- .fs-figure-title { margin: 0 0 18px; font-size: 16px; font-weight: 500; }
74
- .fs-chart-bars { display: grid; gap: 14px; }
75
- .fs-chart-bar-row { display: grid; grid-template-columns: minmax(72px, 1fr) minmax(0, 3fr) minmax(56px, 1fr); gap: 16px; align-items: center; }
76
- .fs-chart-bar-label { font-size: 13px; }
77
- .fs-chart-bar-value { text-align: end; font-size: 13px; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
78
- .fs-chart-track { position: relative; height: 12px; background: var(--fs-surface); border-radius: 3px; }
79
- .fs-chart-track::after { content: ''; position: absolute; left: var(--fs-zero); top: -4px; bottom: -4px; width: 1px; background: var(--fs-rule); }
80
- .fs-chart-bar { position: absolute; top: 0; height: 100%; background: var(--fs-s1); border-radius: 3px; }
81
- .fs-chart-bar--context { background: var(--fs-s2); }
82
- .fs-chart-bars--narrow .fs-chart-bar-row { grid-template-columns: minmax(0, 1fr) fit-content(50%); gap: 7px 12px; }
83
- .fs-chart-bars--narrow .fs-chart-track { grid-column: 1 / -1; grid-row: 2; }
84
- .fs-chart-bars--narrow .fs-chart-bar-value { grid-column: 2; grid-row: 1; }
85
- .fs-chart-field { position: relative; }
86
- .fs-chart-grid { fill: none; stroke: var(--fs-rule); stroke-width: 1; }
87
- .fs-chart-tick, .fs-chart-unit { font-size: 12px; fill: var(--fs-muted); }
88
- .fs-chart-line { fill: none; stroke: var(--fs-s1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
89
- .fs-chart-point { fill: var(--fs-s1); }
90
- .fs-chart-guide { fill: none; stroke: var(--fs-muted); stroke-width: 1; stroke-dasharray: 3 4; }
91
- .fs-chart-hit { position: absolute; border: 0; border-radius: 0; padding: 0; background: transparent; cursor: crosshair; touch-action: pan-y; }
92
- .fs-chart-hit:hover { background: transparent; }
93
- .fs-chart-detail { display: block; min-height: 22px; font-size: 12px; color: var(--fs-muted); font-variant-numeric: tabular-nums; }
94
- .fs-flow-steps { display: grid; grid-template-columns: repeat(var(--fs-step-count), minmax(0, 1fr)); gap: 20px; margin: 0; padding: 0; list-style: none; }
95
- .fs-flow-step { position: relative; min-width: 0; }
96
- .fs-flow-marker { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 50%; background: var(--fs-surface); color: var(--fs-muted); font-size: 11px; font-variant-numeric: tabular-nums; }
97
- .fs-flow-step[data-status="done"] .fs-flow-marker { color: var(--fs-accent); }
98
- .fs-flow-step[data-status="active"] .fs-flow-marker { background: var(--fs-accent-soft); color: var(--fs-accent); outline: 1px solid var(--fs-accent); outline-offset: 2px; }
99
- .fs-flow-step:not(:last-child)::after { content: ''; position: absolute; height: 1px; top: 15px; left: 40px; width: calc(100% - 28px); background: var(--fs-rule); }
100
- .fs-flow-step:not(:last-child)::before { content: ''; position: absolute; top: 12px; left: calc(100% + 7px); width: 6px; height: 6px; border-top: 1px solid var(--fs-muted); border-right: 1px solid var(--fs-muted); transform: rotate(45deg); }
101
- .fs-flow-content { display: grid; gap: 6px; margin-top: 12px; }
102
- .fs-flow-label { display: block; font-size: 13px; font-weight: 500; }
103
- .fs-flow-description { display: block; font-size: 12px; color: var(--fs-muted); }
104
- .fs-flow-branches { display: grid; gap: 12px; list-style: none; padding: 0 0 0 12px; margin: 8px 0 0; border-left: 1px solid var(--fs-rule); }
105
- .fs-flow-branch { position: relative; display: grid; gap: 3px; }
106
- .fs-flow-branch::before { content: ''; position: absolute; left: -12px; top: 9px; width: 7px; height: 1px; background: var(--fs-rule); }
107
- .fs-flow-steps--vertical { grid-template-columns: minmax(0, 1fr); gap: 22px; }
108
- .fs-flow-steps--vertical .fs-flow-step { display: grid; grid-template-columns: 30px minmax(0, 1fr); gap: 14px; }
109
- .fs-flow-steps--vertical .fs-flow-content { margin-top: 3px; }
110
- .fs-flow-steps--vertical .fs-flow-step:not(:last-child)::after { left: 15px; top: 39px; width: 1px; height: calc(100% - 23px); }
111
- .fs-flow-steps--vertical .fs-flow-step:not(:last-child)::before { top: calc(100% + 11px); left: 12px; transform: rotate(135deg); }
112
- /* 直播补丁(10-09):新来的部件淡入;文字原地续写不动画。 */
113
- [data-fs-new] { animation: fs-in .28s ease-out both; }
114
- @keyframes fs-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
115
- /* 统一拼装部件(10-09,对标 Intelligent UI 的固定组件库):网格 / 选项 / 按钮行 / 提示块 / 对比 / 追问选择 / 勾选清单。 */
116
- .fs-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(128px, 100%), 1fr)); gap: 12px; margin: 4px 0 12px; } /* 128:1200 宽的窗口里聊天栏卡内只有 ≈430px,要并排得下三个选项 */
117
- .fs-option { display: grid; align-content: start; gap: 6px; min-width: 0; padding: 12px 14px; border-radius: var(--fs-radius); background: var(--fs-surface); }
118
- .fs-option > h4 { margin: 0; font-size: 14px; }
119
- .fs-points { margin: 0; padding-left: 18px; font-size: 13px; display: grid; gap: 3px; }
120
- .fs-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
121
- .fs-callout { padding: 10px 14px; border-left: 2px solid var(--fs-accent); background: var(--fs-surface); border-radius: 0 var(--fs-radius) var(--fs-radius) 0; font-size: 13px; }
122
- fs-compare, fs-choice, fs-checklist { display: block; min-width: 0; }
123
- fs-compare + fs-choice, fs-choice + fs-compare, fs-checklist + fs-choice, fs-chart + fs-compare, fs-compare + fs-chart, fs-flow + fs-checklist, fs-checklist + fs-flow { margin-top: 24px; }
124
- .fs-choice-question { margin: 0 0 10px; font-size: 14px; font-weight: 500; }
125
- .fs-choice-options { display: flex; flex-wrap: wrap; gap: 8px; }
126
- .fs-checklist-items { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
127
- .fs-checklist-items .fs-check { align-items: start; }
128
- .fs-checklist-items .fs-check input { margin-top: 4px; }
129
- .fs-checklist-items .fs-check input:checked + span { color: var(--fs-muted); text-decoration: line-through; }
130
- ::selection { background: var(--fs-accent-soft); }
131
- @media(max-width:480px) {
132
- body { padding: 14px 12px; }
133
- .fs-controls { gap: 12px; }
134
- }
135
- @media(pointer:coarse) {
136
- button, .fs-check { min-height: 44px; }
137
- .fs-input, .fs-select { font-size: 16px; min-height: 44px; }
138
- .fs-range { min-height: 36px; }
139
- }
140
- @media(prefers-reduced-motion:reduce) {
141
- *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
142
- }
143
- `,lt=`/* Runs only inside the opaque-origin sandbox. No host capabilities or network. */
144
- (() => {
145
- let state = __SKETCH_INITIAL_STATE__
146
- // 授权令牌(Codex 10-09 二轮 P1):宿主只认带这个 nonce 的 ask / copy。它只活在这个闭包里 —— 运行时跑完就把自己的 script 节点删掉
147
- // (模型脚本读 outerHTML 也拿不到),模型 HTML 绕过运行时直接 postMessage 就没有它。真正的手势判定因此可以放在卡内:
148
- // navigator.userActivation 是每个 window 各自的,父文档里敲键不会传进子帧,子帧里的真点击才会让它为真。getter 在模型脚本
149
- // 跑之前就抓好,模型脚本改不了。
150
- const NONCE = '__SKETCH_NONCE__'
151
- const uaGet = typeof Navigator !== 'undefined' ? Object.getOwnPropertyDescriptor(Navigator.prototype, 'userActivation')?.get : undefined
152
- const activeGet = typeof UserActivation !== 'undefined' ? Object.getOwnPropertyDescriptor(UserActivation.prototype, 'isActive')?.get : undefined
153
- const gestureActive = () => { try { const ua = uaGet && uaGet.call(navigator); return !!(ua && activeGet && activeGet.call(ua)) } catch { return false } }
154
- const send = (msg) => parent.postMessage({ ...msg, nonce: NONCE }, '*')
155
- window.forsionSketch = Object.freeze({
156
- get state() { return state },
157
- setState(value) {
158
- const json = JSON.stringify(value)
159
- if (!json || new TextEncoder().encode(json).length > 16384) throw new Error('Sketch state exceeds 16 KiB')
160
- state = JSON.parse(json)
161
- parent.postMessage({ type: 'sketch-state', state }, '*')
162
- },
163
- // 卡内按钮回头改答案:把这句话当用户的下一条消息发出去(宿主侧再核 nonce + 焦点、限频、限长,只在对话里接)。
164
- // 手势检查在这里是**真闸**(见上):模型写的卡不能一加载 / 定时就替用户发话。
165
- ask(text) {
166
- if (!gestureActive()) throw new Error('forsionSketch.ask() must be called from a user gesture')
167
- const t = String(text ?? '').trim().slice(0, 400)
168
- if (!t) throw new Error('forsionSketch.ask() needs a non-empty text')
169
- send({ type: 'sketch-ask', text: t })
170
- },
171
- // 复制到剪贴板(沙箱帧自己没有剪贴板权限,由宿主代写;同样要用户手势)。
172
- copy(text) {
173
- if (!gestureActive()) throw new Error('forsionSketch.copy() must be called from a user gesture')
174
- const t = String(text ?? '')
175
- if (!t) return
176
- send({ type: 'sketch-copy', text: t.slice(0, 20000) })
177
- },
178
- })
179
- document.currentScript?.remove()
180
-
181
- // An href must never turn a sandbox frame into an external navigation surface.
182
- document.addEventListener('click', (event) => {
183
- if (event.target.closest?.('a[href]')) event.preventDefault()
184
- }, true)
185
- document.addEventListener('submit', (event) => event.preventDefault(), true)
186
-
187
- // 直播补丁(10-09,对标 ChatGPT Intelligent UI 的流式组件):宿主把最新 html 发进来,这里**原地**打补丁 —— 不换 srcdoc、不重载。
188
- // 同位置同标签的元素保留(只同步属性、递归子节点),文字节点原地续写,新节点标 data-fs-new 淡入;自定义元素(fs-*)内容一变整个换掉
189
- // (它们从 JSON 子节点取数据,只在接入时解析)。终稿(sketch-final)再把惰性的 script 节点换成会执行的,并补发 DOMContentLoaded / load,
190
- // 让「等 DOM 就绪再初始化」的两种写法都能跑。
191
- function syncAttrs(live, next) {
192
- for (const a of [...live.attributes]) if (a.name !== 'data-fs-new' && !next.hasAttribute(a.name)) live.removeAttribute(a.name)
193
- for (const a of [...next.attributes]) if (live.getAttribute(a.name) !== a.value) live.setAttribute(a.name, a.value)
194
- }
195
- const markNew = (n) => {
196
- if (n.nodeType !== 1) return
197
- n.setAttribute('data-fs-new', '')
198
- n.addEventListener('animationend', () => n.removeAttribute('data-fs-new'), { once: true })
199
- }
200
- function morph(live, next) {
201
- if (live.nodeType === 1 && next.nodeType === 1) syncAttrs(live, next)
202
- const a = [...live.childNodes], b = [...next.childNodes]
203
- for (let i = 0; i < Math.max(a.length, b.length); i++) {
204
- const x = a[i], y = b[i]
205
- if (!y) { x.remove(); continue }
206
- if (!x) { const n = document.importNode(y, true); markNew(n); live.appendChild(n); continue }
207
- if (x.nodeType === 3 && y.nodeType === 3) { if (x.nodeValue !== y.nodeValue) x.nodeValue = y.nodeValue; continue }
208
- const sameTag = x.nodeType === 1 && y.nodeType === 1 && x.tagName === y.tagName
209
- // 自定义元素渲染后 innerHTML 已是画好的 DOM,比的是它接入时记下的原始源码(_fsSrc),不然每一拍都会被换掉重画。
210
- if (sameTag && x.tagName.includes('-')) {
211
- if ((x._fsSrc ?? x.innerHTML) !== y.innerHTML) { const n = document.importNode(y, true); markNew(n); x.replaceWith(n) }
212
- else syncAttrs(x, y)
213
- continue
214
- }
215
- if (sameTag) { morph(x, y); continue }
216
- const n = document.importNode(y, true); markNew(n); x.replaceWith(n)
217
- }
218
- }
219
- // 会执行的 script type(HTML 标准的 JavaScript MIME 类型表 + module);其余(application/json、importmap …)是数据,原样留着
220
- const JS_TYPES = /^(?:module|(?:text|application)\\/(?:x-)?(?:ecma|java)script|text\\/(?:javascript1\\.[0-5]|jscript|livescript))$/
221
- function applyHtml(html, final) {
222
- const t = document.createElement('template')
223
- t.innerHTML = html
224
- morph(document.body, t.content)
225
- if (final) {
226
- const pending = [] // module 脚本是异步执行的,等它们跑完再发就绪事件(Codex 10-09 P2)
227
- for (const s of [...document.body.querySelectorAll('script')]) {
228
- const type = (s.getAttribute('type') || '').trim().toLowerCase()
229
- if (type && !JS_TYPES.test(type)) continue
230
- const n = document.createElement('script')
231
- for (const attr of [...s.attributes]) n.setAttribute(attr.name, attr.value)
232
- n.textContent = s.textContent
233
- if (type === 'module') pending.push(new Promise((r) => { n.addEventListener('load', r, { once: true }); n.addEventListener('error', r, { once: true }) }))
234
- s.replaceWith(n)
235
- }
236
- const ready = () => { document.dispatchEvent(new Event('DOMContentLoaded')); window.dispatchEvent(new Event('load')); measure() }
237
- if (pending.length) Promise.all(pending).then(ready)
238
- else ready()
239
- }
240
- measure()
241
- }
242
-
243
- window.addEventListener('message', (event) => {
244
- if (event.source !== parent) return
245
- const data = event.data
246
- if (!data) return
247
- if (data.type === 'sketch-draft' || data.type === 'sketch-final') { applyHtml(String(data.html ?? ''), data.type === 'sketch-final'); return }
248
- if (data.type !== 'sketch-theme' || !data.vars) return
249
- for (const [key, value] of Object.entries(data.vars)) {
250
- if (key.startsWith('--fs-')) document.documentElement.style.setProperty(key, String(value))
251
- else if (key === 'color-scheme') document.documentElement.style.colorScheme = String(value)
252
- }
253
- window.dispatchEvent(new Event('forsion:themechange'))
254
- })
255
-
256
- let lastHeight = 0
257
- function measure() {
258
- const height = Math.ceil(document.body?.getBoundingClientRect().height || 0)
259
- if (height && height !== lastHeight) {
260
- lastHeight = height
261
- parent.postMessage({ type: 'sketch-height', height }, '*')
262
- }
263
- }
264
-
265
- function selectTab(tab) {
266
- const list = tab.closest('.fs-tabs[role="tablist"]')
267
- if (!list || tab.disabled || tab.getAttribute('aria-disabled') === 'true') return
268
- for (const peer of list.querySelectorAll('[role="tab"]')) {
269
- const selected = peer === tab
270
- peer.setAttribute('aria-selected', String(selected))
271
- const panel = document.getElementById(peer.getAttribute('aria-controls'))
272
- if (panel?.getAttribute('role') === 'tabpanel') panel.hidden = !selected
273
- }
274
- }
275
- document.addEventListener('click', (event) => {
276
- const tab = event.target.closest?.('.fs-tabs [role="tab"]')
277
- if (tab) selectTab(tab)
278
- })
279
- document.addEventListener('keydown', (event) => {
280
- const tab = event.target.closest?.('.fs-tabs [role="tab"]')
281
- if (!tab || !['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return
282
- const tabs = [...tab.closest('.fs-tabs').querySelectorAll('[role="tab"]')]
283
- .filter((node) => !node.disabled && node.getAttribute('aria-disabled') !== 'true')
284
- const index = tabs.indexOf(tab)
285
- const next = event.key === 'Home' ? 0 : event.key === 'End' ? tabs.length - 1
286
- : (index + (event.key === 'ArrowRight' ? 1 : -1) + tabs.length) % tabs.length
287
- event.preventDefault()
288
- tabs[next]?.focus()
289
- if (tabs[next]) selectTab(tabs[next])
290
- })
291
-
292
- function ready() {
293
- window.__fsLoadedAt = Date.now() // 台架用:整张卡只加载一次(草稿 → 终稿不重载)
294
- if (window.ResizeObserver) new ResizeObserver(measure).observe(document.body)
295
- measure()
296
- }
297
- // once:终稿(sketch-final)会补发一次合成的 DOMContentLoaded 给模型脚本,运行时自己的就绪只跑一次
298
- if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', ready, { once: true })
299
- else ready()
300
- window.addEventListener('load', measure)
301
- })()
302
- `,dt=`/* Small, offline figure primitives. Text and data are never interpreted as HTML. */
303
- (() => {
304
- const svgNS = 'http://www.w3.org/2000/svg'
305
- const number = (value) => new Intl.NumberFormat(undefined, {
306
- maximumSignificantDigits: 6, notation: Math.abs(value) >= 1e15 || (value !== 0 && Math.abs(value) < 1e-4) ? 'scientific' : Math.abs(value) >= 1e6 ? 'compact' : 'standard',
307
- }).format(value)
308
- const node = (tag, cls, text) => {
309
- const el = document.createElement(tag)
310
- if (cls) el.className = cls
311
- if (text !== undefined) el.textContent = String(text)
312
- return el
313
- }
314
- const mark = (tag, attrs, text) => {
315
- const el = document.createElementNS(svgNS, tag)
316
- for (const [key, value] of Object.entries(attrs)) el.setAttribute(key, String(value))
317
- if (text !== undefined) el.textContent = String(text)
318
- return el
319
- }
320
- function heading(root, data) {
321
- if (data.title) root.append(node('h3', 'fs-figure-title', data.title))
322
- }
323
- function caption(root, data) {
324
- if (data.caption) root.append(node('p', 'fs-caption', data.caption))
325
- }
326
- class Figure extends HTMLElement {
327
- connectedCallback() {
328
- queueMicrotask(() => {
329
- if (!this.isConnected) return
330
- if (!this.figureData) {
331
- this._fsSrc = this.innerHTML // 直播补丁(sketchRuntime morph)拿它和新来的源码比,渲染后 innerHTML 就不是源码了
332
- try { this.figureData = JSON.parse(this.querySelector('script[type="application/json"]')?.textContent || '{}') }
333
- catch { this.figureData = {} }
334
- }
335
- this.render()
336
- this.observer?.disconnect()
337
- if (!window.ResizeObserver) return
338
- this.observer = new ResizeObserver(() => {
339
- const width = Math.round(this.clientWidth)
340
- if (width && width !== this.lastWidth) { this.lastWidth = width; this.render() }
341
- })
342
- this.observer.observe(this)
343
- })
344
- }
345
- disconnectedCallback() { this.observer?.disconnect() }
346
- setData(data) { this.figureData = data; if (this.isConnected) this.render() }
347
- error() {
348
- // No guessed labels or fabricated zeroes when the input is invalid.
349
- const error = node('p', 'fs-caption', this.figureData?.emptyLabel || '—')
350
- error.setAttribute('role', 'alert')
351
- this.replaceChildren(error)
352
- }
353
- }
354
-
355
- class Chart extends Figure {
356
- render() {
357
- const data = this.figureData
358
- if (!['bar', 'line'].includes(this.getAttribute('type') || 'bar') ||
359
- !data || !Array.isArray(data.data) || !data.data.length || data.data.length > 100 ||
360
- data.data.some((item) => typeof item?.label !== 'string' || typeof item.value !== 'number' || !Number.isFinite(item.value))) {
361
- this.error(); return
362
- }
363
- this.replaceChildren()
364
- const root = node('figure', 'fs-chart-figure')
365
- heading(root, data)
366
- this.append(root)
367
- if (this.getAttribute('type') === 'line') this.line(root, data)
368
- else this.bars(root, data)
369
- caption(root, data)
370
- }
371
- bars(root, data) {
372
- // A zero baseline also handles negative-only and mixed-sign comparisons honestly.
373
- const magnitude = Math.max(1, ...data.data.map((item) => Math.abs(item.value)))
374
- const low = Math.min(0, ...data.data.map((item) => item.value / magnitude))
375
- const high = Math.max(0, ...data.data.map((item) => item.value / magnitude))
376
- const span = high - low || 1
377
- const zero = -low / span * 100
378
- const list = node('div', 'fs-chart-bars')
379
- list.setAttribute('role', 'list')
380
- list.setAttribute('aria-label', String(data.title || data.unit || data.data.map((item) => item.label).join(', ')))
381
- const narrow = this.clientWidth < 440
382
- list.classList.toggle('fs-chart-bars--narrow', narrow)
383
- for (const [index, item] of data.data.entries()) {
384
- const row = node('div', 'fs-chart-bar-row')
385
- row.setAttribute('role', 'listitem')
386
- const label = node('span', 'fs-chart-bar-label', item.label)
387
- const value = node('span', 'fs-chart-bar-value', number(item.value) + (data.unit ? ' ' + data.unit : ''))
388
- const track = node('span', 'fs-chart-track')
389
- track.setAttribute('aria-hidden', 'true')
390
- const bar = node('span', 'fs-chart-bar')
391
- bar.style.left = Math.min(zero, (item.value / magnitude - low) / span * 100) + '%'
392
- bar.style.width = Math.abs(item.value / magnitude) / span * 100 + '%'
393
- if (Number.isInteger(data.highlight) && data.highlight !== index) bar.classList.add('fs-chart-bar--context')
394
- track.style.setProperty('--fs-zero', zero + '%')
395
- track.append(bar)
396
- row.append(label, track, value)
397
- list.append(row)
398
- }
399
- root.append(list)
400
- }
401
- line(root, data) {
402
- const width = Math.max(1, this.clientWidth)
403
- const height = 238
404
- const values = data.data.map((item) => item.value)
405
- const maxAbs = Math.max(...values.map(Math.abs))
406
- const magnitude = maxAbs ? Math.pow(10, Math.floor(Math.log10(maxAbs))) || Number.MIN_VALUE : 1
407
- const min = Math.min(...values.map((v) => v / magnitude)), max = Math.max(...values.map((v) => v / magnitude))
408
- const pad = (max - min || Math.abs(max) || 1) * .12
409
- const limit = Number.MAX_VALUE / magnitude
410
- const paddedLow = min >= 0 ? Math.max(0, min - pad) : min - pad
411
- const paddedHigh = max <= 0 ? Math.min(0, max + pad) : max + pad
412
- const roughStep = (paddedHigh - paddedLow) / 4 || .25
413
- const power = Math.pow(10, Math.floor(Math.log10(roughStep)))
414
- const step = ([1, 2, 5, 10].find((factor) => factor >= roughStep / power) || 10) * power
415
- const low = Math.max(-limit, Math.floor(paddedLow / step) * step)
416
- const high = Math.min(limit, Math.ceil(paddedHigh / step) * step) || step
417
- const ticks = []
418
- for (let tick = Math.ceil(low / step) * step; tick <= high + step * 1e-8; tick += step) {
419
- ticks.push(Number((tick * magnitude).toPrecision(12)))
420
- if (ticks.length > 8) break
421
- }
422
- const canvas = document.createElement('canvas')
423
- const context = canvas.getContext('2d')
424
- if (context) context.font = '12px ' + getComputedStyle(this).fontFamily
425
- const left = Math.min(width * .35, Math.max(48, ...ticks.map((v) => (context?.measureText(number(v)).width || 36) + 14)))
426
- const right = Math.max(left + 1, width - 8), top = 28, bottom = height - 32
427
- const x = (i) => left + (right - left) * (values.length === 1 ? .5 : i / (values.length - 1))
428
- const y = (value) => bottom - (value / magnitude - low) / (high - low) * (bottom - top)
429
- const field = node('div', 'fs-chart-field')
430
- const svg = mark('svg', { viewBox: \`0 0 \${width} \${height}\`, role: 'img', 'aria-label': String(data.title || data.data.map((item) => item.label).join(', ')) })
431
- svg.append(mark('title', {}, data.data.map((v) => \`\${v.label}: \${number(v.value)} \${data.unit || ''}\`).join('; ')))
432
- if (data.unit) svg.append(mark('text', { x: left, y: 14, class: 'fs-chart-unit' }, data.unit))
433
- for (const tick of ticks) {
434
- svg.append(mark('path', { d: \`M\${left} \${y(tick)}H\${right}\`, class: 'fs-chart-grid' }))
435
- svg.append(mark('text', { x: left - 10, y: y(tick) + 4, 'text-anchor': 'end', class: 'fs-chart-tick' }, number(tick)))
436
- }
437
- const count = Math.min(values.length, width < 440 ? 3 : 5)
438
- let previousRight = -Infinity
439
- for (let i = 0; i < count; i++) {
440
- const index = count === 1 ? 0 : Math.round(i * (values.length - 1) / (count - 1))
441
- const label = data.data[index].label
442
- const size = context?.measureText(label).width || label.length * 8
443
- const px = x(index)
444
- const labelLeft = i === 0 ? px : i === count - 1 ? px - size : px - size / 2
445
- if (labelLeft < previousRight + 8 || size > right - left) continue
446
- previousRight = labelLeft + size
447
- svg.append(mark('text', { x: px, y: height - 9, 'text-anchor': i === 0 ? 'start' : i === count - 1 ? 'end' : 'middle', class: 'fs-chart-tick' }, label))
448
- }
449
- const path = values.map((value, i) => \`\${i ? 'L' : 'M'}\${x(i)} \${y(value)}\`).join(' ')
450
- svg.append(mark('path', { d: path, class: 'fs-chart-line' }))
451
- for (const [i, value] of values.entries()) svg.append(mark('circle', { cx: x(i), cy: y(value), r: 2.5, class: 'fs-chart-point' }))
452
- const guide = mark('path', { class: 'fs-chart-guide', visibility: 'hidden' })
453
- const dot = mark('circle', { r: 4, class: 'fs-chart-point', visibility: 'hidden' })
454
- svg.append(guide, dot)
455
- const detail = node('output', 'fs-chart-detail')
456
- const hit = node('button', 'fs-chart-hit')
457
- hit.type = 'button'
458
- hit.setAttribute('aria-label', String(data.inspectLabel || data.title || data.data.map((item) => item.label).join(', ')))
459
- hit.style.left = left + 'px'; hit.style.top = top + 'px'
460
- hit.style.width = (right - left) + 'px'; hit.style.height = (bottom - top) + 'px'
461
- let current = 0
462
- const show = (position) => {
463
- current = Math.max(0, Math.min(values.length - 1, position))
464
- const a = Math.floor(current), b = Math.ceil(current), t = current - a
465
- const value = (values[a] / magnitude * (1 - t) + values[b] / magnitude * t) * magnitude
466
- const px = x(current)
467
- guide.setAttribute('d', \`M\${px} \${top}V\${bottom}\`)
468
- dot.setAttribute('cx', px); dot.setAttribute('cy', y(value))
469
- guide.setAttribute('visibility', 'visible'); dot.setAttribute('visibility', 'visible')
470
- const label = a === b ? data.data[a].label : \`\${data.data[a].label} – \${data.data[b].label}\`
471
- detail.textContent = \`\${label} · \${number(value)} \${data.unit || ''}\`
472
- }
473
- hit.addEventListener('pointermove', (event) => {
474
- detail.removeAttribute('aria-live')
475
- const bounds = hit.getBoundingClientRect()
476
- show((event.clientX - bounds.left) / bounds.width * (values.length - 1))
477
- })
478
- hit.addEventListener('focus', () => show(Math.round(current)))
479
- hit.addEventListener('click', (event) => {
480
- if (!event.detail) { show(Math.round(current)); return }
481
- const bounds = hit.getBoundingClientRect()
482
- show((event.clientX - bounds.left) / bounds.width * (values.length - 1))
483
- })
484
- hit.addEventListener('keydown', (event) => {
485
- if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return
486
- event.preventDefault()
487
- detail.setAttribute('aria-live', 'polite')
488
- show(event.key === 'Home' ? 0 : event.key === 'End' ? values.length - 1 : Math.round(current) + (event.key === 'ArrowRight' ? 1 : -1))
489
- })
490
- field.append(svg, hit)
491
- root.append(field, detail)
492
- }
493
- }
494
-
495
- class Flow extends Figure {
496
- render() {
497
- const data = this.figureData
498
- if (!data || !Array.isArray(data.steps) || !data.steps.length || data.steps.length > 12 ||
499
- data.steps.some((step) => !step || typeof step.label !== 'string' ||
500
- (step.branches !== undefined && (!Array.isArray(step.branches) || step.branches.length > 8 ||
501
- step.branches.some((branch) => !branch || typeof branch.label !== 'string'))))) { this.error(); return }
502
- this.replaceChildren()
503
- const root = node('figure', 'fs-flow-figure')
504
- heading(root, data)
505
- const list = node('ol', 'fs-flow-steps')
506
- list.classList.toggle('fs-flow-steps--vertical', this.clientWidth < data.steps.length * 145)
507
- list.style.setProperty('--fs-step-count', data.steps.length)
508
- for (const [index, step] of data.steps.entries()) {
509
- const item = node('li', 'fs-flow-step')
510
- const status = ['done', 'active'].includes(step.status) ? step.status : 'pending'
511
- item.dataset.status = status
512
- if (status === 'active') item.setAttribute('aria-current', 'step')
513
- const marker = node('span', 'fs-flow-marker', String(index + 1).padStart(2, '0'))
514
- marker.setAttribute('aria-hidden', 'true')
515
- const content = node('div', 'fs-flow-content')
516
- content.append(node('span', 'fs-flow-label', step.label))
517
- if (step.detail) content.append(node('span', 'fs-flow-description', step.detail))
518
- if (Array.isArray(step.branches) && step.branches.length) {
519
- const branches = node('ul', 'fs-flow-branches')
520
- for (const branch of step.branches) {
521
- const branchNode = node('li', 'fs-flow-branch')
522
- branchNode.append(node('span', 'fs-flow-label', branch.label || ''))
523
- if (branch.detail) branchNode.append(node('span', 'fs-flow-description', branch.detail))
524
- branches.append(branchNode)
525
- }
526
- content.append(branches)
527
- }
528
- item.append(marker, content); list.append(item)
529
- }
530
- root.append(list); caption(root, data); this.append(root)
531
- }
532
- }
533
-
534
- // 10-09(对标 ChatGPT Intelligent UI「只能拼固定组件库」):统一的拼装部件,模型只给 JSON,外观由宿主定。
535
- const askOf = (text) => { try { window.forsionSketch.ask(String(text)) } catch (e) { console.warn(e) } }
536
- const button = (label, onClick) => { const b = node('button', 'fs-button', label); b.type = 'button'; b.addEventListener('click', onClick); return b }
537
-
538
- /** <fs-compare>:并排选项 {title?, caption?, options:[{label, summary?, points?:string[], ask?:{label?, text}}]}(2–6 项)。 */
539
- class Compare extends Figure {
540
- render() {
541
- const d = this.figureData
542
- const ok = d && Array.isArray(d.options) && d.options.length >= 2 && d.options.length <= 6 &&
543
- d.options.every((o) => o && typeof o.label === 'string' &&
544
- (o.points === undefined || (Array.isArray(o.points) && o.points.length <= 8 && o.points.every((p) => typeof p === 'string'))) &&
545
- (o.ask === undefined || (o.ask && typeof o.ask.text === 'string')))
546
- if (!ok) { this.error(); return }
547
- this.replaceChildren()
548
- const root = node('div', 'fs-compare')
549
- heading(root, d)
550
- const grid = node('div', 'fs-grid')
551
- for (const o of d.options) {
552
- const card = node('section', 'fs-option')
553
- card.append(node('h4', '', o.label))
554
- if (typeof o.summary === 'string' && o.summary) card.append(node('p', 'fs-muted', o.summary))
555
- if (Array.isArray(o.points) && o.points.length) { const ul = node('ul', 'fs-points'); for (const p of o.points) ul.append(node('li', '', p)); card.append(ul) }
556
- if (o.ask) { const act = node('div', 'fs-actions'); act.append(button(o.ask.label || o.label, () => askOf(o.ask.text))); card.append(act) }
557
- grid.append(card)
558
- }
559
- root.append(grid); caption(root, d); this.append(root)
560
- }
561
- }
562
-
563
- /** <fs-choice>:追问选择题 {question, options:[{label, ask?}], multiple?, ask?("{choices}" 占位), submitLabel?, caption?}。
564
- * 单选点了就把 ask(缺省 label)当用户消息发出;多选勾完按提交,把 ask 模板里的 {choices} 换成所选。 */
565
- class Choice extends Figure {
566
- render() {
567
- const d = this.figureData
568
- const ok = d && typeof d.question === 'string' && Array.isArray(d.options) && d.options.length >= 2 && d.options.length <= 8 &&
569
- d.options.every((o) => o && typeof o.label === 'string' && (o.ask === undefined || typeof o.ask === 'string'))
570
- if (!ok) { this.error(); return }
571
- this.picked ||= new Set() // 宽度变化重绘时保住已勾的
572
- for (const i of [...this.picked]) if (i >= d.options.length) this.picked.delete(i) // setData 换了更短的选项表:越界的勾作废(Codex 10-09)
573
- this.replaceChildren()
574
- const root = node('div', 'fs-choice')
575
- root.setAttribute('role', 'group')
576
- root.append(node('p', 'fs-choice-question', d.question))
577
- const opts = node('div', 'fs-choice-options')
578
- if (d.multiple) {
579
- for (const [i, o] of d.options.entries()) {
580
- const l = node('label', 'fs-check'); const c = node('input'); c.type = 'checkbox'; c.checked = this.picked.has(i)
581
- c.addEventListener('change', () => { if (c.checked) this.picked.add(i); else this.picked.delete(i) })
582
- l.append(c, node('span', '', o.label)); opts.append(l)
583
- }
584
- const act = node('div', 'fs-actions')
585
- act.append(button(d.submitLabel || 'OK', () => {
586
- const chosen = [...this.picked].sort((x, y) => x - y).map((i) => d.options[i]?.label).filter(Boolean)
587
- if (chosen.length) askOf(String(d.ask || '{choices}').replace('{choices}', chosen.join(', ')))
588
- }))
589
- root.append(opts, act)
590
- } else {
591
- for (const o of d.options) opts.append(button(o.label, () => askOf(typeof o.ask === 'string' ? o.ask : o.label)))
592
- root.append(opts)
593
- }
594
- caption(root, d); this.append(root)
595
- }
596
- }
597
-
598
- /** <fs-checklist>:勾选清单 {title?, caption?, items:[{label, detail?}]}(1–40 项);勾选状态经 forsionSketch.setState 存在本机
599
- * (键 checklists[<元素 id 或 'checklist'>]),重开这张卡还在。 */
600
- class Checklist extends Figure {
601
- render() {
602
- const d = this.figureData
603
- const ok = d && Array.isArray(d.items) && d.items.length >= 1 && d.items.length <= 40 &&
604
- d.items.every((it) => it && typeof it.label === 'string' && (it.detail === undefined || typeof it.detail === 'string'))
605
- if (!ok) { this.error(); return }
606
- const key = this.id || 'checklist'
607
- const st = window.forsionSketch?.state
608
- const saved = st && typeof st === 'object' && st.checklists ? st.checklists[key] : undefined
609
- const done = new Set(Array.isArray(saved) ? saved.filter((i) => Number.isInteger(i)) : [])
610
- this.replaceChildren()
611
- const root = node('div', 'fs-checklist')
612
- heading(root, d)
613
- const ul = node('ul', 'fs-checklist-items')
614
- for (const [i, it] of d.items.entries()) {
615
- const li = node('li'); const l = node('label', 'fs-check'); const c = node('input'); c.type = 'checkbox'; c.checked = done.has(i)
616
- c.addEventListener('change', () => {
617
- if (c.checked) done.add(i); else done.delete(i)
618
- const cur = window.forsionSketch.state
619
- const base = cur && typeof cur === 'object' && !Array.isArray(cur) ? cur : {}
620
- try { window.forsionSketch.setState({ ...base, checklists: { ...(base.checklists || {}), [key]: [...done].sort((x, y) => x - y) } }) } catch (e) { console.warn(e) }
621
- })
622
- const text = node('span', '', it.label)
623
- if (it.detail) text.append(node('small', 'fs-muted', ' ' + it.detail))
624
- l.append(c, text); li.append(l); ul.append(li)
625
- }
626
- root.append(ul); caption(root, d); this.append(root)
627
- }
628
- }
629
-
630
- function register() {
631
- if (!customElements.get('fs-chart')) customElements.define('fs-chart', Chart)
632
- if (!customElements.get('fs-flow')) customElements.define('fs-flow', Flow)
633
- if (!customElements.get('fs-compare')) customElements.define('fs-compare', Compare)
634
- if (!customElements.get('fs-choice')) customElements.define('fs-choice', Choice)
635
- if (!customElements.get('fs-checklist')) customElements.define('fs-checklist', Checklist)
636
- }
637
- if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', register)
638
- else register()
639
- })()
640
- `,q=16384,G="forsion_sketch_state_v1",M=48;function S(t){try{const e=JSON.stringify(t);return e&&new TextEncoder().encode(e).length<=q?e:void 0}catch{return}}function ft(t,e,n){let s=2166136261;for(let i=0;i<n.length;i++)s=Math.imul(s^n.charCodeAt(i),16777619);return JSON.stringify([t,e,n.length,s>>>0])}function W(t){const e=t.getItem(G);if(!e||e.length>q*(M+4))return[];let n;try{n=JSON.parse(e)}catch{return[]}return Array.isArray(n)?n.filter(s=>!!s&&typeof s.key=="string"&&s.key.length<2048&&S(s.state)!==void 0).slice(-M):[]}function pt(t){try{return W(localStorage).find(e=>e.key===t)?.state??null}catch{return null}}function ut(t,e){const n=S(e);if(!(!n||t.length>=2048))try{const s=W(localStorage).filter(i=>i.key!==t);s.push({key:t,state:JSON.parse(n)}),localStorage.setItem(G,JSON.stringify(s.slice(-M)))}catch{}}const ht="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:; media-src data: blob:; font-src data:",mt="allow-scripts",P=40,gt=2400,bt=220,vt={"--fs-bg":"transparent"},xt=[["--fs-surface","--overlay-subtle"],["--fs-text","--text"],["--fs-muted","--text-muted"],["--fs-faint","--text-faint"],["--fs-border","--border"],["--fs-rule","--overlay-medium"],["--fs-accent","--accent-ink"],["--fs-accent-soft","--accent-light"],["--fs-green","--green"],["--fs-danger","--danger"],["--fs-radius","--radius-sm"],["--fs-font","--font-ui"],["--fs-mono","--font-mono"]];function B(t){return String(t).replace(/[<>]/g,"").trim()}function K(t){const e=getComputedStyle(t),n={...vt};for(const[s,i]of xt){const c=B(e.getPropertyValue(i));c&&(n[s]=c)}return n["color-scheme"]=document.documentElement.getAttribute("data-mode")==="dark"?"dark":"light",n}const w=new Set;let g=null;function yt(t){return w.add(t),!g&&typeof MutationObserver<"u"&&(g=new MutationObserver(()=>{for(const e of w)e()}),g.observe(document.documentElement,{attributes:!0,attributeFilter:["data-theme","data-skin","data-bg","data-mode","data-flat","data-glass","class"]})),()=>{w.delete(t),!w.size&&g&&(g.disconnect(),g=null)}}const kt=":root{--fs-s1:var(--fs-accent);--fs-s2:color-mix(in srgb,var(--fs-text) 62%,transparent);--fs-s3:color-mix(in srgb,var(--fs-text) 42%,transparent);--fs-s4:color-mix(in srgb,var(--fs-text) 26%,transparent);--fs-s5:color-mix(in srgb,var(--fs-text) 14%,transparent)}";function wt(t){const e=Object.entries(t).map(([n,s])=>`${n.replace(/[^a-z-]/gi,"")}:${B(s)}`).join(";");return e?`:root{${e}}`:""}function St(t,e={},n=null,s=""){const i=(S(n)??"null").replace(/</g,"\\u003c").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029"),c=lt.replace("__SKETCH_INITIAL_STATE__",()=>i).replace("__SKETCH_NONCE__",()=>s.replace(/[^A-Za-z0-9-]/g,""));return`<!doctype html><html><head><meta http-equiv="Content-Security-Policy" content="${ht}"><meta name="viewport" content="width=device-width, initial-scale=1"><style>${wt(e)}${kt}${ct}</style><script>${c};
641
- ${dt}<\/script></head><body>${t}</body></html>`}const X=`(?![^>]*\\stype\\s*=\\s*["']?application/json\\b)`,At=new RegExp(`<script\\b${X}[^>]*>[\\s\\S]*?<\/script\\s*>`,"gi"),Et=new RegExp(`<script\\b${X}[^>]*>[\\s\\S]*$`,"i"),Mt=/<script\b[^>]*$/i,Tt=/<[a-zA-Z][^>]*(?:>|$)/g,Nt=/\son[a-z]+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi,Ct=/<(fs-[a-z]+)\b(?![\s\S]*<\/\1\s*>)[\s\S]*$/i;function J(t){return t.replace(At,"").replace(Et,"").replace(Mt,"").replace(Ct,"").replace(Tt,e=>e.replace(Nt,""))}const _t=400,Lt=1500,Rt=2e4,zt=150;function Ot(){try{const t=window.Capacitor;return!!(t&&typeof t.isNativePlatform=="function"&&t.isNativePlatform())}catch{return!1}}function Ht(t){return!t||document.activeElement!==t?!1:navigator.userActivation?.isActive===!0}const It=()=>crypto.randomUUID?crypto.randomUUID():Array.from(crypto.getRandomValues(new Uint8Array(16)),t=>t.toString(16).padStart(2,"0")).join(""),$t=({item:t,actions:e,stateScope:n,onAsk:s})=>{const{t:i}=U(),c=a.useMemo(()=>n&&!t.draft?ft(n,t.callId,t.html):null,[n,t.callId,t.html,t.draft]),u=a.useRef(s);u.current=s;const x=a.useRef(!!t.draft);x.current=!!t.draft;const T=a.useRef(0),Y=a.useRef(t.draft?J(t.html):t.html),Z=a.useRef(c?pt(c):null),N=a.useRef(It()),y=a.useRef(null),C=a.useRef(null),h=a.useRef(null),[_,Q]=a.useState(t.draft?P:bt),[b,tt]=a.useState(!1),[L,et]=a.useState(!1),[k,nt]=a.useState(null);a.useLayoutEffect(()=>{y.current&&nt(K(y.current))},[]),a.useEffect(()=>yt(()=>{const r=y.current,d=h.current?.contentWindow;r&&d&&d.postMessage({type:"sketch-theme",vars:K(r)},"*")}),[]);const A=a.useRef(!1),E=a.useRef(!1),v=a.useRef(null),m=a.useRef(void 0),R=r=>{h.current?.contentWindow?.postMessage(r,"*")},z=()=>{if(m.current=void 0,!A.current)return;const r=v.current;v.current=null,r!==null&&x.current&&!E.current&&R({type:"sketch-draft",html:r})},O=()=>{!A.current||E.current||(E.current=!0,clearTimeout(m.current),m.current=void 0,v.current=null,R({type:"sketch-final",html:t.html}))},H=a.useRef(!!t.draft);a.useEffect(()=>{t.draft?(v.current=J(t.html),m.current||(m.current=setTimeout(z,zt))):H.current&&O()},[t.html,t.draft]),a.useEffect(()=>()=>clearTimeout(m.current),[]);const at=()=>{A.current=!0,!x.current&&H.current?O():v.current!==null&&z()};a.useEffect(()=>{let r,d;const p=()=>{c&&r!==void 0&&ut(c,JSON.parse(r)),r=void 0,d=void 0},$=j=>{if(!h.current||j.source!==h.current.contentWindow)return;const o=j.data;if(o?.type==="sketch-state"&&c){const f=S(o.state);f!==void 0&&(r=f,d||(d=setTimeout(p,200)))}o&&o.type==="sketch-height"&&Number.isFinite(Number(o.height))&&Q(Math.min(gt,Math.max(P,Math.ceil(Number(o.height)))));const D=o&&o.nonce===N.current&&!x.current&&Ht(h.current);if(D&&o.type==="sketch-ask"&&typeof o.text=="string"&&u.current){const f=Date.now(),F=o.text.trim().slice(0,_t);F&&f-T.current>=Lt&&(T.current=f,u.current(F))}if(D&&o.type==="sketch-copy"&&typeof o.text=="string"){const f=o.text.slice(0,Rt);f&&navigator.clipboard?.writeText(f).catch(()=>{})}};return window.addEventListener("message",$),window.addEventListener("pagehide",p),()=>{window.removeEventListener("message",$),window.removeEventListener("pagehide",p),clearTimeout(d),p()}},[c]),a.useEffect(()=>{const r=C.current;if(!r||b)return;const d=()=>et(r.scrollHeight>r.clientHeight+1);d();const p=new ResizeObserver(d);return p.observe(r),()=>p.disconnect()},[_,b]);const st=a.useMemo(()=>k?St(Y.current,k,Z.current,N.current):"",[k]),I=t.draft?void 0:e;return l.jsxs("div",{className:"sketch-card",ref:y,"data-sketch-call-id":t.callId,"data-sketch-draft":t.draft?"":void 0,children:[(t.title||I)&&l.jsxs("div",{className:"sketch-card-head",children:[t.title&&l.jsx("div",{className:"sketch-card-title",children:t.title}),I?.(t)]}),l.jsx("div",{ref:C,className:`sketch-clip${b?" open":""}${L&&!b?" faded":""}`,children:k&&l.jsx("iframe",{ref:h,className:"sketch-frame",sandbox:mt,srcDoc:st,style:{height:_},title:t.title||"sketch",onLoad:at})}),L&&l.jsx("button",{type:"button",className:"sketch-card-toggle",onClick:()=>tt(r=>!r),children:i(b?"sketch.collapse":"sketch.expand")})]})},jt=({item:t})=>{const{t:e}=U();return l.jsxs("div",{className:"sketch-card","data-sketch-call-id":t.callId,children:[t.title&&l.jsx("div",{className:"sketch-card-title",children:t.title}),l.jsx("div",{className:"sketch-card-note",children:e("sketch.mobileUnavailable")})]})},Vt=({items:t,actions:e,stateScope:n,onAsk:s})=>{const i=Ot(),c=i?jt:$t;return l.jsx(l.Fragment,{children:t.map(u=>l.jsx(c,{item:u,actions:i?void 0:e,stateScope:n,onAsk:i?void 0:s},`${n||""}:${u.callId}`))})};export{Pt as F,Kt as S,Vt as a,ot as b,Jt as s};