@cardstack/boxel-cli 0.11.0-unstable.1 → 0.11.0-unstable.3

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 (177) hide show
  1. package/bundled-realms/pretui/components/agent-mark.gts +98 -0
  2. package/bundled-realms/pretui/components/agent-question.gts +340 -37
  3. package/bundled-realms/pretui/components/answer-footer.gts +249 -0
  4. package/bundled-realms/pretui/components/card-embed.gts +523 -0
  5. package/bundled-realms/pretui/components/card-pills.gts +725 -0
  6. package/bundled-realms/pretui/components/code-block.gts +87 -45
  7. package/bundled-realms/pretui/components/collapsed-turn.gts +133 -12
  8. package/bundled-realms/pretui/components/compaction-chip.gts +81 -67
  9. package/bundled-realms/pretui/components/composer-cap.gts +516 -0
  10. package/bundled-realms/pretui/components/context-ring.gts +108 -0
  11. package/bundled-realms/pretui/components/diff-block.gts +1002 -31
  12. package/bundled-realms/pretui/components/diff-stat.gts +102 -0
  13. package/bundled-realms/pretui/components/jump-chip.gts +86 -53
  14. package/bundled-realms/pretui/components/markdown-stream.gts +799 -0
  15. package/bundled-realms/pretui/components/markdown-surface.gts +71 -0
  16. package/bundled-realms/pretui/components/plan-mark.gts +147 -0
  17. package/bundled-realms/pretui/components/prose.gts +185 -8
  18. package/bundled-realms/pretui/components/prose.md +6 -8
  19. package/bundled-realms/pretui/components/quick-look.gts +377 -0
  20. package/bundled-realms/pretui/components/reactions.gts +136 -0
  21. package/bundled-realms/pretui/components/recommendation.gts +67 -36
  22. package/bundled-realms/pretui/components/result-card.gts +58 -22
  23. package/bundled-realms/pretui/components/segmented-control.gts +13 -8
  24. package/bundled-realms/pretui/components/session-prep.gts +12 -11
  25. package/bundled-realms/pretui/components/sliding-highlight.gts +8 -3
  26. package/bundled-realms/pretui/components/speaker-label.gts +132 -0
  27. package/bundled-realms/pretui/components/state-glyph.gts +121 -0
  28. package/bundled-realms/pretui/components/step-list.gts +62 -60
  29. package/bundled-realms/pretui/components/stick-to-bottom.gts +1150 -0
  30. package/bundled-realms/pretui/components/system-line.gts +143 -0
  31. package/bundled-realms/pretui/components/task-checklist.gts +184 -0
  32. package/bundled-realms/pretui/components/thinking.gts +63 -94
  33. package/bundled-realms/pretui/components/tool-change-table.gts +285 -0
  34. package/bundled-realms/pretui/components/tool-gate.gts +462 -0
  35. package/bundled-realms/pretui/components/tool-group.gts +920 -0
  36. package/bundled-realms/pretui/components/tool-icon.ts +64 -0
  37. package/bundled-realms/pretui/components/tool-meta.gts +82 -0
  38. package/bundled-realms/pretui/components/tool-plan.gts +197 -0
  39. package/bundled-realms/pretui/components/tool-row.gts +2087 -0
  40. package/bundled-realms/pretui/components/turn-changes.gts +227 -0
  41. package/bundled-realms/pretui/components/user-bubble.gts +575 -0
  42. package/bundled-realms/pretui/components/work-item.gts +185 -48
  43. package/bundled-realms/pretui/docs/scroll-anchoring-protocol.md +136 -0
  44. package/bundled-realms/pretui/internal/markdown-projection.ts +438 -0
  45. package/bundled-realms/pretui/internal/mount-queue.ts +79 -0
  46. package/bundled-realms/pretui/internal/tool-phrases.ts +168 -0
  47. package/bundled-realms/pretui/package.json +2 -1
  48. package/bundled-test-harness/assets/{ai-module-creation-test-beRNwH-e.js → ai-module-creation-test-B6FQKqIl.js} +1 -1
  49. package/bundled-test-harness/assets/{app-QAuw0l8v.js → app-KpPqdyX3.js} +4 -4
  50. package/bundled-test-harness/assets/{binary-upload-dedupe-test-bI8T0QLl.js → binary-upload-dedupe-test-DN00y1tM.js} +1 -1
  51. package/bundled-test-harness/assets/{can-invoke-test-DVaU_yRT.js → can-invoke-test-Bl-EUFM3.js} +1 -1
  52. package/bundled-test-harness/assets/{card-chooser-paging-test-DnxMnXKR.js → card-chooser-paging-test-BNuZRHX3.js} +1 -1
  53. package/bundled-test-harness/assets/{card-chooser-test-DUSnLr-u.js → card-chooser-test-wKfPOOT4.js} +1 -1
  54. package/bundled-test-harness/assets/{card-def-field-def-relationships-test-GBUr3tFK.js → card-def-field-def-relationships-test-CduQ6zan.js} +1 -1
  55. package/bundled-test-harness/assets/{card-delete-test-CQveO1VC.js → card-delete-test-DKxolj5o.js} +1 -1
  56. package/bundled-test-harness/assets/{check-correctness-test-D2M2p66N.js → check-correctness-test-B-kgHztp.js} +1 -1
  57. package/bundled-test-harness/assets/choreo-BEHW-NOc.js +2 -0
  58. package/bundled-test-harness/assets/{choreo-CJfBb_EY.js → choreo-C2cpCfhA.js} +164 -13
  59. package/bundled-test-harness/assets/{choreo-feature-reel-test-D2OrygZv.js → choreo-feature-reel-test-CPI_6nkT.js} +2 -2
  60. package/bundled-test-harness/assets/{choreo-gallery-w07xqtO-.js → choreo-gallery-BxA9cyzF.js} +3 -3
  61. package/bundled-test-harness/assets/{choreo-gallery-build-order-test-yQg4JER6.js → choreo-gallery-build-order-test-CLVoseAJ.js} +1 -1
  62. package/bundled-test-harness/assets/{choreo-gallery-compositor-test-C2THCXJN.js → choreo-gallery-compositor-test-BpT5Ia6B.js} +1 -1
  63. package/bundled-test-harness/assets/{choreo-gallery-cover-test-D4T_Tk4s.js → choreo-gallery-cover-test-DL_fdSsh.js} +1 -1
  64. package/bundled-test-harness/assets/{choreo-gallery-crossing-stage-test-tHUPJ-Hy.js → choreo-gallery-crossing-stage-test-BcKHhpOK.js} +2 -2
  65. package/bundled-test-harness/assets/{choreo-gallery-demos-alive-test-BOtBOnEZ.js → choreo-gallery-demos-alive-test-KufLhXG8.js} +1 -1
  66. package/bundled-test-harness/assets/{choreo-gallery-drift-test-D_6U1Z2c.js → choreo-gallery-drift-test-Cx58rYIA.js} +1 -1
  67. package/bundled-test-harness/assets/{choreo-gallery-escort-test-DDBU0n4C.js → choreo-gallery-escort-test-Wz-emmID.js} +1 -1
  68. package/bundled-test-harness/assets/{choreo-gallery-films-test-CgW1NSdr.js → choreo-gallery-films-test-BFrVs5WW.js} +2 -2
  69. package/bundled-test-harness/assets/{choreo-gallery-filter-test-DUIsNwdO.js → choreo-gallery-filter-test-DCKQkhwe.js} +1 -1
  70. package/bundled-test-harness/assets/{choreo-gallery-fold-test-Chzlxvdr.js → choreo-gallery-fold-test-UtpDgpG9.js} +1 -1
  71. package/bundled-test-harness/assets/{choreo-gallery-guide-pages-test-DOWnqALT.js → choreo-gallery-guide-pages-test-rXDU9JLM.js} +1 -1
  72. package/bundled-test-harness/assets/{choreo-gallery-guides-test-Dra2J4LJ.js → choreo-gallery-guides-test-DfVFdIuU.js} +3 -3
  73. package/bundled-test-harness/assets/{choreo-gallery-hang-test-zzn1eiB-.js → choreo-gallery-hang-test-Cj7MbkFf.js} +1 -1
  74. package/bundled-test-harness/assets/{choreo-gallery-highlight-test-CW99hncQ.js → choreo-gallery-highlight-test-D6CF3IYZ.js} +2 -2
  75. package/bundled-test-harness/assets/{choreo-gallery-inline-edit-test-CYFm1kUz.js → choreo-gallery-inline-edit-test-LfHWsbqc.js} +1 -1
  76. package/bundled-test-harness/assets/{choreo-gallery-interruption-test-CYIBrKV9.js → choreo-gallery-interruption-test-CvQQAgTp.js} +2 -2
  77. package/bundled-test-harness/assets/{choreo-gallery-lone-stack-test-DL8R3SG7.js → choreo-gallery-lone-stack-test-D7Zci7fm.js} +1 -1
  78. package/bundled-test-harness/assets/{choreo-gallery-navigation-test-Dcv04kDx.js → choreo-gallery-navigation-test-DB1EnBEW.js} +1 -1
  79. package/bundled-test-harness/assets/{choreo-gallery-playhead-transport-test-Cfz7GsXl.js → choreo-gallery-playhead-transport-test-CtBlc6AJ.js} +1 -1
  80. package/bundled-test-harness/assets/{choreo-gallery-poplayout-subtree-test-CwoklBkW.js → choreo-gallery-poplayout-subtree-test-BQbmjsvI.js} +1 -1
  81. package/bundled-test-harness/assets/{choreo-gallery-presence-modes-test-BDCIZzJ0.js → choreo-gallery-presence-modes-test-CIdXVG1K.js} +1 -1
  82. package/bundled-test-harness/assets/{choreo-gallery-presentation-test-DlyiHwFf.js → choreo-gallery-presentation-test-C_rPFp29.js} +1 -1
  83. package/bundled-test-harness/assets/{choreo-gallery-reduced-motion-test-DVz5SKNR.js → choreo-gallery-reduced-motion-test-CH5w8Lw-.js} +2 -2
  84. package/bundled-test-harness/assets/{choreo-gallery-sheet-standalone-test-CpD_-BvS.js → choreo-gallery-sheet-standalone-test-CDgI4mGX.js} +1 -1
  85. package/bundled-test-harness/assets/{choreo-gallery-sheet-test-BjvAKHDL.js → choreo-gallery-sheet-test-5lsFX7Rk.js} +1 -1
  86. package/bundled-test-harness/assets/{choreo-gallery-site-test-oq_7y_PN.js → choreo-gallery-site-test-DbMa2xeC.js} +2 -2
  87. package/bundled-test-harness/assets/{choreo-gallery-stage-Bzr4_8Xd.js → choreo-gallery-stage-b3Sk86hp.js} +2 -2
  88. package/bundled-test-harness/assets/{choreo-gallery-stage-keyboard-test-a83d2euJ.js → choreo-gallery-stage-keyboard-test-ds6fT5Eg.js} +1 -1
  89. package/bundled-test-harness/assets/{choreo-gallery-stages-test-C9Sl1kH6.js → choreo-gallery-stages-test-ahioKCct.js} +2 -2
  90. package/bundled-test-harness/assets/{choreo-gallery-subdivision-test-BVVnkOwk.js → choreo-gallery-subdivision-test-g7anTDhT.js} +1 -1
  91. package/bundled-test-harness/assets/{choreo-gallery-table-plan-test-B0YdYEA0.js → choreo-gallery-table-plan-test-Bozc4uUf.js} +1 -1
  92. package/bundled-test-harness/assets/{choreo-gallery-theater-test-BLA147xw.js → choreo-gallery-theater-test-kE535d-b.js} +3 -3
  93. package/bundled-test-harness/assets/{choreo-gallery-tuning-test-DSXiNzCh.js → choreo-gallery-tuning-test-6rHkQBnZ.js} +1 -1
  94. package/bundled-test-harness/assets/{choreo-gallery-widget-room-test-BI574PdO.js → choreo-gallery-widget-room-test-0Vq-uTo1.js} +2 -2
  95. package/bundled-test-harness/assets/{choreo-gallery-wires-test-B6Mz2WZl.js → choreo-gallery-wires-test-CdtnAWYO.js} +1 -1
  96. package/bundled-test-harness/assets/clip-BLfuHi8g.js +2 -0
  97. package/bundled-test-harness/assets/{clip-C_pXjVvY.js → clip-q1QE5f73.js} +1 -1
  98. package/bundled-test-harness/assets/{codeblocks-test-AdolhdCA.js → codeblocks-test-BDD7qK_V.js} +1 -1
  99. package/bundled-test-harness/assets/{compaction-test-DvyAQq56.js → compaction-test-BweolkhG.js} +1 -1
  100. package/bundled-test-harness/assets/{container-DIF_9lZ9.css → container-B5B6u-xm.css} +29 -22
  101. package/bundled-test-harness/assets/{container-DvvqmNpg.js → container-BnJjIM6J.js} +9 -6
  102. package/bundled-test-harness/assets/{create-listing-modal-test-D95JfQab.js → create-listing-modal-test-FvcAKpIa.js} +1 -1
  103. package/bundled-test-harness/assets/{debug-message-test-BcNtj7Wr.js → debug-message-test-CJ18Evt7.js} +1 -1
  104. package/bundled-test-harness/assets/{externals-6ZWftYIb.js → externals-BWjhmCD4.js} +12 -12
  105. package/bundled-test-harness/assets/{fallback-banner-live-delete-test-5lnN1pv2.js → fallback-banner-live-delete-test-C2H3BrT-.js} +1 -1
  106. package/bundled-test-harness/assets/{fallback-banner-test-DFb_m_Kq.js → fallback-banner-test-C10aYjkj.js} +1 -1
  107. package/bundled-test-harness/assets/{fallback-models-test-p3YIwj1L.js → fallback-models-test-BxoPiaGF.js} +1 -1
  108. package/bundled-test-harness/assets/{file-attachment-test-CmyjNWRR.js → file-attachment-test-DeKyzYaz.js} +1 -1
  109. package/bundled-test-harness/assets/film-B68PjRlr.js +2 -0
  110. package/bundled-test-harness/assets/{film-D7vtJO5q.js → film-CeUpnHN_.js} +6 -6
  111. package/bundled-test-harness/assets/{film-DN0A8JHx.js → film-DBZqyqW4.js} +6 -6
  112. package/bundled-test-harness/assets/{general-test-CX-TFDuX.js → general-test-BewzrpoB.js} +1 -1
  113. package/bundled-test-harness/assets/{glimmer-motion-and-choreo-in-cards-test-BHte2t9G.js → glimmer-motion-and-choreo-in-cards-test-HA-INN3d.js} +14 -14
  114. package/bundled-test-harness/assets/{glimmer-motion-and-choreo-test-BPNVeIio.js → glimmer-motion-and-choreo-test-BZ0ZuuAw.js} +3 -3
  115. package/bundled-test-harness/assets/{index-query-engine-test-Dz7Q4Xmk.js → index-query-engine-test-BtI8Y2LR.js} +1 -1
  116. package/bundled-test-harness/assets/{instance-filter-matcher-test-BoLU3bVg.js → instance-filter-matcher-test-BHXHGHjE.js} +1 -1
  117. package/bundled-test-harness/assets/{main-Dlgp8c7v.js → main-CqAHZ2kK.js} +1 -1
  118. package/bundled-test-harness/assets/{message-tool-test-CfjRSJvt.js → message-tool-test-NMaPJFsd.js} +1 -1
  119. package/bundled-test-harness/assets/{model-cost-tier-test-mZG84Uso.js → model-cost-tier-test-BgbfN2LH.js} +1 -1
  120. package/bundled-test-harness/assets/{operation-lowering-test-B0KpI1xu.js → operation-lowering-test-C4IaOjsA.js} +1 -1
  121. package/bundled-test-harness/assets/{operator-mode-card-chooser-test-KWS8lq16.js → operator-mode-card-chooser-test-Bwe47Rn7.js} +1 -1
  122. package/bundled-test-harness/assets/{operator-mode-links-test-CViFt0Ws.js → operator-mode-links-test-BU4jkC-B.js} +1 -1
  123. package/bundled-test-harness/assets/{operator-mode-test-D0gZM2yw.js → operator-mode-test-Bh0rGM9z.js} +1 -1
  124. package/bundled-test-harness/assets/{operator-mode-ui-test-CEvHJ9DS.js → operator-mode-ui-test-whgUw0ju.js} +1 -1
  125. package/bundled-test-harness/assets/{overlay-menu-items-test-Pw80RXsr.js → overlay-menu-items-test-Cwn1vr8q.js} +1 -1
  126. package/bundled-test-harness/assets/{overlays-BnOM360u.js → overlays-BOzLbVDK.js} +1 -1
  127. package/bundled-test-harness/assets/{overlays-kBVfa4i8.js → overlays-C_PuGDGh.js} +1 -1
  128. package/bundled-test-harness/assets/{past-sessions-test-CW0-Bjav.js → past-sessions-test-Bh24N-Kz.js} +1 -1
  129. package/bundled-test-harness/assets/{permission-checking-realm-test-D5uXQypS.js → permission-checking-realm-test-DKnnAy0f.js} +1 -1
  130. package/bundled-test-harness/assets/{plate-CFvCDv2t.js → plate-BL7UtyKE.js} +1 -1
  131. package/bundled-test-harness/assets/plate-CqG3igCJ.js +2 -0
  132. package/bundled-test-harness/assets/player-BJfsgdSI.js +2 -0
  133. package/bundled-test-harness/assets/{player-DzuYjrTU.js → player-Da_CIsp_.js} +1 -1
  134. package/bundled-test-harness/assets/{realm-config-policy-standing-test-Btatheni.js → realm-config-policy-standing-test-DngdYypq.js} +1 -1
  135. package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-Dh5zW13o.js → realm-config-routing-rule-edit-test-_rkFU8SN.js} +1 -1
  136. package/bundled-test-harness/assets/{realm-config-settings-test-BJa8gv_C.js → realm-config-settings-test-CR9NH0Zn.js} +1 -1
  137. package/bundled-test-harness/assets/{reasoning-test-2Zp37cQB.js → reasoning-test-0lH10kRl.js} +1 -1
  138. package/bundled-test-harness/assets/{room-message-test-BsrON13e.js → room-message-test-C-PddE4Y.js} +1 -1
  139. package/bundled-test-harness/assets/{run-BMyvn_UL.js → run-D4n4LPcK.js} +96 -6
  140. package/bundled-test-harness/assets/{run-realm-code-BxktQf6R.js → run-realm-code-C8N7DtN-.js} +1 -1
  141. package/bundled-test-harness/assets/{run-realm-code-test-7grpTos-.js → run-realm-code-test-DBdp147q.js} +1 -1
  142. package/bundled-test-harness/assets/{schema-generation-test-CM9ggQji.js → schema-generation-test-CB1Hb7GQ.js} +1 -1
  143. package/bundled-test-harness/assets/{scrolling-test-BER00htB.js → scrolling-test-3PhVin8h.js} +1 -1
  144. package/bundled-test-harness/assets/{searchable-option-test-BBr5BPow.js → searchable-option-test-BAdOiL4U.js} +1 -1
  145. package/bundled-test-harness/assets/{sending-test-BJGobs2E.js → sending-test-KSmu1tSJ.js} +1 -1
  146. package/bundled-test-harness/assets/{skills-test-GPOsHRN6.js → skills-test-D-dlcFpd.js} +1 -1
  147. package/bundled-test-harness/assets/{src-Df148w_b.js → src-B_DEhPze.js} +4 -4
  148. package/bundled-test-harness/assets/{src-Cf2wv-Le.js → src-BoTgwqUA.js} +2 -2
  149. package/bundled-test-harness/assets/{store-test-QvvHimzH.js → store-test-CEW7xQjZ.js} +1 -1
  150. package/bundled-test-harness/assets/{test-support-rNHuieEc.js → test-support-FXDPpIl3.js} +1 -1
  151. package/bundled-test-harness/assets/{test-support-C6N_2X-l.js → test-support-VX6ukQNR.js} +1 -1
  152. package/bundled-test-harness/assets/{tests-CmsQ-Z_3.js → tests-QYqqa6nv.js} +84 -84
  153. package/bundled-test-harness/assets/{text-input-validator-test-CYYH2N0L.js → text-input-validator-test-D8iNOWep.js} +1 -1
  154. package/bundled-test-harness/assets/{titles-B1pTaIfP.js → titles-DFJj5O0E.js} +1 -1
  155. package/bundled-test-harness/assets/titles-xGlgu7ys.js +2 -0
  156. package/bundled-test-harness/assets/{to-device-streaming-test-Ctqa0bVp.js → to-device-streaming-test-trCX-505.js} +1 -1
  157. package/bundled-test-harness/assets/{token-usage-test-BQVbK3X0.js → token-usage-test-C6sULooH.js} +1 -1
  158. package/bundled-test-harness/assets/{tools-DU8Rc15s.js → tools-UJfD-_al.js} +1 -1
  159. package/bundled-test-harness/assets/{tools-test-B13yvEKE.js → tools-test-Brav31AV.js} +1 -1
  160. package/bundled-test-harness/assets/{worker-DHBEBihX.js → worker-9ph9_Lpv.js} +31 -26
  161. package/bundled-test-harness/index.html +8 -8
  162. package/bundled-test-harness/tests/index.html +8 -8
  163. package/bundled-types/choreo/beacons.ts +16 -4
  164. package/bundled-types/choreo/changeset.ts +25 -5
  165. package/bundled-types/choreo/choreo.gts +245 -3
  166. package/bundled-types/choreo/far.ts +39 -0
  167. package/bundled-types/choreo/index.ts +2 -0
  168. package/bundled-types/choreo/run.ts +104 -1
  169. package/bundled-types/host-app/lib/realm-runner/worker.ts +8 -51
  170. package/bundled-types/runtime-common/realm-runner-script.d.ts +3 -0
  171. package/package.json +1 -1
  172. package/bundled-test-harness/assets/choreo-B3Z9QhDH.js +0 -2
  173. package/bundled-test-harness/assets/clip-BjcXuTwN.js +0 -2
  174. package/bundled-test-harness/assets/film-DMDPP7ma.js +0 -2
  175. package/bundled-test-harness/assets/plate-66qnQ-M9.js +0 -2
  176. package/bundled-test-harness/assets/player-pygg1PwA.js +0 -2
  177. package/bundled-test-harness/assets/titles-Ccpcl-jq.js +0 -2
