@joewinke/jatui 0.36.3 → 0.38.0

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 (271) hide show
  1. package/dist/artifact-blocks/AttachmentChip.svelte +66 -0
  2. package/dist/artifact-blocks/AttachmentChip.svelte.d.ts +7 -0
  3. package/dist/artifact-blocks/BlockComments.svelte +309 -0
  4. package/dist/artifact-blocks/BlockComments.svelte.d.ts +33 -0
  5. package/dist/artifact-blocks/BlockRenderer.svelte +674 -0
  6. package/dist/artifact-blocks/BlockRenderer.svelte.d.ts +55 -0
  7. package/dist/artifact-blocks/BlockVerdict.svelte +151 -0
  8. package/dist/artifact-blocks/BlockVerdict.svelte.d.ts +13 -0
  9. package/dist/artifact-blocks/BlocksArtifactView.svelte +1616 -0
  10. package/dist/artifact-blocks/BlocksArtifactView.svelte.d.ts +113 -0
  11. package/dist/artifact-blocks/CONTRACT.md +225 -0
  12. package/dist/artifact-blocks/CommentPill.svelte +49 -0
  13. package/dist/artifact-blocks/CommentPill.svelte.d.ts +16 -0
  14. package/dist/artifact-blocks/FoldedRounds.svelte +95 -0
  15. package/dist/artifact-blocks/FoldedRounds.svelte.d.ts +9 -0
  16. package/dist/artifact-blocks/Glyph.svelte +54 -0
  17. package/dist/artifact-blocks/Glyph.svelte.d.ts +10 -0
  18. package/dist/artifact-blocks/HistoryScrubber.svelte +500 -0
  19. package/dist/artifact-blocks/HistoryScrubber.svelte.d.ts +15 -0
  20. package/dist/artifact-blocks/Markdown.svelte +186 -0
  21. package/dist/artifact-blocks/Markdown.svelte.d.ts +30 -0
  22. package/dist/artifact-blocks/NoteComposer.svelte +31 -0
  23. package/dist/artifact-blocks/NoteComposer.svelte.d.ts +8 -0
  24. package/dist/artifact-blocks/PlainComposer.svelte +200 -0
  25. package/dist/artifact-blocks/PlainComposer.svelte.d.ts +15 -0
  26. package/dist/artifact-blocks/SectionTools.svelte +102 -0
  27. package/dist/artifact-blocks/SectionTools.svelte.d.ts +19 -0
  28. package/dist/artifact-blocks/adapter.d.ts +13 -0
  29. package/dist/artifact-blocks/adapter.js +31 -0
  30. package/dist/artifact-blocks/autoSend.d.ts +49 -0
  31. package/dist/artifact-blocks/autoSend.js +103 -0
  32. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte +557 -0
  33. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte.d.ts +48 -0
  34. package/dist/artifact-blocks/blocks/actions/block.d.ts +8 -0
  35. package/dist/artifact-blocks/blocks/actions/block.js +74 -0
  36. package/dist/artifact-blocks/blocks/actions/requests.d.ts +62 -0
  37. package/dist/artifact-blocks/blocks/actions/requests.js +26 -0
  38. package/dist/artifact-blocks/blocks/actions/schema.d.ts +168 -0
  39. package/dist/artifact-blocks/blocks/actions/schema.js +253 -0
  40. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte +779 -0
  41. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte.d.ts +40 -0
  42. package/dist/artifact-blocks/blocks/callout/block.d.ts +7 -0
  43. package/dist/artifact-blocks/blocks/callout/block.js +39 -0
  44. package/dist/artifact-blocks/blocks/callout/schema.d.ts +72 -0
  45. package/dist/artifact-blocks/blocks/callout/schema.js +115 -0
  46. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte +875 -0
  47. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte.d.ts +59 -0
  48. package/dist/artifact-blocks/blocks/chart/block.d.ts +9 -0
  49. package/dist/artifact-blocks/blocks/chart/block.js +70 -0
  50. package/dist/artifact-blocks/blocks/chart/schema.d.ts +171 -0
  51. package/dist/artifact-blocks/blocks/chart/schema.js +498 -0
  52. package/dist/artifact-blocks/blocks/chart/thumb.d.ts +2 -0
  53. package/dist/artifact-blocks/blocks/chart/thumb.js +201 -0
  54. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte +1048 -0
  55. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte.d.ts +16 -0
  56. package/dist/artifact-blocks/blocks/checklist/Icon.svelte +105 -0
  57. package/dist/artifact-blocks/blocks/checklist/Icon.svelte.d.ts +17 -0
  58. package/dist/artifact-blocks/blocks/checklist/block.d.ts +10 -0
  59. package/dist/artifact-blocks/blocks/checklist/block.js +63 -0
  60. package/dist/artifact-blocks/blocks/checklist/itemReview.d.ts +16 -0
  61. package/dist/artifact-blocks/blocks/checklist/itemReview.js +63 -0
  62. package/dist/artifact-blocks/blocks/checklist/labels.d.ts +62 -0
  63. package/dist/artifact-blocks/blocks/checklist/labels.js +96 -0
  64. package/dist/artifact-blocks/blocks/checklist/retest.d.ts +43 -0
  65. package/dist/artifact-blocks/blocks/checklist/retest.js +68 -0
  66. package/dist/artifact-blocks/blocks/checklist/schema.d.ts +84 -0
  67. package/dist/artifact-blocks/blocks/checklist/schema.js +91 -0
  68. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte +128 -0
  69. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte.d.ts +12 -0
  70. package/dist/artifact-blocks/blocks/code/block.d.ts +8 -0
  71. package/dist/artifact-blocks/blocks/code/block.js +31 -0
  72. package/dist/artifact-blocks/blocks/code/highlight.d.ts +34 -0
  73. package/dist/artifact-blocks/blocks/code/highlight.js +280 -0
  74. package/dist/artifact-blocks/blocks/code/schema.d.ts +32 -0
  75. package/dist/artifact-blocks/blocks/code/schema.js +39 -0
  76. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte +290 -0
  77. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte.d.ts +29 -0
  78. package/dist/artifact-blocks/blocks/collage/block.d.ts +9 -0
  79. package/dist/artifact-blocks/blocks/collage/block.js +29 -0
  80. package/dist/artifact-blocks/blocks/collage/schema.d.ts +52 -0
  81. package/dist/artifact-blocks/blocks/collage/schema.js +86 -0
  82. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte +484 -0
  83. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte.d.ts +25 -0
  84. package/dist/artifact-blocks/blocks/compare/block.d.ts +9 -0
  85. package/dist/artifact-blocks/blocks/compare/block.js +32 -0
  86. package/dist/artifact-blocks/blocks/compare/schema.d.ts +74 -0
  87. package/dist/artifact-blocks/blocks/compare/schema.js +148 -0
  88. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte +392 -0
  89. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte.d.ts +30 -0
  90. package/dist/artifact-blocks/blocks/diagram/block.d.ts +9 -0
  91. package/dist/artifact-blocks/blocks/diagram/block.js +50 -0
  92. package/dist/artifact-blocks/blocks/diagram/constants.d.ts +48 -0
  93. package/dist/artifact-blocks/blocks/diagram/constants.js +53 -0
  94. package/dist/artifact-blocks/blocks/diagram/schema.d.ts +161 -0
  95. package/dist/artifact-blocks/blocks/diagram/schema.js +621 -0
  96. package/dist/artifact-blocks/blocks/diagram/thumb.d.ts +2 -0
  97. package/dist/artifact-blocks/blocks/diagram/thumb.js +157 -0
  98. package/dist/artifact-blocks/blocks/diagram/types.d.ts +74 -0
  99. package/dist/artifact-blocks/blocks/diagram/types.js +1 -0
  100. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte +81 -0
  101. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte.d.ts +10 -0
  102. package/dist/artifact-blocks/blocks/diff/block.d.ts +7 -0
  103. package/dist/artifact-blocks/blocks/diff/block.js +36 -0
  104. package/dist/artifact-blocks/blocks/diff/schema.d.ts +18 -0
  105. package/dist/artifact-blocks/blocks/diff/schema.js +35 -0
  106. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte +1055 -0
  107. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte.d.ts +5 -0
  108. package/dist/artifact-blocks/blocks/diff-review/block.d.ts +15 -0
  109. package/dist/artifact-blocks/blocks/diff-review/block.js +64 -0
  110. package/dist/artifact-blocks/blocks/diff-review/decisions.d.ts +57 -0
  111. package/dist/artifact-blocks/blocks/diff-review/decisions.js +80 -0
  112. package/dist/artifact-blocks/blocks/diff-review/schema.d.ts +13 -0
  113. package/dist/artifact-blocks/blocks/diff-review/schema.js +84 -0
  114. package/dist/artifact-blocks/blocks/diff-review/types.d.ts +35 -0
  115. package/dist/artifact-blocks/blocks/diff-review/types.js +1 -0
  116. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte +145 -0
  117. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte.d.ts +5 -0
  118. package/dist/artifact-blocks/blocks/explainer/block.d.ts +8 -0
  119. package/dist/artifact-blocks/blocks/explainer/block.js +21 -0
  120. package/dist/artifact-blocks/blocks/explainer/schema.d.ts +26 -0
  121. package/dist/artifact-blocks/blocks/explainer/schema.js +69 -0
  122. package/dist/artifact-blocks/blocks/group-content.d.ts +10 -0
  123. package/dist/artifact-blocks/blocks/group-content.js +16 -0
  124. package/dist/artifact-blocks/blocks/group-data.d.ts +10 -0
  125. package/dist/artifact-blocks/blocks/group-data.js +7 -0
  126. package/dist/artifact-blocks/blocks/group-review.d.ts +10 -0
  127. package/dist/artifact-blocks/blocks/group-review.js +12 -0
  128. package/dist/artifact-blocks/blocks/group-visual.d.ts +17 -0
  129. package/dist/artifact-blocks/blocks/group-visual.js +14 -0
  130. package/dist/artifact-blocks/blocks/map/MapBlock.svelte +413 -0
  131. package/dist/artifact-blocks/blocks/map/MapBlock.svelte.d.ts +53 -0
  132. package/dist/artifact-blocks/blocks/map/block.d.ts +9 -0
  133. package/dist/artifact-blocks/blocks/map/block.js +62 -0
  134. package/dist/artifact-blocks/blocks/map/schema.d.ts +123 -0
  135. package/dist/artifact-blocks/blocks/map/schema.js +113 -0
  136. package/dist/artifact-blocks/blocks/map/thumb.d.ts +2 -0
  137. package/dist/artifact-blocks/blocks/map/thumb.js +69 -0
  138. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte +33 -0
  139. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte.d.ts +15 -0
  140. package/dist/artifact-blocks/blocks/markdown/block.d.ts +7 -0
  141. package/dist/artifact-blocks/blocks/markdown/block.js +28 -0
  142. package/dist/artifact-blocks/blocks/markdown/render.d.ts +17 -0
  143. package/dist/artifact-blocks/blocks/markdown/render.js +115 -0
  144. package/dist/artifact-blocks/blocks/markdown/schema.d.ts +10 -0
  145. package/dist/artifact-blocks/blocks/markdown/schema.js +23 -0
  146. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte +2112 -0
  147. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte.d.ts +5 -0
  148. package/dist/artifact-blocks/blocks/media-picker/block.d.ts +24 -0
  149. package/dist/artifact-blocks/blocks/media-picker/block.js +137 -0
  150. package/dist/artifact-blocks/blocks/media-picker/choices.d.ts +28 -0
  151. package/dist/artifact-blocks/blocks/media-picker/choices.js +35 -0
  152. package/dist/artifact-blocks/blocks/media-picker/decisions.d.ts +51 -0
  153. package/dist/artifact-blocks/blocks/media-picker/decisions.js +75 -0
  154. package/dist/artifact-blocks/blocks/media-picker/schema.d.ts +7 -0
  155. package/dist/artifact-blocks/blocks/media-picker/schema.js +199 -0
  156. package/dist/artifact-blocks/blocks/media-picker/types.d.ts +92 -0
  157. package/dist/artifact-blocks/blocks/media-picker/types.js +1 -0
  158. package/dist/artifact-blocks/blocks/media-picker/versions.d.ts +51 -0
  159. package/dist/artifact-blocks/blocks/media-picker/versions.js +118 -0
  160. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte +213 -0
  161. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte.d.ts +5 -0
  162. package/dist/artifact-blocks/blocks/mockup/block.d.ts +26 -0
  163. package/dist/artifact-blocks/blocks/mockup/block.js +52 -0
  164. package/dist/artifact-blocks/blocks/mockup/doc.d.ts +24 -0
  165. package/dist/artifact-blocks/blocks/mockup/doc.js +44 -0
  166. package/dist/artifact-blocks/blocks/mockup/sandbox.d.ts +21 -0
  167. package/dist/artifact-blocks/blocks/mockup/sandbox.js +27 -0
  168. package/dist/artifact-blocks/blocks/mockup/schema.d.ts +7 -0
  169. package/dist/artifact-blocks/blocks/mockup/schema.js +90 -0
  170. package/dist/artifact-blocks/blocks/mockup/types.d.ts +36 -0
  171. package/dist/artifact-blocks/blocks/mockup/types.js +17 -0
  172. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte +359 -0
  173. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte.d.ts +32 -0
  174. package/dist/artifact-blocks/blocks/program/block.d.ts +35 -0
  175. package/dist/artifact-blocks/blocks/program/block.js +68 -0
  176. package/dist/artifact-blocks/blocks/program/schema.d.ts +132 -0
  177. package/dist/artifact-blocks/blocks/program/schema.js +268 -0
  178. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte +315 -0
  179. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte.d.ts +24 -0
  180. package/dist/artifact-blocks/blocks/stats/block.d.ts +7 -0
  181. package/dist/artifact-blocks/blocks/stats/block.js +49 -0
  182. package/dist/artifact-blocks/blocks/stats/schema.d.ts +82 -0
  183. package/dist/artifact-blocks/blocks/stats/schema.js +43 -0
  184. package/dist/artifact-blocks/blocks/stats/thumb.d.ts +2 -0
  185. package/dist/artifact-blocks/blocks/stats/thumb.js +102 -0
  186. package/dist/artifact-blocks/blocks/table/TableBlock.svelte +490 -0
  187. package/dist/artifact-blocks/blocks/table/TableBlock.svelte.d.ts +28 -0
  188. package/dist/artifact-blocks/blocks/table/block.d.ts +9 -0
  189. package/dist/artifact-blocks/blocks/table/block.js +100 -0
  190. package/dist/artifact-blocks/blocks/table/schema.d.ts +143 -0
  191. package/dist/artifact-blocks/blocks/table/schema.js +278 -0
  192. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte +347 -0
  193. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte.d.ts +42 -0
  194. package/dist/artifact-blocks/blocks/timeline/block.d.ts +9 -0
  195. package/dist/artifact-blocks/blocks/timeline/block.js +96 -0
  196. package/dist/artifact-blocks/blocks/timeline/constants.d.ts +26 -0
  197. package/dist/artifact-blocks/blocks/timeline/constants.js +27 -0
  198. package/dist/artifact-blocks/blocks/timeline/schema.d.ts +102 -0
  199. package/dist/artifact-blocks/blocks/timeline/schema.js +405 -0
  200. package/dist/artifact-blocks/blocks/timeline/thumb.d.ts +2 -0
  201. package/dist/artifact-blocks/blocks/timeline/thumb.js +117 -0
  202. package/dist/artifact-blocks/blocks/timeline/types.d.ts +66 -0
  203. package/dist/artifact-blocks/blocks/timeline/types.js +1 -0
  204. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte +169 -0
  205. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte.d.ts +26 -0
  206. package/dist/artifact-blocks/blocks/transcript/block.d.ts +9 -0
  207. package/dist/artifact-blocks/blocks/transcript/block.js +86 -0
  208. package/dist/artifact-blocks/blocks/transcript/schema.d.ts +114 -0
  209. package/dist/artifact-blocks/blocks/transcript/schema.js +126 -0
  210. package/dist/artifact-blocks/builtins.d.ts +40 -0
  211. package/dist/artifact-blocks/builtins.js +22 -0
  212. package/dist/artifact-blocks/contractBlocks.d.ts +92 -0
  213. package/dist/artifact-blocks/contractBlocks.js +279 -0
  214. package/dist/artifact-blocks/history.d.ts +140 -0
  215. package/dist/artifact-blocks/history.js +363 -0
  216. package/dist/artifact-blocks/index.d.ts +40 -0
  217. package/dist/artifact-blocks/index.js +46 -0
  218. package/dist/artifact-blocks/listen/context.d.ts +30 -0
  219. package/dist/artifact-blocks/listen/context.js +30 -0
  220. package/dist/artifact-blocks/liveData.d.ts +78 -0
  221. package/dist/artifact-blocks/liveData.js +137 -0
  222. package/dist/artifact-blocks/liveDataPoller.d.ts +41 -0
  223. package/dist/artifact-blocks/liveDataPoller.js +140 -0
  224. package/dist/artifact-blocks/openNav.d.ts +46 -0
  225. package/dist/artifact-blocks/openNav.js +106 -0
  226. package/dist/artifact-blocks/pageReviewKeys.d.ts +17 -0
  227. package/dist/artifact-blocks/pageReviewKeys.js +115 -0
  228. package/dist/artifact-blocks/params.d.ts +98 -0
  229. package/dist/artifact-blocks/params.js +159 -0
  230. package/dist/artifact-blocks/registry.d.ts +27 -0
  231. package/dist/artifact-blocks/registry.js +83 -0
  232. package/dist/artifact-blocks/review/BlockIcon.svelte +99 -0
  233. package/dist/artifact-blocks/review/BlockIcon.svelte.d.ts +17 -0
  234. package/dist/artifact-blocks/review/BulkRejectForm.svelte +94 -0
  235. package/dist/artifact-blocks/review/BulkRejectForm.svelte.d.ts +11 -0
  236. package/dist/artifact-blocks/review/BulkUndoBar.svelte +40 -0
  237. package/dist/artifact-blocks/review/BulkUndoBar.svelte.d.ts +9 -0
  238. package/dist/artifact-blocks/review/ItemNote.svelte +193 -0
  239. package/dist/artifact-blocks/review/ItemNote.svelte.d.ts +33 -0
  240. package/dist/artifact-blocks/review/NoteToggle.svelte +52 -0
  241. package/dist/artifact-blocks/review/NoteToggle.svelte.d.ts +12 -0
  242. package/dist/artifact-blocks/review/TeamChip.svelte +71 -0
  243. package/dist/artifact-blocks/review/TeamChip.svelte.d.ts +8 -0
  244. package/dist/artifact-blocks/review/attachments.d.ts +10 -0
  245. package/dist/artifact-blocks/review/attachments.js +37 -0
  246. package/dist/artifact-blocks/review/bulk.d.ts +52 -0
  247. package/dist/artifact-blocks/review/bulk.js +61 -0
  248. package/dist/artifact-blocks/review/itemReview.d.ts +33 -0
  249. package/dist/artifact-blocks/review/itemReview.js +112 -0
  250. package/dist/artifact-blocks/review/roundLines.d.ts +14 -0
  251. package/dist/artifact-blocks/review/roundLines.js +20 -0
  252. package/dist/artifact-blocks/review/rounds.d.ts +86 -0
  253. package/dist/artifact-blocks/review/rounds.js +302 -0
  254. package/dist/artifact-blocks/review/saver.d.ts +23 -0
  255. package/dist/artifact-blocks/review/saver.js +48 -0
  256. package/dist/artifact-blocks/review/team.d.ts +31 -0
  257. package/dist/artifact-blocks/review/team.js +42 -0
  258. package/dist/artifact-blocks/review/visualOrder.d.ts +29 -0
  259. package/dist/artifact-blocks/review/visualOrder.js +66 -0
  260. package/dist/artifact-blocks/review.d.ts +180 -0
  261. package/dist/artifact-blocks/review.js +716 -0
  262. package/dist/artifact-blocks/thumb-kit.d.ts +80 -0
  263. package/dist/artifact-blocks/thumb-kit.js +149 -0
  264. package/dist/artifact-blocks/types.d.ts +513 -0
  265. package/dist/artifact-blocks/types.js +1 -0
  266. package/dist/components/Button.svelte +8 -0
  267. package/dist/components/TextInput.svelte +39 -6
  268. package/dist/components/TextInput.svelte.d.ts +15 -7
  269. package/dist/components/basic/Checkbox.svelte +52 -14
  270. package/dist/components/basic/Checkbox.svelte.d.ts +11 -1
  271. package/package.json +11 -2
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Versions vs views for the media-picker (mos-0wvol).
3
+ *
4
+ * A review round's variants mix two different things: VERSIONS of the asset
5
+ * (v6 under review, v5 as last reviewed) and VIEWS of one version (the loop,
6
+ * an old-vs-new strip, a water-over-time map). Shown as one flat filmstrip
7
+ * the caption read "1 of 4 · v6 · v6" — meaningless. These helpers split an
8
+ * item into versions (newest first, the one under review marked) and, inside
9
+ * a version, labelled views.
10
+ *
11
+ * Pure: no DOM, no Svelte — the component and the tests share them.
12
+ * Backward compatible: an item whose variants carry fewer than two distinct
13
+ * versions has no version row (`versionsOf` returns []), exactly as before.
14
+ */
15
+ import type { MediaItem, MediaVariant } from "./types.js";
16
+ /** The version under review: explicit, else the first versioned variant's. */
17
+ export declare function currentVersionOf(item: MediaItem): string | null;
18
+ /** Which version a variant belongs to. Unversioned variants sit with the
19
+ * version under review (they are views of what is being judged). */
20
+ export declare function versionOfVariant(item: MediaItem, variant: MediaVariant): string | null;
21
+ /**
22
+ * Versions in display order: the one under review first, then the others
23
+ * in the order the publisher listed them (review-kit puts the newest first).
24
+ * Fewer than two distinct versions → [] (no switcher; render as before).
25
+ */
26
+ export declare function versionsOf(item: MediaItem): string[];
27
+ /** The views (variants) of one version; with no versions, every variant. */
28
+ export declare function viewsOf(item: MediaItem, version: string | null): MediaVariant[];
29
+ /**
30
+ * A view's human label with the redundant version prefix stripped:
31
+ * "v6" on a v6 video → "Loop"; "v6 · strip" → "strip"; "v5 (as reviewed)"
32
+ * → "Loop (as reviewed)". A label that says something else is kept as is.
33
+ */
34
+ export declare function cleanViewLabel(label: string | undefined | null, version: string | undefined | null, kind: MediaVariant["kind"]): string;
35
+ /** The label a view thumbnail and the caption show. */
36
+ export declare function viewLabel(item: MediaItem, variant: MediaVariant): string;
37
+ /**
38
+ * The card caption under the media:
39
+ * versioned → "v6 (reviewing) · Loop · 1 of 3" / "v5 (previous) · Loop · 1 of 1"
40
+ * flat → "1 of 4 · warm" (as before, minus a label that only repeats the version)
41
+ */
42
+ export declare function captionFor(item: MediaItem, variant: MediaVariant, version: string | null): string;
43
+ /**
44
+ * "Your verdict then: needs work. Note: “water not natural”" (or a no-record
45
+ * line). Takes the locked round line for the version (viewer or publisher
46
+ * history, merged by ../../review/rounds.ts).
47
+ */
48
+ export declare function historyLine(h: {
49
+ verdict?: string | null;
50
+ note?: string | null;
51
+ } | null | undefined): string;
@@ -0,0 +1,118 @@
1
+ /** The version under review: explicit, else the first versioned variant's. */
2
+ export function currentVersionOf(item) {
3
+ if (item.currentVersion)
4
+ return item.currentVersion;
5
+ return item.variants.find((v) => v.version)?.version ?? null;
6
+ }
7
+ /** Which version a variant belongs to. Unversioned variants sit with the
8
+ * version under review (they are views of what is being judged). */
9
+ export function versionOfVariant(item, variant) {
10
+ return variant.version ?? currentVersionOf(item);
11
+ }
12
+ /**
13
+ * Versions in display order: the one under review first, then the others
14
+ * in the order the publisher listed them (review-kit puts the newest first).
15
+ * Fewer than two distinct versions → [] (no switcher; render as before).
16
+ */
17
+ export function versionsOf(item) {
18
+ const cur = currentVersionOf(item);
19
+ if (!cur)
20
+ return [];
21
+ const seen = [cur];
22
+ for (const v of item.variants) {
23
+ const ver = v.version ?? cur;
24
+ if (!seen.includes(ver))
25
+ seen.push(ver);
26
+ }
27
+ return seen.length > 1 ? seen : [];
28
+ }
29
+ /** The views (variants) of one version; with no versions, every variant. */
30
+ export function viewsOf(item, version) {
31
+ if (versionsOf(item).length === 0 || version == null)
32
+ return item.variants;
33
+ return item.variants.filter((v) => versionOfVariant(item, v) === version);
34
+ }
35
+ const KIND_VIEW = {
36
+ video: "Loop",
37
+ image: "Still",
38
+ audio: "Audio",
39
+ };
40
+ /**
41
+ * A view's human label with the redundant version prefix stripped:
42
+ * "v6" on a v6 video → "Loop"; "v6 · strip" → "strip"; "v5 (as reviewed)"
43
+ * → "Loop (as reviewed)". A label that says something else is kept as is.
44
+ */
45
+ export function cleanViewLabel(label, version, kind) {
46
+ const fallback = KIND_VIEW[kind];
47
+ let s = (label ?? "").trim();
48
+ if (version) {
49
+ const v = version.trim();
50
+ // repeat: an older spec may carry "v6 · v6"
51
+ for (let guard = 0; guard < 3 && v; guard++) {
52
+ if (s.toLowerCase() === v.toLowerCase()) {
53
+ s = "";
54
+ break;
55
+ }
56
+ if (s.toLowerCase().startsWith(v.toLowerCase())) {
57
+ const rest = s.slice(v.length);
58
+ if (/^[\s·:\-—–|/]/.test(rest) || rest.startsWith("(")) {
59
+ s = rest.replace(/^[\s·:\-—–|/]+/, "").trim();
60
+ continue;
61
+ }
62
+ }
63
+ break;
64
+ }
65
+ }
66
+ if (!s)
67
+ return fallback;
68
+ if (/^\(.*\)$/.test(s))
69
+ return `${fallback} ${s}`;
70
+ return s;
71
+ }
72
+ /** The label a view thumbnail and the caption show. */
73
+ export function viewLabel(item, variant) {
74
+ const versioned = versionsOf(item).length > 0;
75
+ const version = versioned ? versionOfVariant(item, variant) : variant.version;
76
+ return cleanViewLabel(variant.label ?? variant.id, version, variant.kind);
77
+ }
78
+ /**
79
+ * The card caption under the media:
80
+ * versioned → "v6 (reviewing) · Loop · 1 of 3" / "v5 (previous) · Loop · 1 of 1"
81
+ * flat → "1 of 4 · warm" (as before, minus a label that only repeats the version)
82
+ */
83
+ export function captionFor(item, variant, version) {
84
+ const versions = versionsOf(item);
85
+ if (versions.length > 0 && version) {
86
+ const views = viewsOf(item, version);
87
+ const idx = Math.max(0, views.findIndex((v) => v.id === variant.id));
88
+ const role = version === currentVersionOf(item) ? "reviewing" : "previous";
89
+ return `${version} (${role}) · ${viewLabel(item, variant)} · ${idx + 1} of ${views.length}`;
90
+ }
91
+ const idx = Math.max(0, item.variants.findIndex((v) => v.id === variant.id));
92
+ const head = `${idx + 1} of ${item.variants.length}`;
93
+ const raw = variant.label?.trim();
94
+ if (!raw)
95
+ return head;
96
+ const label = variant.version && raw.toLowerCase() === variant.version.toLowerCase()
97
+ ? raw
98
+ : cleanViewLabel(raw, variant.version, variant.kind);
99
+ return `${head} · ${label}`;
100
+ }
101
+ const VERDICT_WORD = {
102
+ approve: "approved",
103
+ redo: "needs work",
104
+ reject: "rejected",
105
+ };
106
+ /**
107
+ * "Your verdict then: needs work. Note: “water not natural”" (or a no-record
108
+ * line). Takes the locked round line for the version (viewer or publisher
109
+ * history, merged by ../../review/rounds.ts).
110
+ */
111
+ export function historyLine(h) {
112
+ if (!h || (!h.verdict && !h.note))
113
+ return "No verdict was recorded for this version.";
114
+ const word = h.verdict ? (VERDICT_WORD[h.verdict] ?? h.verdict) : "a note";
115
+ return h.note
116
+ ? `Your verdict then: ${word}. Note: “${h.note}”`
117
+ : `Your verdict then: ${word}`;
118
+ }
@@ -0,0 +1,213 @@
1
+ <script lang="ts">
2
+ /**
3
+ * MockupBlock — agent-authored HTML in device frames (mos-vzame).
4
+ *
5
+ * Each variant renders inside its own iframe. The iframe's sandbox
6
+ * attribute comes from mockupSandboxAttr() in ./sandbox.ts — the artifact
7
+ * sandbox's token list (a host may override it via services.sandboxAttr),
8
+ * which NEVER includes allow-same-origin (see that module for the threat
9
+ * model: opaque origin, no session, no cookies, no parent DOM). Scripts run
10
+ * only when the author passed allowScripts, and even then inside the opaque
11
+ * origin. referrerpolicy="no-referrer" mirrors ArtifactShell.
12
+ *
13
+ * The frame is a scaled viewport: the iframe is laid out at the DEVICE's
14
+ * pixel width and transform-scaled to the column, so a "desktop" mockup is
15
+ * laid out at 1440px even on a phone screen — not reflowed to column width.
16
+ * bind:clientWidth measures the wrapper; the scale correction lands on
17
+ * hydrate, so server HTML ships a sensible default.
18
+ *
19
+ * The theme toggle passes data-theme=light|dark into every fragment (see
20
+ * ./doc.ts) — the snippet's own CSS decides what the attribute means.
21
+ */
22
+ import { mockupSandboxAttr } from "./sandbox.js"
23
+ import type { BlockProps } from "../../types.js"
24
+ import { mockupDocument } from "./doc.js"
25
+ import {
26
+ MOCKUP_DIMS,
27
+ type MockupDevice,
28
+ type MockupDims,
29
+ type MockupParams,
30
+ } from "./types.js"
31
+ import SectionTools from "../../SectionTools.svelte"
32
+
33
+ let { params, ctx }: BlockProps<MockupParams> = $props()
34
+
35
+ let theme = $state<"light" | "dark">("light")
36
+ /** Measured on-screen width of each frame's viewport, by variant id. */
37
+ let frameWidths = $state<Record<string, number>>({})
38
+
39
+ const sandbox = $derived(
40
+ mockupSandboxAttr(params.allowScripts === true, ctx?.services?.sandboxAttr),
41
+ )
42
+
43
+ /**
44
+ * Normalize any device value to a real MockupDevice (mos-659rz): the
45
+ * schema now guarantees a variant carries one, but a stale or malformed
46
+ * params object (history restored, a value the schema once accepted) must
47
+ * render a frame — anything unknown falls back to desktop, never to
48
+ * MOCKUP_DIMS[undefined].maxFrameW.
49
+ */
50
+ function deviceOf(device: unknown): MockupDevice {
51
+ return typeof device === "string" && device in MOCKUP_DIMS
52
+ ? (device as MockupDevice)
53
+ : "desktop"
54
+ }
55
+
56
+ /** Device dims — never undefined (mos-659rz): an unknown value falls back
57
+ * to desktop dims instead of crashing on `.maxFrameW`. */
58
+ function dims(device: unknown): MockupDims {
59
+ return MOCKUP_DIMS[deviceOf(device)] ?? MOCKUP_DIMS.desktop
60
+ }
61
+
62
+ /** device px → screen px for this frame (falls back to the frame cap). */
63
+ function scale(id: string, device: unknown): number {
64
+ const d = dims(device)
65
+ const measured = frameWidths[id]
66
+ const w = measured && measured > 0 ? measured : d.maxFrameW
67
+ return w / d.w
68
+ }
69
+
70
+ function frameStyle(id: string, device: unknown): string {
71
+ const d = dims(device)
72
+ return `max-width:${d.maxFrameW}px;aspect-ratio:${d.w}/${d.h};`
73
+ }
74
+ </script>
75
+
76
+ <section
77
+ class="border-base-content/10 bg-base-100 rounded-box border"
78
+ aria-label={params.title ?? "Mockup"}
79
+ >
80
+ <header
81
+ class="flex flex-wrap items-center gap-x-3 gap-y-2 px-4 pt-4 pb-1 sm:px-5"
82
+ >
83
+ <div class="min-w-0 flex-1">
84
+ {#if params.title}
85
+ <h2 class="text-lg font-semibold tracking-tight">{params.title}</h2>
86
+ {/if}
87
+ {#if params.intro}
88
+ <p class="text-base-content/60 mt-0.5 text-sm whitespace-pre-line">
89
+ {params.intro}
90
+ </p>
91
+ {/if}
92
+ </div>
93
+ <!-- Light / dark toggle: re-wraps every fragment with data-theme -->
94
+ <div
95
+ class="flex items-center gap-1"
96
+ role="group"
97
+ aria-label="Preview theme"
98
+ >
99
+ <button
100
+ type="button"
101
+ class="btn btn-xs rounded-field {theme === 'light'
102
+ ? 'btn-primary'
103
+ : 'border-base-content/10 bg-transparent text-base-content/70'}"
104
+ aria-pressed={theme === "light"}
105
+ onclick={() => (theme = "light")}
106
+ >
107
+ Light
108
+ </button>
109
+ <button
110
+ type="button"
111
+ class="btn btn-xs rounded-field {theme === 'dark'
112
+ ? 'btn-primary'
113
+ : 'border-base-content/10 bg-transparent text-base-content/70'}"
114
+ aria-pressed={theme === "dark"}
115
+ onclick={() => (theme = "dark")}
116
+ >
117
+ Dark
118
+ </button>
119
+ </div>
120
+ <SectionTools {ctx} inline />
121
+ </header>
122
+
123
+ <div class="flex flex-wrap items-start gap-5 px-4 pt-2 pb-5 sm:px-5">
124
+ {#each params.variants as v (v.id)}
125
+ {@const dev = deviceOf(v.device)}
126
+ {@const d = dims(dev)}
127
+ {@const s = scale(v.id, dev)}
128
+ <figure class="m-0">
129
+ <!-- Frame chrome per device; the viewport inside is the scaled iframe. -->
130
+ <div
131
+ class="relative mx-auto"
132
+ style={frameStyle(v.id, dev)}
133
+ bind:clientWidth={frameWidths[v.id]}
134
+ >
135
+ {#if dev === "desktop"}
136
+ <!-- Browser chrome -->
137
+ <div
138
+ class="border-base-content/15 bg-base-200 rounded-box overflow-hidden border"
139
+ style="height:100%"
140
+ >
141
+ <div
142
+ class="border-base-content/10 flex items-center gap-2 border-b px-3 py-1.5"
143
+ >
144
+ <span class="flex gap-1" aria-hidden="true">
145
+ <span class="bg-error size-2 rounded-full"></span>
146
+ <span class="bg-warning size-2 rounded-full"></span>
147
+ <span class="bg-success size-2 rounded-full"></span>
148
+ </span>
149
+ <span
150
+ class="bg-base-100 border-base-content/10 text-base-content/50 mx-auto rounded-field max-w-[60%] flex-1 truncate px-2 py-0.5 text-center text-2xs"
151
+ aria-hidden="true"
152
+ >
153
+ {v.label ?? v.id}
154
+ </span>
155
+ </div>
156
+ <iframe
157
+ data-mock-id={v.id}
158
+ srcdoc={mockupDocument(v.html, theme)}
159
+ {sandbox}
160
+ title="{v.label ?? v.id} — desktop preview"
161
+ referrerpolicy="no-referrer"
162
+ loading="lazy"
163
+ style="width:{d.w}px;height:{d.h -
164
+ 30 / s}px;transform:scale({s});transform-origin:0 0;border:0;"
165
+ ></iframe>
166
+ </div>
167
+ {:else}
168
+ <!-- Phone / tablet chrome: bezel + notch or camera dot -->
169
+ <div
170
+ class="bg-base-300 border-base-content/15 relative h-full overflow-hidden {dev ===
171
+ 'phone'
172
+ ? 'rounded-[2.25rem] border-[6px]'
173
+ : 'rounded-[1.5rem] border-[8px]'}"
174
+ >
175
+ <span
176
+ class="bg-base-content/20 absolute top-2 left-1/2 h-1.5 w-16 -translate-x-1/2 rounded-full {dev ===
177
+ 'tablet'
178
+ ? 'hidden'
179
+ : ''}"
180
+ aria-hidden="true"
181
+ ></span>
182
+ <span
183
+ class="bg-base-content/20 absolute top-2.5 left-3 size-1.5 rounded-full {dev ===
184
+ 'phone'
185
+ ? 'hidden'
186
+ : ''}"
187
+ aria-hidden="true"
188
+ ></span>
189
+ <iframe
190
+ data-mock-id={v.id}
191
+ srcdoc={mockupDocument(v.html, theme)}
192
+ {sandbox}
193
+ title="{v.label ?? v.id} — {dev} preview"
194
+ referrerpolicy="no-referrer"
195
+ loading="lazy"
196
+ style="width:{d.w}px;height:{d.h}px;transform:scale({s});transform-origin:0 0;border:0;"
197
+ ></iframe>
198
+ </div>
199
+ {/if}
200
+ </div>
201
+ <figcaption
202
+ class="text-base-content/60 mt-1.5 text-center text-xs tabular-nums"
203
+ >
204
+ {v.label ?? v.id}
205
+ <span class="text-base-content/40">
206
+ &middot; {dev}
207
+ {d.w}&times;{d.h}
208
+ </span>
209
+ </figcaption>
210
+ </figure>
211
+ {/each}
212
+ </div>
213
+ </section>
@@ -0,0 +1,5 @@
1
+ import type { BlockProps } from "../../types.js";
2
+ import { type MockupParams } from "./types.js";
3
+ declare const MockupBlock: import("svelte").Component<BlockProps<MockupParams>, {}, "">;
4
+ type MockupBlock = ReturnType<typeof MockupBlock>;
5
+ export default MockupBlock;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * mockup — agent-authored HTML shown in device frames (mos-vzame, epic
3
+ * mos-m1qrx).
4
+ *
5
+ * Params are DATA: one or more variants, each an HTML snippet rendered
6
+ * verbatim inside a sandboxed iframe shaped like a phone, tablet, or desktop
7
+ * frame. The iframe's sandbox attribute comes from
8
+ * `artifactSandboxAttr()` in src/lib/modules/artifacts/sandbox.ts — the same
9
+ * token list the html artifact viewer's CSP header serves — and
10
+ * allow-same-origin is NEVER emitted: the frame is an opaque origin with no
11
+ * session, no cookies, no parent DOM (see that module for the threat model).
12
+ * Scripts stay off unless `allowScripts` is true, and even then they run in
13
+ * the opaque origin only.
14
+ *
15
+ * The light/dark toggle re-wraps fragments with `data-theme` on <html> (see
16
+ * ./doc.ts); the snippet's own CSS decides what that attribute means.
17
+ *
18
+ * Use it when the artifact IS a design artifact: a homepage concept, a
19
+ * component state exploration, an email template. One-line tip: publish each
20
+ * design option as its own variant (side by side) rather than a separate
21
+ * block per option — reviewers compare them at a glance.
22
+ */
23
+ import type { ArtifactBlockDef } from "../../types.js";
24
+ import type { MockupParams } from "./types.js";
25
+ declare const mockup: ArtifactBlockDef<MockupParams>;
26
+ export default mockup;
@@ -0,0 +1,52 @@
1
+ import { mockupSchema } from "./schema.js";
2
+ import MockupBlock from "./MockupBlock.svelte";
3
+ const example = {
4
+ title: "Checkout — concept A/B",
5
+ intro: "Same flow, two treatments. Toggle the theme to check both.",
6
+ variants: [
7
+ {
8
+ id: "a-phone",
9
+ label: "Concept A",
10
+ device: "phone",
11
+ html: `<main style="font:16px/1.5 system-ui;padding:24px">
12
+ <h1 style="font-size:20px;margin:0 0 8px">Checkout</h1>
13
+ <p style="margin:0 0 16px;color:#666">Concept A — single column</p>
14
+ <div style="height:44px;border-radius:12px;background:#eee"></div>
15
+ </main>`,
16
+ },
17
+ {
18
+ id: "b-phone",
19
+ label: "Concept B",
20
+ device: "phone",
21
+ html: `<main style="font:16px/1.5 system-ui;padding:24px">
22
+ <h1 style="font-size:20px;margin:0 0 8px">Checkout</h1>
23
+ <p style="margin:0 0 16px;color:#666">Concept B — summary card</p>
24
+ <div style="height:44px;border-radius:12px;background:#ddd"></div>
25
+ </main>`,
26
+ },
27
+ {
28
+ id: "a-desktop",
29
+ label: "Concept A · desktop",
30
+ device: "desktop",
31
+ html: `<main style="font:16px/1.5 system-ui;padding:48px;max-width:960px">
32
+ <h1 style="font-size:28px;margin:0 0 12px">Checkout — desktop</h1>
33
+ <div style="display:flex;gap:24px">
34
+ <div style="flex:1;height:180px;border-radius:12px;background:#eee"></div>
35
+ <div style="width:280px;height:180px;border-radius:12px;background:#ddd"></div>
36
+ </div>
37
+ </main>`,
38
+ },
39
+ ],
40
+ };
41
+ const mockup = {
42
+ type: "mockup",
43
+ title: "Mockup (sandboxed HTML in device frames)",
44
+ description: "Renders agent-authored HTML snippets inside phone, tablet, or desktop device frames — the way to put a UI concept into an artifact WITHOUT giving that HTML the page's origin: each variant is an iframe whose sandbox attribute comes from the artifact sandbox module (opaque origin, allow-same-origin never emitted, scripts only when allowScripts is true), so the mockup can never touch the session. Pass a FRAGMENT per variant; the block wraps it and drives data-theme=light|dark on <html> so the block-level theme toggle re-skins designs that honor the attribute (a full document passes through unwrapped and owns its own theming). Variants render side by side for A/B comparison. A top-level `device` param is shorthand: it becomes the device of every variant that does not name its own (a variant's own device wins); a variant without any device defaults to phone. Budget: 48KB of HTML per variant, 256KB for the whole block. One-line tip: name variant ids after the option they show (a-phone, b-phone) — reviewers reference them in notes.",
45
+ schema: mockupSchema,
46
+ component: MockupBlock,
47
+ // mos-8fvt9: the section's Listen + comment sit on the heading row.
48
+ hostsTools: () => true,
49
+ example,
50
+ reviewableByDefault: true,
51
+ };
52
+ export default mockup;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The sandboxed document a mockup iframe renders (mos-vzame).
3
+ *
4
+ * The iframe gets its sandbox from artifactSandboxAttr() in
5
+ * src/lib/modules/artifacts/sandbox.ts — the same token list the html
6
+ * artifact viewer serves under its `Content-Security-Policy: sandbox` header.
7
+ * allow-same-origin is absent in every mode that helper can emit; the frame
8
+ * is an opaque origin and can never reach the app session, cookies, or DOM.
9
+ * That helper is the single source of truth for the boundary — this file only
10
+ * decides WHAT the opaque-origin document contains.
11
+ *
12
+ * The light/dark toggle works by re-wrapping the snippet with `data-theme` on
13
+ * the <html> element — the author's CSS decides what that attribute means
14
+ * (DaisyUI themes, Tailwind `dark:` with a data-theme selector, hand CSS).
15
+ * A full document (one that already has <html>) passes through untouched:
16
+ * rewriting untrusted markup by regex is exactly the fragility this block
17
+ * refuses; authors who bring their own document own their own theming.
18
+ */
19
+ /**
20
+ * Wrap a mockup snippet into a full document carrying `data-theme`. A
21
+ * fragment gets the wrapper (body margin 0 — a mockup is full-bleed); a
22
+ * document that already brings `<html>` passes through verbatim.
23
+ */
24
+ export declare function mockupDocument(html: string, theme: "light" | "dark"): string;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The sandboxed document a mockup iframe renders (mos-vzame).
3
+ *
4
+ * The iframe gets its sandbox from artifactSandboxAttr() in
5
+ * src/lib/modules/artifacts/sandbox.ts — the same token list the html
6
+ * artifact viewer serves under its `Content-Security-Policy: sandbox` header.
7
+ * allow-same-origin is absent in every mode that helper can emit; the frame
8
+ * is an opaque origin and can never reach the app session, cookies, or DOM.
9
+ * That helper is the single source of truth for the boundary — this file only
10
+ * decides WHAT the opaque-origin document contains.
11
+ *
12
+ * The light/dark toggle works by re-wrapping the snippet with `data-theme` on
13
+ * the <html> element — the author's CSS decides what that attribute means
14
+ * (DaisyUI themes, Tailwind `dark:` with a data-theme selector, hand CSS).
15
+ * A full document (one that already has <html>) passes through untouched:
16
+ * rewriting untrusted markup by regex is exactly the fragility this block
17
+ * refuses; authors who bring their own document own their own theming.
18
+ */
19
+ const WRAPPER_HEAD = `<!doctype html>
20
+ <html lang="en" data-theme="THEME">
21
+ <head>
22
+ <meta charset="utf-8">
23
+ <meta name="viewport" content="width=device-width, initial-scale=1">
24
+ <style>
25
+ html[data-theme="light"] { color-scheme: light; }
26
+ html[data-theme="dark"] { color-scheme: dark; }
27
+ body { margin: 0; padding: 0; }
28
+ </style>
29
+ </head>
30
+ <body>
31
+ `;
32
+ const WRAPPER_TAIL = `
33
+ </body>
34
+ </html>`;
35
+ /**
36
+ * Wrap a mockup snippet into a full document carrying `data-theme`. A
37
+ * fragment gets the wrapper (body margin 0 — a mockup is full-bleed); a
38
+ * document that already brings `<html>` passes through verbatim.
39
+ */
40
+ export function mockupDocument(html, theme) {
41
+ if (/<html[\s>]/i.test(html))
42
+ return html;
43
+ return `${WRAPPER_HEAD.replace("THEME", theme)}${html}${WRAPPER_TAIL}`;
44
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The mockup frame's `sandbox` attribute (origin: MOS
3
+ * src/lib/modules/artifacts/sandbox.ts artifactSandboxAttr, bad16b324).
4
+ *
5
+ * Each variant is agent-authored HTML in an iframe `srcdoc`. The sandbox puts
6
+ * it in an OPAQUE origin: no session, no cookies, no parent DOM. That only
7
+ * holds while `allow-same-origin` is absent — srcdoc with scripts +
8
+ * same-origin is the one combination that defeats it — so this module never
9
+ * emits it, and strips it from a host override too.
10
+ *
11
+ * `allow-popups` + `allow-popups-to-escape-sandbox`: a link in a mockup that
12
+ * opens a new tab lands on a normal page, not a sandboxed one. Scripts run
13
+ * only when the author passed `allowScripts`.
14
+ *
15
+ * A host may widen or narrow the token list with `services.sandboxAttr`
16
+ * (a string, or a function of allowScripts); `allow-same-origin` is removed
17
+ * from whatever it returns, and `allow-scripts` is removed unless the author
18
+ * asked for scripts.
19
+ */
20
+ export type SandboxAttrService = string | ((allowScripts: boolean) => string);
21
+ export declare function mockupSandboxAttr(allowScripts: boolean, override?: unknown): string;
@@ -0,0 +1,27 @@
1
+ const FORBIDDEN = new Set(["allow-same-origin"]);
2
+ export function mockupSandboxAttr(allowScripts, override) {
3
+ let raw;
4
+ if (typeof override === "function") {
5
+ const v = override(allowScripts);
6
+ raw = typeof v === "string" ? v : defaultTokens(allowScripts);
7
+ }
8
+ else if (typeof override === "string") {
9
+ raw = override;
10
+ }
11
+ else {
12
+ raw = defaultTokens(allowScripts);
13
+ }
14
+ const tokens = raw
15
+ .split(/\s+/)
16
+ .map((t) => t.trim().toLowerCase())
17
+ .filter(Boolean)
18
+ .filter((t) => !FORBIDDEN.has(t))
19
+ .filter((t) => allowScripts || t !== "allow-scripts");
20
+ return [...new Set(tokens)].join(" ");
21
+ }
22
+ function defaultTokens(allowScripts) {
23
+ const tokens = ["allow-popups", "allow-popups-to-escape-sandbox"];
24
+ if (allowScripts)
25
+ tokens.push("allow-scripts");
26
+ return tokens.join(" ");
27
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Params schema for the mockup block (agent HTML in sandboxed device frames).
3
+ * Imported by block.ts (def) and the tests — keeps them cycle-free.
4
+ */
5
+ import { z } from "zod";
6
+ import type { MockupParams } from "./types.js";
7
+ export declare const mockupSchema: z.ZodType<MockupParams>;