@@ -0,0 +1,523 @@
1
+ // Pretui — CardEmbed: the frame around a host-rendered card inside the transcript.
2
+ import Component from '@glimmer/component';
3
+ import { StateGlyph } from './state-glyph';
4
+ import { on } from '@ember/modifier';
5
+ import type { ComponentLike } from '@glint/template';
6
+ import { cssDeclaration, cssStyleFrom } from '../pretui-css';
7
+
8
+ export type CardEmbedState =
9
+ | 'pending'
10
+ | 'loading'
11
+ | 'ready'
12
+ | 'error'
13
+ | 'missing'
14
+ | 'auth-required'
15
+ | 'cancelled';
16
+ export type CardEmbedFormat =
17
+ | 'fitted'
18
+ | 'embedded'
19
+ | 'isolated'
20
+ | 'edit'
21
+ | 'atom';
22
+
23
+ export interface CardEmbedSignature {
24
+ Args: {
25
+ /** the format the host renders the card in; drives the sizing */
26
+ format?: CardEmbedFormat;
27
+ /** an explicit box, from the ref's args or the host's size parser:
28
+ * '320px', '100%' */
29
+ width?: string;
30
+ height?: string;
31
+ /** the least height the card gets. Default: fitted 4rem, embedded
32
+ * 7.5rem, isolated 12.5rem */
33
+ minHeight?: string;
34
+ /** past this, the card scrolls in its own box */
35
+ maxHeight?: string;
36
+ /** 'ready' (default), 'pending' (the call is still writing it: the
37
+ * box is held with a shimmering line), 'loading' (the card is
38
+ * fetching), 'error', 'missing' (deleted since) */
39
+ state?: CardEmbedState;
40
+ /** the card's title: the frame's name, and the pending line */
41
+ label?: string;
42
+ /** its type, said quietly: 'Tea lot' */
43
+ kind?: string;
44
+ /** open the card where the reader works; a corner Open with an arrow icon */
45
+ onOpen?: () => void;
46
+ /** the corner button's words. Default 'Open'; 'Open in Boxel' inside
47
+ * an MCP App, where `@onOpen` calls the host's openLink */
48
+ openLabel?: string;
49
+ /** the hat: one 1.625rem line over the card with its type, its title and
50
+ * its actions (Open, and `<:actions>`). Default: on for embedded,
51
+ * isolated and edit, which are big enough to carry one; off for fitted
52
+ * and atom, which keep a quiet corner Open */
53
+ hat?: boolean;
54
+ /** the type's icon, in the hat: a boxel-icons component */
55
+ icon?: ComponentLike<{ Element: SVGSVGElement }>;
56
+ /** why it could not show, or why it was cancelled */
57
+ error?: string;
58
+ onRetry?: () => void;
59
+ /** fill the width it is given, with no cap and no outer edge: the
60
+ * top-level frame of an MCP App iframe */
61
+ fill?: boolean;
62
+ /** the definite box a fitted card needs when nothing around it has a
63
+ * height: an aspect ratio ('16 / 9') or a height ('180px') */
64
+ envelope?: string;
65
+ /** 'auth-required': what access is missing ("Saving needs edit access
66
+ * to Home renovation"), with one action */
67
+ authPrompt?: string;
68
+ authorizeLabel?: string;
69
+ onAuthorize?: () => void;
70
+ };
71
+ Blocks: {
72
+ /** the host's CardRenderer */
73
+ default: [];
74
+ /** replaces the pending line */
75
+ pending: [];
76
+ /** more corner actions, beside Open */
77
+ actions: [];
78
+ };
79
+ Element: HTMLDivElement;
80
+ }
81
+
82
+ const MIN: Record<CardEmbedFormat, string> = {
83
+ fitted: '4rem',
84
+ embedded: '7.5rem',
85
+ isolated: '12.5rem',
86
+ edit: '12.5rem',
87
+ atom: '1.25rem',
88
+ };
89
+
90
+ /**
91
+ * Pret UI cannot render a card (that is the host's CardRenderer), so this
92
+ * is the frame, the states and the sizing around one. It holds the card's
93
+ * box while the call is still writing it (Law 8: late values never shift
94
+ * layout), stops the transcript's prose styles at its edge so the card
95
+ * keeps its own type and theme, scrolls a tall card in its own box, and
96
+ * offers "Open ↗" in a corner, outside the card's own tab order.
97
+ */
98
+ export class CardEmbed extends Component<CardEmbedSignature> {
99
+ get format(): CardEmbedFormat {
100
+ return this.args.format ?? 'fitted';
101
+ }
102
+ get state(): CardEmbedState {
103
+ return this.args.state ?? 'ready';
104
+ }
105
+ get isPending() {
106
+ return this.state === 'pending';
107
+ }
108
+ get isLoading() {
109
+ return this.state === 'loading';
110
+ }
111
+ get isError() {
112
+ return (
113
+ this.state === 'error' ||
114
+ this.state === 'missing' ||
115
+ this.state === 'cancelled'
116
+ );
117
+ }
118
+ get needsAuth() {
119
+ return this.state === 'auth-required';
120
+ }
121
+ get authText(): string {
122
+ return this.args.authPrompt ?? 'This needs more access';
123
+ }
124
+ /** a card that failed can be tried again; a deleted one cannot */
125
+ get canRetry() {
126
+ return this.state === 'error' && Boolean(this.args.onRetry);
127
+ }
128
+ get hasHat(): boolean {
129
+ if (this.args.hat !== undefined) {
130
+ return this.args.hat;
131
+ }
132
+ let f = this.format;
133
+ return (
134
+ (f === 'embedded' || f === 'isolated' || f === 'edit') &&
135
+ Boolean(this.args.label ?? this.args.kind)
136
+ );
137
+ }
138
+ get showsCard() {
139
+ return this.state === 'ready' || this.state === 'loading';
140
+ }
141
+ /** each size is validated as one CSS value; a rejected one is dropped
142
+ * and the frame keeps its default */
143
+ get boxStyle() {
144
+ let { envelope, minHeight, width, height, maxHeight } = this.args;
145
+ let ratio = envelope?.includes('/');
146
+ return cssStyleFrom([
147
+ cssDeclaration('--pretui-embed-min', minHeight) ??
148
+ `--pretui-embed-min: ${MIN[this.format]}`,
149
+ ratio ? cssDeclaration('aspect-ratio', envelope) : undefined,
150
+ envelope && !ratio
151
+ ? cssDeclaration('--pretui-embed-h', envelope)
152
+ : undefined,
153
+ cssDeclaration('--pretui-embed-w', width),
154
+ cssDeclaration('--pretui-embed-h', height),
155
+ cssDeclaration('--pretui-embed-max-h', maxHeight),
156
+ ]);
157
+ }
158
+ get pendingText(): string {
159
+ let what = this.args.label ?? this.args.kind ?? 'the card';
160
+ return `Making ${what}…`;
161
+ }
162
+ get errorText(): string {
163
+ let what = this.args.label ?? this.args.kind ?? 'the card';
164
+ if (this.state === 'cancelled') {
165
+ return this.args.error ? `Cancelled · ${this.args.error}` : 'Cancelled';
166
+ }
167
+ return this.state === 'missing'
168
+ ? `${what} was deleted since`
169
+ : (this.args.error ?? `Couldn’t show ${what}`);
170
+ }
171
+ get openLabel(): string {
172
+ return this.args.openLabel
173
+ ? `${this.args.openLabel}: ${this.args.label ?? 'the card'}`
174
+ : `Open ${this.args.label ?? 'the card'} on the stack`;
175
+ }
176
+ get openText(): string {
177
+ return this.args.openLabel ?? 'Open';
178
+ }
179
+ authorize = () => this.args.onAuthorize?.();
180
+ open = () => this.args.onOpen?.();
181
+ retry = () => this.args.onRetry?.();
182
+ <template>
183
+ <div
184
+ class='pretui-embed'
185
+ role='group'
186
+ aria-label={{if @label @label 'Card'}}
187
+ aria-busy={{if (if this.isPending true this.isLoading) 'true'}}
188
+ data-format={{this.format}}
189
+ data-state={{this.state}}
190
+ data-fill={{if @fill 'true'}}
191
+ data-hat={{if this.hasHat 'true'}}
192
+ data-scroll-region={{if @maxHeight 'true'}}
193
+ style={{this.boxStyle}}
194
+ data-test-pretui-card-embed={{this.state}}
195
+ ...attributes
196
+ >
197
+ {{#if this.hasHat}}
198
+ <div class='pretui-embed-hat' data-test-pretui-card-embed-hat>
199
+ {{#if @icon}}<@icon
200
+ class='pretui-embed-hat-icon'
201
+ width='14'
202
+ height='14'
203
+ aria-hidden='true'
204
+ />{{/if}}
205
+ {{#if @kind}}<span
206
+ class='pretui-embed-hat-kind'
207
+ >{{@kind}}</span>{{/if}}
208
+ {{#if @label}}<span
209
+ class='pretui-embed-hat-title'
210
+ title={{@label}}
211
+ >{{@label}}</span>{{/if}}
212
+ <span class='pretui-embed-hat-actions'>
213
+ {{yield to='actions'}}
214
+ {{#if (if @onOpen this.showsCard)}}
215
+ <button
216
+ type='button'
217
+ class='pretui-embed-hat-open'
218
+ aria-label={{this.openLabel}}
219
+ {{on 'click' this.open}}
220
+ data-test-pretui-card-embed-open
221
+ >{{this.openText}}
222
+ <StateGlyph @glyph='open' @size={{11}} /></button>
223
+ {{/if}}
224
+ </span>
225
+ </div>
226
+ {{/if}}
227
+ {{#if this.isPending}}
228
+ <div class='pretui-embed-pending' data-test-pretui-card-embed-pending>
229
+ {{#if (has-block 'pending')}}{{yield to='pending'}}{{else}}
230
+ <span class='pretui-embed-shimmer'>{{this.pendingText}}</span>
231
+ {{/if}}
232
+ </div>
233
+ {{else if this.needsAuth}}
234
+ <div
235
+ class='pretui-embed-error'
236
+ data-kind='auth'
237
+ role='status'
238
+ data-test-pretui-card-embed-auth
239
+ >
240
+ <span>{{this.authText}}</span>
241
+ {{#if @onAuthorize}}<button
242
+ type='button'
243
+ class='pretui-embed-act'
244
+ data-kind='primary'
245
+ data-test-pretui-card-embed-authorize
246
+ {{on 'click' this.authorize}}
247
+ >{{if
248
+ @authorizeLabel
249
+ @authorizeLabel
250
+ 'Ask for access'
251
+ }}</button>{{/if}}
252
+ </div>
253
+ {{else if this.isError}}
254
+ <div
255
+ class='pretui-embed-error'
256
+ role='status'
257
+ data-test-pretui-card-embed-error
258
+ >
259
+ <span>{{this.errorText}}</span>
260
+ {{#if this.canRetry}}<button
261
+ type='button'
262
+ class='pretui-embed-act'
263
+ data-test-pretui-card-embed-retry
264
+ {{on 'click' this.retry}}
265
+ >Retry</button>{{/if}}
266
+ </div>
267
+ {{else}}
268
+ <div class='pretui-embed-card'>{{yield}}</div>
269
+ {{/if}}
270
+ {{#if
271
+ (if
272
+ this.hasHat
273
+ false
274
+ (if this.showsCard (if @onOpen true (has-block 'actions')))
275
+ )
276
+ }}
277
+ <div class='pretui-embed-corner'>
278
+ {{yield to='actions'}}
279
+ {{#if @onOpen}}
280
+ <button
281
+ type='button'
282
+ class='pretui-embed-open'
283
+ aria-label={{this.openLabel}}
284
+ {{on 'click' this.open}}
285
+ data-test-pretui-card-embed-open
286
+ >{{this.openText}}
287
+ <StateGlyph @glyph='open' @size={{11}} /></button>
288
+ {{/if}}
289
+ </div>
290
+ {{/if}}
291
+ </div>
292
+ <style scoped>
293
+ @layer PretComponent {
294
+ /* a size container at the text column's width: the card's own
295
+ container queries see the embed, not the window */
296
+ .pretui-embed {
297
+ container-type: inline-size;
298
+ position: relative;
299
+ box-sizing: border-box;
300
+ width: var(--pretui-embed-w, 100%);
301
+ max-width: var(--pretui-embed-max, 37.5rem);
302
+ min-height: var(--pretui-embed-min);
303
+ height: var(--pretui-embed-h, auto);
304
+ max-height: var(--pretui-embed-max-h, none);
305
+ overflow: auto;
306
+ border-radius: var(--boxel-border-radius);
307
+ box-shadow: 0 0 0 1px var(--border);
308
+ isolation: isolate;
309
+ contain: layout paint;
310
+ /* the transcript's prose stops at the frame: the card brings
311
+ its own measure, leading and link colour */
312
+ font-family: var(--font-sans);
313
+ font-size: var(--boxel-font-size);
314
+ font-weight: 400;
315
+ font-style: normal;
316
+ line-height: normal;
317
+ letter-spacing: normal;
318
+ text-align: start;
319
+ white-space: normal;
320
+ color: var(--foreground);
321
+ }
322
+ /* the hat: one quiet line in the frame's own chrome over the card's
323
+ surface, lower than the host's card header: the type as a mono
324
+ eyebrow, the title at the small size, and the actions as text */
325
+ .pretui-embed[data-hat] {
326
+ display: grid;
327
+ grid-template-rows: auto minmax(0, 1fr);
328
+ }
329
+ .pretui-embed-hat {
330
+ position: sticky;
331
+ inset-block-start: 0;
332
+ z-index: 1;
333
+ display: flex;
334
+ align-items: center;
335
+ gap: var(--boxel-sp-2xs);
336
+ min-width: 0;
337
+ height: 1.625rem;
338
+ padding: 0 var(--boxel-sp-2xs) 0 var(--boxel-sp-xs);
339
+ background-color: var(--card);
340
+ box-shadow: 0 1px 0 var(--border);
341
+ color: var(--card-foreground);
342
+ }
343
+ .pretui-embed-hat-icon {
344
+ flex: none;
345
+ color: var(--muted-foreground);
346
+ }
347
+ .pretui-embed-hat-kind {
348
+ flex: none;
349
+ font-family: var(--font-mono);
350
+ font-size: var(--boxel-font-size-2xs);
351
+ font-weight: 500;
352
+ letter-spacing: 0.06em;
353
+ text-transform: uppercase;
354
+ color: var(--subtle-foreground);
355
+ }
356
+ .pretui-embed-hat-title {
357
+ min-width: 0;
358
+ overflow: hidden;
359
+ text-overflow: ellipsis;
360
+ white-space: nowrap;
361
+ font-size: var(--boxel-font-size-xs);
362
+ font-weight: 500;
363
+ }
364
+ .pretui-embed-hat-actions {
365
+ display: flex;
366
+ align-items: center;
367
+ gap: var(--boxel-sp-6xs);
368
+ margin-inline-start: auto;
369
+ }
370
+ .pretui-embed-hat-open {
371
+ display: inline-flex;
372
+ align-items: center;
373
+ gap: var(--boxel-sp-5xs);
374
+ height: 1.5rem;
375
+ padding: 0 var(--boxel-sp-2xs);
376
+ border: 0;
377
+ border-radius: var(--boxel-border-radius-xs);
378
+ background-color: transparent;
379
+ font-family: inherit;
380
+ font-size: var(--boxel-font-size-2xs);
381
+ font-weight: 500;
382
+ color: var(--muted-foreground);
383
+ cursor: pointer;
384
+ }
385
+ .pretui-embed-hat-open:hover {
386
+ color: var(--primary-ink);
387
+ background-color: var(--hover);
388
+ }
389
+ .pretui-embed-hat-open:focus-visible {
390
+ outline: 2px solid var(--ring);
391
+ outline-offset: 1px;
392
+ }
393
+ /* the iframe's top level: the whole width, no cap, no edge */
394
+ .pretui-embed[data-fill] {
395
+ max-width: none;
396
+ border-radius: 0;
397
+ box-shadow: none;
398
+ }
399
+ .pretui-embed-card {
400
+ display: grid;
401
+ min-height: inherit;
402
+ }
403
+ .pretui-embed-card > :deep(*) {
404
+ min-width: 0;
405
+ }
406
+ .pretui-embed-pending,
407
+ .pretui-embed-error {
408
+ display: flex;
409
+ align-items: center;
410
+ gap: var(--boxel-sp-xs);
411
+ box-sizing: border-box;
412
+ height: 100%;
413
+ min-height: var(--pretui-embed-min);
414
+ padding: var(--boxel-sp-sm);
415
+ background-color: var(--inset);
416
+ font-size: var(--boxel-font-size-xs);
417
+ color: var(--muted-foreground);
418
+ }
419
+ /* the shimmer is a moving gradient in CSS: no clock */
420
+ .pretui-embed-shimmer {
421
+ background-image: linear-gradient(
422
+ 90deg,
423
+ var(--muted-foreground) 0%,
424
+ var(--foreground) 50%,
425
+ var(--muted-foreground) 100%
426
+ );
427
+ background-size: 200% 100%;
428
+ -webkit-background-clip: text;
429
+ background-clip: text;
430
+ color: transparent;
431
+ animation: pretui-embed-shimmer 1.6s linear infinite;
432
+ }
433
+ @keyframes pretui-embed-shimmer {
434
+ from {
435
+ background-position: 100% 0;
436
+ }
437
+ to {
438
+ background-position: -100% 0;
439
+ }
440
+ }
441
+ .pretui-embed-error[data-kind='auth'] {
442
+ color: var(--foreground);
443
+ }
444
+ .pretui-embed-act[data-kind='primary'] {
445
+ padding: 0 var(--boxel-sp-xs);
446
+ border-radius: var(--boxel-border-radius-pill);
447
+ background-color: var(--primary);
448
+ color: var(--primary-foreground);
449
+ }
450
+ .pretui-embed[data-state='error'] .pretui-embed-error {
451
+ color: var(--destructive-ink);
452
+ }
453
+ /* 1.5rem tall, the least a pointer target takes */
454
+ .pretui-embed-act {
455
+ min-height: 1.5rem;
456
+ padding: 0 var(--boxel-sp-4xs);
457
+ border: 0;
458
+ border-radius: var(--boxel-border-radius-xs);
459
+ background-color: transparent;
460
+ font-family: inherit;
461
+ font-size: inherit;
462
+ font-weight: 600;
463
+ color: var(--foreground);
464
+ cursor: pointer;
465
+ }
466
+ .pretui-embed-act:hover {
467
+ color: var(--primary-ink);
468
+ }
469
+ /* Open sits in the corner, quiet until the frame is hovered or
470
+ focused (always on touch), never over the card's own controls'
471
+ focus order: it comes after the card */
472
+ .pretui-embed-corner {
473
+ position: absolute;
474
+ inset-block-start: var(--boxel-sp-2xs);
475
+ inset-inline-end: var(--boxel-sp-2xs);
476
+ display: flex;
477
+ gap: var(--boxel-sp-4xs);
478
+ opacity: 0;
479
+ transition: opacity 120ms ease-out;
480
+ }
481
+ .pretui-embed:hover .pretui-embed-corner,
482
+ .pretui-embed:focus-within .pretui-embed-corner {
483
+ opacity: 1;
484
+ }
485
+ @media (hover: none) {
486
+ .pretui-embed-corner {
487
+ opacity: 1;
488
+ }
489
+ }
490
+ .pretui-embed-open {
491
+ height: 1.5rem;
492
+ padding: 0 var(--boxel-sp-xs);
493
+ border: 0;
494
+ border-radius: var(--boxel-border-radius-pill);
495
+ background-color: var(--popover);
496
+ box-shadow: 0 0 0 1px var(--border-strong);
497
+ font-family: inherit;
498
+ font-size: var(--boxel-font-size-2xs);
499
+ font-weight: 500;
500
+ color: var(--popover-foreground);
501
+ cursor: pointer;
502
+ }
503
+ .pretui-embed-open:hover {
504
+ color: var(--primary-ink);
505
+ }
506
+ .pretui-embed-open:focus-visible,
507
+ .pretui-embed-act:focus-visible {
508
+ outline: 2px solid var(--ring);
509
+ outline-offset: 1px;
510
+ }
511
+ @media (prefers-reduced-motion: reduce) {
512
+ .pretui-embed-shimmer {
513
+ animation: none;
514
+ color: var(--muted-foreground);
515
+ }
516
+ .pretui-embed-corner {
517
+ transition: none;
518
+ }
519
+ }
520
+ }
521
+ </style>
522
+ </template>
523
+ }