@hanzo/ui 8.27.15 → 8.27.16

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 (178) hide show
  1. package/NOTICE +19 -0
  2. package/dist/agents/Attachments.cjs +29 -0
  3. package/dist/agents/Attachments.d.ts +31 -0
  4. package/dist/agents/Attachments.d.ts.map +1 -0
  5. package/dist/agents/Attachments.js +27 -0
  6. package/dist/agents/Attachments.js.map +1 -0
  7. package/dist/agents/Choice.cjs +47 -0
  8. package/dist/agents/Choice.d.ts +34 -0
  9. package/dist/agents/Choice.d.ts.map +1 -0
  10. package/dist/agents/Choice.js +44 -0
  11. package/dist/agents/Choice.js.map +1 -0
  12. package/dist/agents/Console.cjs +106 -0
  13. package/dist/agents/Console.d.ts +54 -0
  14. package/dist/agents/Console.d.ts.map +1 -0
  15. package/dist/agents/Console.js +104 -0
  16. package/dist/agents/Console.js.map +1 -0
  17. package/dist/agents/Feedback.cjs +50 -0
  18. package/dist/agents/Feedback.d.ts +25 -0
  19. package/dist/agents/Feedback.d.ts.map +1 -0
  20. package/dist/agents/Feedback.js +48 -0
  21. package/dist/agents/Feedback.js.map +1 -0
  22. package/dist/agents/FileTabs.cjs +63 -0
  23. package/dist/agents/FileTabs.d.ts +45 -0
  24. package/dist/agents/FileTabs.d.ts.map +1 -0
  25. package/dist/agents/FileTabs.js +61 -0
  26. package/dist/agents/FileTabs.js.map +1 -0
  27. package/dist/agents/FileTree.cjs +160 -0
  28. package/dist/agents/FileTree.d.ts +41 -0
  29. package/dist/agents/FileTree.d.ts.map +1 -0
  30. package/dist/agents/FileTree.js +157 -0
  31. package/dist/agents/FileTree.js.map +1 -0
  32. package/dist/agents/PreviewFrame.cjs +108 -0
  33. package/dist/agents/PreviewFrame.d.ts +78 -0
  34. package/dist/agents/PreviewFrame.d.ts.map +1 -0
  35. package/dist/agents/PreviewFrame.js +105 -0
  36. package/dist/agents/PreviewFrame.js.map +1 -0
  37. package/dist/agents/Suggestions.cjs +29 -0
  38. package/dist/agents/Suggestions.d.ts +28 -0
  39. package/dist/agents/Suggestions.d.ts.map +1 -0
  40. package/dist/agents/Suggestions.js +26 -0
  41. package/dist/agents/Suggestions.js.map +1 -0
  42. package/dist/agents/Workspace.cjs +103 -0
  43. package/dist/agents/Workspace.d.ts +104 -0
  44. package/dist/agents/Workspace.d.ts.map +1 -0
  45. package/dist/agents/Workspace.js +98 -0
  46. package/dist/agents/Workspace.js.map +1 -0
  47. package/dist/agents/bridge.cjs +201 -0
  48. package/dist/agents/bridge.d.ts +102 -0
  49. package/dist/agents/bridge.d.ts.map +1 -0
  50. package/dist/agents/bridge.js +197 -0
  51. package/dist/agents/bridge.js.map +1 -0
  52. package/dist/agents/index.cjs +64 -1
  53. package/dist/agents/index.d.ts +23 -0
  54. package/dist/agents/index.d.ts.map +1 -1
  55. package/dist/agents/index.js +23 -0
  56. package/dist/agents/index.js.map +1 -1
  57. package/dist/agents/log.cjs +75 -0
  58. package/dist/agents/log.d.ts +58 -0
  59. package/dist/agents/log.d.ts.map +1 -0
  60. package/dist/agents/log.js +65 -0
  61. package/dist/agents/log.js.map +1 -0
  62. package/dist/agents/tree.cjs +238 -0
  63. package/dist/agents/tree.d.ts +99 -0
  64. package/dist/agents/tree.d.ts.map +1 -0
  65. package/dist/agents/tree.js +226 -0
  66. package/dist/agents/tree.js.map +1 -0
  67. package/dist/backends/gui/3d-card.d.ts +6 -6
  68. package/dist/backends/gui/3d-marquee.d.ts +7 -8
  69. package/dist/backends/gui/3d-marquee.d.ts.map +1 -1
  70. package/dist/backends/gui/3d-pin.d.ts +1 -1
  71. package/dist/backends/gui/alert.d.ts +3 -3
  72. package/dist/backends/gui/android.d.ts +1 -1
  73. package/dist/backends/gui/animated-testimonials.d.ts +1 -1
  74. package/dist/backends/gui/animated-tooltip.d.ts +1 -1
  75. package/dist/backends/gui/announcement.d.ts +1 -1
  76. package/dist/backends/gui/banner.d.ts +1 -1
  77. package/dist/backends/gui/button.d.ts +1 -1
  78. package/dist/backends/gui/card.d.ts +7 -7
  79. package/dist/backends/gui/code-editor.cjs +2 -2
  80. package/dist/backends/gui/code-editor.d.ts +7 -1
  81. package/dist/backends/gui/code-editor.d.ts.map +1 -1
  82. package/dist/backends/gui/code-editor.js +2 -2
  83. package/dist/backends/gui/code-editor.js.map +1 -1
  84. package/dist/backends/gui/command.d.ts +5 -5
  85. package/dist/backends/gui/command.d.ts.map +1 -1
  86. package/dist/backends/gui/context-menu.d.ts +14 -14
  87. package/dist/backends/gui/context-menu.d.ts.map +1 -1
  88. package/dist/backends/gui/credit-card.d.ts +1 -1
  89. package/dist/backends/gui/desktop.d.ts +1 -1
  90. package/dist/backends/gui/dock.d.ts +3 -3
  91. package/dist/backends/gui/dropdown-menu.d.ts +16 -16
  92. package/dist/backends/gui/dropdown-menu.d.ts.map +1 -1
  93. package/dist/backends/gui/empty.d.ts +6 -6
  94. package/dist/backends/gui/field.d.ts +3 -3
  95. package/dist/backends/gui/gantt.d.ts +1 -1
  96. package/dist/backends/gui/grid-pattern.d.ts +1 -2
  97. package/dist/backends/gui/grid-pattern.d.ts.map +1 -1
  98. package/dist/backends/gui/image-zoom.d.ts +1 -1
  99. package/dist/backends/gui/iphone-15-pro.d.ts +1 -1
  100. package/dist/backends/gui/item.d.ts +9 -9
  101. package/dist/backends/gui/list.d.ts +2 -2
  102. package/dist/backends/gui/macos-dock.d.ts +2 -2
  103. package/dist/backends/gui/magnetic.d.ts +1 -1
  104. package/dist/backends/gui/marquee.d.ts +1 -15
  105. package/dist/backends/gui/marquee.d.ts.map +1 -1
  106. package/dist/backends/gui/menu-dock.d.ts +1 -1
  107. package/dist/backends/gui/menubar.d.ts +15 -15
  108. package/dist/backends/gui/menubar.d.ts.map +1 -1
  109. package/dist/backends/gui/message-dock.d.ts +1 -1
  110. package/dist/backends/gui/motion-highlight.d.ts +1 -12
  111. package/dist/backends/gui/motion-highlight.d.ts.map +1 -1
  112. package/dist/backends/gui/pagination.d.ts +4 -4
  113. package/dist/backends/gui/qr-code.d.ts +1 -2
  114. package/dist/backends/gui/qr-code.d.ts.map +1 -1
  115. package/dist/backends/gui/scroll-area.d.ts +3 -14
  116. package/dist/backends/gui/scroll-area.d.ts.map +1 -1
  117. package/dist/backends/gui/sheet.d.ts +3 -3
  118. package/dist/backends/gui/sheet.d.ts.map +1 -1
  119. package/dist/backends/gui/status.d.ts +1 -1
  120. package/dist/backends/gui/table.d.ts +8 -8
  121. package/dist/backends/gui/toaster.d.ts +1 -15
  122. package/dist/backends/gui/toaster.d.ts.map +1 -1
  123. package/dist/backends/gui/toggle.d.ts +1 -1
  124. package/dist/backends/gui/video-player.d.ts +1 -1
  125. package/dist/chat/Composer.cjs +60 -9
  126. package/dist/chat/Composer.d.ts +42 -2
  127. package/dist/chat/Composer.d.ts.map +1 -1
  128. package/dist/chat/Composer.js +61 -11
  129. package/dist/chat/Composer.js.map +1 -1
  130. package/dist/chat/EmptyPrompt.cjs +27 -0
  131. package/dist/chat/EmptyPrompt.d.ts +30 -0
  132. package/dist/chat/EmptyPrompt.d.ts.map +1 -0
  133. package/dist/chat/EmptyPrompt.js +24 -0
  134. package/dist/chat/EmptyPrompt.js.map +1 -0
  135. package/dist/chat/SessionRail.cjs +97 -0
  136. package/dist/chat/SessionRail.d.ts +97 -0
  137. package/dist/chat/SessionRail.d.ts.map +1 -0
  138. package/dist/chat/SessionRail.js +94 -0
  139. package/dist/chat/SessionRail.js.map +1 -0
  140. package/dist/chat/Thread.d.ts +2 -8
  141. package/dist/chat/Thread.d.ts.map +1 -1
  142. package/dist/chat/index.cjs +8 -1
  143. package/dist/chat/index.d.ts +3 -1
  144. package/dist/chat/index.d.ts.map +1 -1
  145. package/dist/chat/index.js +3 -1
  146. package/dist/chat/index.js.map +1 -1
  147. package/dist/gallery.cjs +28 -1
  148. package/dist/gallery.d.ts.map +1 -1
  149. package/dist/gallery.html +71 -3
  150. package/dist/gallery.js +30 -3
  151. package/dist/gallery.js.map +1 -1
  152. package/dist/product/BranchSelect.cjs +27 -0
  153. package/dist/product/BranchSelect.d.ts +27 -0
  154. package/dist/product/BranchSelect.d.ts.map +1 -0
  155. package/dist/product/BranchSelect.js +23 -0
  156. package/dist/product/BranchSelect.js.map +1 -0
  157. package/dist/product/ChipSelect.cjs +267 -0
  158. package/dist/product/ChipSelect.d.ts +71 -0
  159. package/dist/product/ChipSelect.d.ts.map +1 -0
  160. package/dist/product/ChipSelect.js +265 -0
  161. package/dist/product/ChipSelect.js.map +1 -0
  162. package/dist/product/RepoSelect.cjs +75 -0
  163. package/dist/product/RepoSelect.d.ts +63 -0
  164. package/dist/product/RepoSelect.d.ts.map +1 -0
  165. package/dist/product/RepoSelect.js +69 -0
  166. package/dist/product/RepoSelect.js.map +1 -0
  167. package/dist/product/chipSelect.logic.cjs +147 -0
  168. package/dist/product/chipSelect.logic.d.ts +92 -0
  169. package/dist/product/chipSelect.logic.d.ts.map +1 -0
  170. package/dist/product/chipSelect.logic.js +138 -0
  171. package/dist/product/chipSelect.logic.js.map +1 -0
  172. package/dist/product/index.cjs +23 -1
  173. package/dist/product/index.d.ts +4 -0
  174. package/dist/product/index.d.ts.map +1 -1
  175. package/dist/product/index.js +7 -0
  176. package/dist/product/index.js.map +1 -1
  177. package/dist/styles.css +68 -0
  178. package/package.json +2 -1
@@ -0,0 +1,157 @@
1
+ 'use client';
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * FileTree — a repository's files, folders first, one level read at a time.
5
+ *
6
+ * Ported from build-v2 `components/editor/file-tree/{index,glyph}.tsx` (MIT,
7
+ * derived from OSW Studio and DeepSite — see NOTICE). v2 listed a site's pages
8
+ * and let you add, rename and delete them; a repository's files change by runs
9
+ * that commit, so this tree reads and selects and does nothing else.
10
+ *
11
+ * Two ways in, one renderer (`tree.ts`):
12
+ * files every path at once — a flat list the tree groups itself;
13
+ * load one directory per call, the way a repository answers (`''` is the
14
+ * root), read the first time a folder opens and kept after.
15
+ *
16
+ * Names are TEXT. A path comes from a repository somebody else wrote, so it is
17
+ * drawn as a string and never interpreted as markup.
18
+ *
19
+ * Keyboard and roles are the WAI-ARIA tree: one tab stop, arrows move and open,
20
+ * Enter picks. The decisions are `step()` in `tree.ts`; this only applies them.
21
+ */
22
+ import { ScrollView, SizableText, XStack, YStack } from '@hanzo/gui';
23
+ import { Braces, ChevronDown, ChevronRight, FileCode2, FileJson, FileText, FileType, Folder, FolderOpen, Hash, Image, Settings2, } from '@hanzogui/lucide-icons-2';
24
+ import { useEffect, useMemo, useRef, useState, } from 'react';
25
+ import { slot } from '../backends/gui/slot.js';
26
+ import { ancestors, group, put, rows, step } from './tree.js';
27
+ /**
28
+ * A file's icon, from its extension. The glyph varies and the colour does not:
29
+ * the chrome is monochrome and colour means state (live, failed), so a green
30
+ * `.env` would say "healthy" in a vocabulary that already means something.
31
+ */
32
+ const BY_EXTENSION = {
33
+ html: FileCode2,
34
+ htm: FileCode2,
35
+ css: Hash,
36
+ scss: Hash,
37
+ js: Braces,
38
+ mjs: Braces,
39
+ cjs: Braces,
40
+ jsx: Braces,
41
+ ts: FileType,
42
+ tsx: FileType,
43
+ json: FileJson,
44
+ md: FileText,
45
+ mdx: FileText,
46
+ txt: FileText,
47
+ svg: Image,
48
+ png: Image,
49
+ jpg: Image,
50
+ jpeg: Image,
51
+ gif: Image,
52
+ webp: Image,
53
+ ico: Image,
54
+ toml: Settings2,
55
+ yml: Settings2,
56
+ yaml: Settings2,
57
+ env: Settings2,
58
+ };
59
+ /** A file's icon, drawn. `.env` splits to `['', 'env']`, so the last segment is the extension. */
60
+ export function glyph(name, size = 14) {
61
+ const ext = name.split('.').pop()?.toLowerCase() ?? '';
62
+ const Icon = BY_EXTENSION[ext] ?? FileText;
63
+ return _jsx(Icon, { size: size });
64
+ }
65
+ export function FileTree({ files, load, value = null, onSelect, label = 'Files', empty, ...rest }) {
66
+ const [loaded, setLoaded] = useState(() => new Map());
67
+ const [reads, setReads] = useState(() => new Map());
68
+ const [open, setOpen] = useState(() => new Set(value ? ancestors(value) : []));
69
+ const [focus, setFocus] = useState(0);
70
+ const items = useRef([]);
71
+ const asked = useRef(new Set());
72
+ const listing = useMemo(() => (files ? group([...files]) : loaded), [files, loaded]);
73
+ const read = (dir) => {
74
+ if (!load || asked.current.has(dir))
75
+ return;
76
+ asked.current.add(dir);
77
+ setReads((m) => new Map(m).set(dir, 'loading'));
78
+ load(dir).then((entries) => {
79
+ setLoaded((l) => put(l, dir, entries));
80
+ setReads((m) => {
81
+ const next = new Map(m);
82
+ next.delete(dir);
83
+ return next;
84
+ });
85
+ }, (e) => {
86
+ asked.current.delete(dir);
87
+ setReads((m) => new Map(m).set(dir, { error: e instanceof Error ? e.message : 'Could not read this folder' }));
88
+ });
89
+ };
90
+ // The root, and every folder above the chosen file, as soon as there is a
91
+ // way to read them. Revealing the selection is the tree's job: a file opened
92
+ // from elsewhere must not be "selected" inside a folder nobody opened.
93
+ useEffect(() => {
94
+ if (!load)
95
+ return;
96
+ read('');
97
+ for (const dir of value ? ancestors(value) : [])
98
+ read(dir);
99
+ // eslint-disable-next-line react-hooks/exhaustive-deps
100
+ }, [load, value]);
101
+ useEffect(() => {
102
+ if (!value)
103
+ return;
104
+ const reveal = ancestors(value);
105
+ if (reveal.length)
106
+ setOpen((o) => (reveal.every((d) => o.has(d)) ? o : new Set([...o, ...reveal])));
107
+ }, [value]);
108
+ const list = useMemo(() => rows(listing, open), [listing, open]);
109
+ const at = Math.min(focus, Math.max(list.length - 1, 0));
110
+ const toggle = (dir) => {
111
+ const opening = !open.has(dir);
112
+ setOpen((o) => {
113
+ const next = new Set(o);
114
+ if (opening)
115
+ next.add(dir);
116
+ else
117
+ next.delete(dir);
118
+ return next;
119
+ });
120
+ if (opening)
121
+ read(dir);
122
+ };
123
+ const keyed = (e) => {
124
+ const move = step(list, at, e.key);
125
+ if (!move)
126
+ return;
127
+ e.preventDefault();
128
+ if (move.toggle)
129
+ toggle(move.toggle);
130
+ if (move.pick)
131
+ onSelect?.(move.pick);
132
+ setFocus(move.focus);
133
+ items.current[move.focus]?.focus();
134
+ };
135
+ const root = reads.get('');
136
+ if (list.length === 0) {
137
+ return (_jsx(YStack, { ...slot('file-tree'), flex: 1, minH: 0, items: "center", justify: "center", p: "$4", ...rest, children: _jsx(SizableText, { size: "$2", color: "$soft", text: "center", children: root === 'loading'
138
+ ? 'Reading files…'
139
+ : root && typeof root === 'object'
140
+ ? root.error
141
+ : (empty ?? 'No files yet.') }) }));
142
+ }
143
+ return (_jsx(ScrollView, { ...slot('file-tree'), flex: 1, minH: 0, ...rest, children: _jsx(YStack, { role: "tree", "aria-label": label, py: "$1.5", px: "$1.5", onKeyDown: keyed, children: list.map((row, index) => (_jsx(Item, { row: row, index: index, size: list.length, focused: index === at, chosen: row.kind === 'file' && row.path === value, state: row.kind === 'dir' && row.open ? reads.get(row.path) : undefined, onRef: (el) => {
144
+ items.current[index] = el;
145
+ }, onPress: () => {
146
+ setFocus(index);
147
+ if (row.kind === 'dir')
148
+ toggle(row.path);
149
+ else
150
+ onSelect?.(row.path);
151
+ } }, `${row.kind}:${row.path}`))) }) }));
152
+ }
153
+ function Item({ row, index, size, focused, chosen, state, onRef, onPress, }) {
154
+ const dir = row.kind === 'dir';
155
+ return (_jsxs(_Fragment, { children: [_jsxs(XStack, { ref: onRef, role: "treeitem", "aria-level": row.depth + 1, "aria-setsize": size, "aria-posinset": index + 1, "aria-selected": chosen, ...(dir ? { 'aria-expanded': row.open } : null), tabIndex: focused ? 0 : -1, onPress: onPress, items: "center", gap: "$1.5", minH: 28, pr: "$2", rounded: "$3", cursor: "pointer", bg: chosen ? '$raised' : 'transparent', hoverStyle: { bg: chosen ? '$raised' : '$hover' }, focusVisibleStyle: { outlineWidth: 2, outlineStyle: 'solid', outlineColor: '$rim', outlineOffset: -2 }, style: { paddingLeft: 8 + row.depth * 12 }, ...{ 'data-path': row.path }, children: [dir ? (_jsxs(_Fragment, { children: [row.open ? _jsx(ChevronDown, { size: 13, opacity: 0.6 }) : _jsx(ChevronRight, { size: 13, opacity: 0.6 }), row.open ? _jsx(FolderOpen, { size: 14 }) : _jsx(Folder, { size: 14 })] })) : (_jsx(XStack, { pl: 17, items: "center", children: glyph(row.name) })), _jsx(SizableText, { size: "$2", color: chosen || dir ? '$ink' : '$quiet', numberOfLines: 1, flex: 1, minW: 0, children: row.name })] }), state ? (_jsx(SizableText, { size: "$1", color: state === 'loading' ? '$soft' : '$bad', style: { paddingLeft: 8 + (row.depth + 1) * 12 + 17 }, py: "$1", "aria-live": "polite", children: state === 'loading' ? 'Reading…' : state.error })) : null] }));
156
+ }
157
+ //# sourceMappingURL=FileTree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileTree.js","sourceRoot":"","sources":["../../src/agents/FileTree.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACpE,OAAO,EACL,MAAM,EACN,WAAW,EACX,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,UAAU,EACV,IAAI,EACJ,KAAK,EACL,SAAS,GACV,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAIL,SAAS,EACT,OAAO,EACP,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAc,KAAK,EAAgB,GAAG,EAAY,IAAI,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAI9F;;;;GAIG;AACH,MAAM,YAAY,GAAoC;IACpD,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,IAAI;IACT,IAAI,EAAE,IAAI;IACV,EAAE,EAAE,MAAM;IACV,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,EAAE,EAAE,QAAQ;IACZ,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,QAAQ;IACd,EAAE,EAAE,QAAQ;IACZ,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;CACf,CAAA;AAED,kGAAkG;AAClG,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,IAAI,GAAG,EAAE;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IACtD,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAA;IAC1C,OAAO,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,GAAI,CAAA;AAC7B,CAAC;AAkBD,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,KAAK,GAAG,IAAI,EACZ,QAAQ,EACR,KAAK,GAAG,OAAO,EACf,KAAK,EACL,GAAG,IAAI,EACO;IACd,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAU,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAA;IAC9D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAoB,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAA;IACtE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAc,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3F,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;IACrC,MAAM,KAAK,GAAG,MAAM,CAAyB,EAAE,CAAC,CAAA;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,EAAU,CAAC,CAAA;IAEvC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;IAEpF,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;QAC3B,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAM;QAC3C,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACtB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAA;QAC/C,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CACZ,CAAC,OAAO,EAAE,EAAE;YACV,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;YACtC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE;gBACb,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAA;gBACvB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBAChB,OAAO,IAAI,CAAA;YACb,CAAC,CAAC,CAAA;QACJ,CAAC,EACD,CAAC,CAAU,EAAE,EAAE;YACb,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACzB,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAA;QAChH,CAAC,CACF,CAAA;IACH,CAAC,CAAA;IAED,0EAA0E;IAC1E,6EAA6E;IAC7E,uEAAuE;IACvE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,IAAI,CAAC,EAAE,CAAC,CAAA;QACR,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;YAAE,IAAI,CAAC,GAAG,CAAC,CAAA;QAC1D,uDAAuD;IACzD,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;IAEjB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;QAC/B,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACrG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;IAChE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAExD,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE;QAC7B,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC9B,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;YACZ,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAA;YACvB,IAAI,OAAO;gBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;;gBACrB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACrB,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QACF,IAAI,OAAO;YAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,CAAC,CAAgB,EAAE,EAAE;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA;QAClC,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,CAAC,CAAC,cAAc,EAAE,CAAA;QAClB,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACpC,IAAI,IAAI,CAAC,IAAI;YAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACpC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAA;IACpC,CAAC,CAAA;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC1B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CACL,KAAC,MAAM,OAAK,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAC,QAAQ,EAAC,OAAO,EAAC,QAAQ,EAAC,CAAC,EAAC,IAAI,KAAK,IAAI,YAC9F,KAAC,WAAW,IAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAC,OAAO,EAAC,IAAI,EAAC,QAAQ,YAC/C,IAAI,KAAK,SAAS;oBACjB,CAAC,CAAC,gBAAgB;oBAClB,CAAC,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;wBAChC,CAAC,CAAC,IAAI,CAAC,KAAK;wBACZ,CAAC,CAAC,CAAC,KAAK,IAAI,eAAe,CAAC,GACpB,GACP,CACV,CAAA;IACH,CAAC;IAED,OAAO,CACL,KAAC,UAAU,OAAK,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAO,IAAe,YACvE,KAAC,MAAM,IAAC,IAAI,EAAC,MAAM,gBAAa,KAAK,EAAE,EAAE,EAAC,MAAM,EAAC,EAAE,EAAC,MAAM,EAAC,SAAS,EAAE,KAAc,YACjF,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CACxB,KAAC,IAAI,IAEH,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,CAAC,MAAM,EACjB,OAAO,EAAE,KAAK,KAAK,EAAE,EACrB,MAAM,EAAE,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,EACjD,KAAK,EAAE,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EACvE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE;oBACZ,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;gBAC3B,CAAC,EACD,OAAO,EAAE,GAAG,EAAE;oBACZ,QAAQ,CAAC,KAAK,CAAC,CAAA;oBACf,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK;wBAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;;wBACnC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;gBAC3B,CAAC,IAdI,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAe9B,CACH,CAAC,GACK,GACE,CACd,CAAA;AACH,CAAC;AAED,SAAS,IAAI,CAAC,EACZ,GAAG,EACH,KAAK,EACL,IAAI,EACJ,OAAO,EACP,MAAM,EACN,KAAK,EACL,KAAK,EACL,OAAO,GAUR;IACC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,KAAK,KAAK,CAAA;IAC9B,OAAO,CACL,8BACE,MAAC,MAAM,IACL,GAAG,EAAE,KAAc,EACnB,IAAI,EAAC,UAAU,gBACH,GAAG,CAAC,KAAK,GAAG,CAAC,kBACX,IAAI,mBACH,KAAK,GAAG,CAAC,mBACT,MAAM,KACjB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAChD,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAC1B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAC,QAAQ,EACd,GAAG,EAAC,MAAM,EACV,IAAI,EAAE,EAAE,EACR,EAAE,EAAC,IAAI,EACP,OAAO,EAAC,IAAI,EACZ,MAAM,EAAC,SAAS,EAChB,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EACtC,UAAU,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,EACjD,iBAAiB,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EACtG,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,GAAG,EAAE,EAAE,KACrC,EAAE,WAAW,EAAE,GAAG,CAAC,IAAI,EAAa,aAExC,GAAG,CAAC,CAAC,CAAC,CACL,8BACG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,GAAI,CAAC,CAAC,CAAC,KAAC,YAAY,IAAC,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,GAAI,EAC7F,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAC,UAAU,IAAC,IAAI,EAAE,EAAE,GAAI,CAAC,CAAC,CAAC,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,GAAI,IAC1D,CACJ,CAAC,CAAC,CAAC,CACF,KAAC,MAAM,IAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAC,QAAQ,YAC3B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GACT,CACV,EACD,KAAC,WAAW,IAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAE,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,YAChG,GAAG,CAAC,IAAI,GACG,IACP,EACR,KAAK,CAAC,CAAC,CAAC,CACP,KAAC,WAAW,IACV,IAAI,EAAC,IAAI,EACT,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAC7C,KAAK,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EACrD,EAAE,EAAC,IAAI,eACG,QAAQ,YAEjB,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,GACnC,CACf,CAAC,CAAC,CAAC,IAAI,IACP,CACJ,CAAA;AACH,CAAC"}
@@ -0,0 +1,108 @@
1
+ 'use client';"use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.PHONE = void 0;
5
+ exports.PreviewFrame = PreviewFrame;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ /**
8
+ * PreviewFrame — the running app, framed, beside the thing that builds it.
9
+ *
10
+ * Ported from build-v2 `components/editor/preview/index.tsx` (MIT, derived from
11
+ * OSW Studio and DeepSite — see NOTICE). v2 streamed a document it wrote into
12
+ * two `srcdoc` frames and swapped them as a build arrived. What a repository
13
+ * builds is a DEPLOYED page at an address — a preview URL, a sandbox's dev
14
+ * server, the live site — so this frames an address, and the builder's own
15
+ * bytes never enter it.
16
+ *
17
+ * THE SANDBOX, token by token. The framed page is somebody's app: it has to
18
+ * run to be previewed, and it must not be able to act on the page around it.
19
+ *
20
+ * allow-scripts it is an app; without script it is a picture.
21
+ * allow-forms a sign-up form is part of what you are checking.
22
+ * allow-popups its own links that open a tab still open one…
23
+ * allow-popups-to-escape-sandbox …as an ordinary tab, not a crippled one.
24
+ * allow-same-origin ONLY when the address is on ANOTHER origin than
25
+ * this page. There it grants the app its OWN
26
+ * origin — its cookies, its storage, its API —
27
+ * and nothing of ours. On OUR origin the pair
28
+ * `allow-scripts allow-same-origin` lets the
29
+ * framed page reach up and remove its own sandbox,
30
+ * so a same-origin address runs with no origin at
31
+ * all (opaque) instead.
32
+ *
33
+ * Deliberately absent: `allow-top-navigation` (a preview that can move the
34
+ * window it sits in is not a preview), `allow-modals`, `allow-downloads`,
35
+ * `allow-pointer-lock`, and every `allow=` feature — no camera, microphone or
36
+ * clipboard is granted to a page because it is being looked at.
37
+ *
38
+ * Only http(s) is framed. `javascript:`, `data:` and `blob:` addresses are
39
+ * refused before they reach the attribute, and so is anything that fails to
40
+ * parse — `web()` in `bridge.ts` is that check.
41
+ *
42
+ * THE BRIDGE IS OPT-IN. Element picking and the page's console arrive only if
43
+ * the page ships the `script()` from `bridge.ts`, pinned to this origin; this
44
+ * listens only to the frame's own window speaking from the frame's own origin,
45
+ * and posts only to that origin. See `bridge.ts` for the protocol.
46
+ */
47
+ const gui_1 = require("@hanzo/gui");
48
+ const react_1 = require("react");
49
+ const slot_1 = require("../backends/gui/slot.cjs");
50
+ const bridge_1 = require("./bridge.cjs");
51
+ /** A phone's width, px — the narrow preview. */
52
+ exports.PHONE = 390;
53
+ function PreviewFrame({ src, title = 'Preview', device = 'desktop', empty, toolbar, onBridge, onLoad, ref, ...rest }) {
54
+ const frame = (0, react_1.useRef)(null);
55
+ const [loading, setLoading] = (0, react_1.useState)(true);
56
+ const [nonce, setNonce] = (0, react_1.useState)(0);
57
+ const here = typeof window === 'undefined' ? undefined : window.location.href;
58
+ const url = (0, react_1.useMemo)(() => (0, bridge_1.web)(src, here), [src, here]);
59
+ const foreign = Boolean(url && typeof window !== 'undefined' && url.origin !== window.location.origin);
60
+ // No `allow-popups-to-escape-sandbox`: an escaped popup keeps a handle on this
61
+ // window and can move it — a framed page could send the builder's own tab to
62
+ // a look-alike sign-in.
63
+ const sandbox = ['allow-scripts', 'allow-forms', 'allow-popups']
64
+ .concat(foreign ? ['allow-same-origin'] : [])
65
+ .join(' ');
66
+ // Whether the host asked the page to let a person pick: until it has, a
67
+ // pick or a hover the page reports on its own is not a person's.
68
+ const picking = (0, react_1.useRef)(false);
69
+ // A new document has not been asked to let anyone pick: the gate closes on
70
+ // every load, and the host opens it again once the page says it is ready.
71
+ (0, react_1.useEffect)(() => {
72
+ setLoading(true);
73
+ picking.current = false;
74
+ }, [url?.href, nonce]);
75
+ (0, react_1.useImperativeHandle)(ref, () => ({
76
+ reload: () => setNonce((n) => n + 1),
77
+ post: (command) => {
78
+ if (command.type === 'preview:editable')
79
+ picking.current = command.active;
80
+ if (!url || !foreign)
81
+ return;
82
+ frame.current?.contentWindow?.postMessage(command, url.origin);
83
+ },
84
+ }), [url, foreign]);
85
+ (0, react_1.useEffect)(() => {
86
+ if (!onBridge || !url || !foreign)
87
+ return;
88
+ const origin = url.origin;
89
+ const listen = (event) => {
90
+ const said = (0, bridge_1.accept)(event, frame.current, origin);
91
+ if (!said)
92
+ return;
93
+ if ((said.type === 'preview:select' || said.type === 'preview:hover') && !picking.current)
94
+ return;
95
+ onBridge(said);
96
+ };
97
+ window.addEventListener('message', listen);
98
+ return () => window.removeEventListener('message', listen);
99
+ }, [onBridge, url, foreign]);
100
+ if (!url) {
101
+ return ((0, jsx_runtime_1.jsx)(gui_1.YStack, { ...(0, slot_1.slot)('preview-frame'), flex: 1, minH: 0, items: "center", justify: "center", p: "$6", rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$sunken", ...rest, children: empty ?? ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { items: "center", gap: "$1.5", maxW: 360, children: [(0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$4", fontWeight: "600", color: "$ink", text: "center", children: src ? 'This address cannot be previewed.' : 'Nothing deployed yet.' }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", text: "center", children: src ? 'Only http and https pages open here.' : 'Describe what to build and the running app appears here.' })] })) }));
102
+ }
103
+ const phone = device === 'mobile';
104
+ return ((0, jsx_runtime_1.jsxs)(gui_1.YStack, { ...(0, slot_1.slot)('preview-frame'), "data-device": device, position: "relative", flex: 1, minH: 0, minW: 0, rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$sunken", overflow: "hidden", items: "center", ...rest, children: [(0, jsx_runtime_1.jsxs)(gui_1.YStack, { position: "relative", flex: 1, minH: 0, width: "100%", maxW: phone ? exports.PHONE : '100%', ...(phone ? { borderLeftWidth: 1, borderRightWidth: 1, borderColor: '$borderColor' } : null), children: [(0, jsx_runtime_1.jsx)("iframe", { ref: frame, src: url.href, title: title, sandbox: sandbox, referrerPolicy: "strict-origin-when-cross-origin", onLoad: () => {
105
+ setLoading(false);
106
+ onLoad?.();
107
+ }, style: { display: 'block', width: '100%', height: '100%', border: 0, background: 'transparent' } }, `${url.href}#${nonce}`), loading ? ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { position: "absolute", t: 0, r: 0, b: 0, l: 0, items: "center", justify: "center", gap: "$2", bg: "$sunken", pointerEvents: "none", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)(gui_1.Spinner, { size: "small", maxW: 16, maxH: 16 }), (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$2", color: "$soft", children: "Loading preview\u2026" })] })) : null] }), toolbar ? ((0, jsx_runtime_1.jsx)(gui_1.XStack, { ...(0, slot_1.slot)('preview-toolbar'), position: "absolute", b: "$4", self: "center", items: "center", gap: "$1", p: "$1.5", rounded: 999, borderWidth: 1, borderColor: "$borderColor", bg: "$background", shadowColor: "rgba(0,0,0,0.4)", shadowRadius: 16, shadowOffset: { width: 0, height: 6 }, children: toolbar })) : null] }));
108
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * PreviewFrame — the running app, framed, beside the thing that builds it.
3
+ *
4
+ * Ported from build-v2 `components/editor/preview/index.tsx` (MIT, derived from
5
+ * OSW Studio and DeepSite — see NOTICE). v2 streamed a document it wrote into
6
+ * two `srcdoc` frames and swapped them as a build arrived. What a repository
7
+ * builds is a DEPLOYED page at an address — a preview URL, a sandbox's dev
8
+ * server, the live site — so this frames an address, and the builder's own
9
+ * bytes never enter it.
10
+ *
11
+ * THE SANDBOX, token by token. The framed page is somebody's app: it has to
12
+ * run to be previewed, and it must not be able to act on the page around it.
13
+ *
14
+ * allow-scripts it is an app; without script it is a picture.
15
+ * allow-forms a sign-up form is part of what you are checking.
16
+ * allow-popups its own links that open a tab still open one…
17
+ * allow-popups-to-escape-sandbox …as an ordinary tab, not a crippled one.
18
+ * allow-same-origin ONLY when the address is on ANOTHER origin than
19
+ * this page. There it grants the app its OWN
20
+ * origin — its cookies, its storage, its API —
21
+ * and nothing of ours. On OUR origin the pair
22
+ * `allow-scripts allow-same-origin` lets the
23
+ * framed page reach up and remove its own sandbox,
24
+ * so a same-origin address runs with no origin at
25
+ * all (opaque) instead.
26
+ *
27
+ * Deliberately absent: `allow-top-navigation` (a preview that can move the
28
+ * window it sits in is not a preview), `allow-modals`, `allow-downloads`,
29
+ * `allow-pointer-lock`, and every `allow=` feature — no camera, microphone or
30
+ * clipboard is granted to a page because it is being looked at.
31
+ *
32
+ * Only http(s) is framed. `javascript:`, `data:` and `blob:` addresses are
33
+ * refused before they reach the attribute, and so is anything that fails to
34
+ * parse — `web()` in `bridge.ts` is that check.
35
+ *
36
+ * THE BRIDGE IS OPT-IN. Element picking and the page's console arrive only if
37
+ * the page ships the `script()` from `bridge.ts`, pinned to this origin; this
38
+ * listens only to the frame's own window speaking from the frame's own origin,
39
+ * and posts only to that origin. See `bridge.ts` for the protocol.
40
+ */
41
+ import { YStack } from '@hanzo/gui';
42
+ import { type ComponentProps, type ReactNode, type Ref } from 'react';
43
+ import { type FrameCommand, type FrameEvent } from './bridge.js';
44
+ type Col = Omit<ComponentProps<typeof YStack>, 'children'>;
45
+ /** A phone's width, px — the narrow preview. */
46
+ export declare const PHONE = 390;
47
+ /** What the host can do to a mounted frame. */
48
+ export interface PreviewHandle {
49
+ /** Load the address again. */
50
+ reload(): void;
51
+ /** Say something to a page running the bridge. Dropped when there is none. */
52
+ post(command: FrameCommand): void;
53
+ }
54
+ export interface PreviewFrameProps extends Col {
55
+ /** The address to frame. Anything but http(s) is refused. */
56
+ src?: string | null;
57
+ /** The frame's accessible name. */
58
+ title?: string;
59
+ /** Desktop fills the pane; mobile is a phone-wide column. */
60
+ device?: 'desktop' | 'mobile';
61
+ /** Drawn when there is no address — nothing deployed yet. */
62
+ empty?: ReactNode;
63
+ /** A floating bar over the bottom of the frame — v2's edit toolbar. */
64
+ toolbar?: ReactNode;
65
+ /** Messages from a page running the bridge. */
66
+ onBridge?: (event: FrameEvent) => void;
67
+ /** Called once the frame has loaded. */
68
+ onLoad?: () => void;
69
+ /**
70
+ * The handle — `reload()` and `post()`. A plain prop (React 19), not
71
+ * `forwardRef`: the wrapper's `Omit<Props, 'ref'>` collapses these props to
72
+ * `any` against gui's index signature, and every caller loses their types.
73
+ */
74
+ ref?: Ref<PreviewHandle>;
75
+ }
76
+ export declare function PreviewFrame({ src, title, device, empty, toolbar, onBridge, onLoad, ref, ...rest }: PreviewFrameProps): import("react").JSX.Element;
77
+ export {};
78
+ //# sourceMappingURL=PreviewFrame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreviewFrame.d.ts","sourceRoot":"","sources":["../../src/agents/PreviewFrame.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,EAAgC,MAAM,EAAE,MAAM,YAAY,CAAA;AACjE,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,GAAG,EAMT,MAAM,OAAO,CAAA;AAGd,OAAO,EAAU,KAAK,YAAY,EAAE,KAAK,UAAU,EAAO,MAAM,UAAU,CAAA;AAE1E,KAAK,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;AAE1D,gDAAgD;AAChD,eAAO,MAAM,KAAK,MAAM,CAAA;AAExB,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,MAAM,IAAI,IAAI,CAAA;IACd,8EAA8E;IAC9E,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;CAClC;AAED,MAAM,WAAW,iBAAkB,SAAQ,GAAG;IAC5C,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6DAA6D;IAC7D,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC7B,6DAA6D;IAC7D,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,uEAAuE;IACvE,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;IACtC,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;;;;OAIG;IACH,GAAG,CAAC,EAAE,GAAG,CAAC,aAAa,CAAC,CAAA;CACzB;AAED,wBAAgB,YAAY,CAAC,EAC3B,GAAG,EACH,KAAiB,EACjB,MAAkB,EAClB,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,GAAG,EACH,GAAG,IAAI,EACR,EAAE,iBAAiB,+BAiKnB"}
@@ -0,0 +1,105 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * PreviewFrame — the running app, framed, beside the thing that builds it.
5
+ *
6
+ * Ported from build-v2 `components/editor/preview/index.tsx` (MIT, derived from
7
+ * OSW Studio and DeepSite — see NOTICE). v2 streamed a document it wrote into
8
+ * two `srcdoc` frames and swapped them as a build arrived. What a repository
9
+ * builds is a DEPLOYED page at an address — a preview URL, a sandbox's dev
10
+ * server, the live site — so this frames an address, and the builder's own
11
+ * bytes never enter it.
12
+ *
13
+ * THE SANDBOX, token by token. The framed page is somebody's app: it has to
14
+ * run to be previewed, and it must not be able to act on the page around it.
15
+ *
16
+ * allow-scripts it is an app; without script it is a picture.
17
+ * allow-forms a sign-up form is part of what you are checking.
18
+ * allow-popups its own links that open a tab still open one…
19
+ * allow-popups-to-escape-sandbox …as an ordinary tab, not a crippled one.
20
+ * allow-same-origin ONLY when the address is on ANOTHER origin than
21
+ * this page. There it grants the app its OWN
22
+ * origin — its cookies, its storage, its API —
23
+ * and nothing of ours. On OUR origin the pair
24
+ * `allow-scripts allow-same-origin` lets the
25
+ * framed page reach up and remove its own sandbox,
26
+ * so a same-origin address runs with no origin at
27
+ * all (opaque) instead.
28
+ *
29
+ * Deliberately absent: `allow-top-navigation` (a preview that can move the
30
+ * window it sits in is not a preview), `allow-modals`, `allow-downloads`,
31
+ * `allow-pointer-lock`, and every `allow=` feature — no camera, microphone or
32
+ * clipboard is granted to a page because it is being looked at.
33
+ *
34
+ * Only http(s) is framed. `javascript:`, `data:` and `blob:` addresses are
35
+ * refused before they reach the attribute, and so is anything that fails to
36
+ * parse — `web()` in `bridge.ts` is that check.
37
+ *
38
+ * THE BRIDGE IS OPT-IN. Element picking and the page's console arrive only if
39
+ * the page ships the `script()` from `bridge.ts`, pinned to this origin; this
40
+ * listens only to the frame's own window speaking from the frame's own origin,
41
+ * and posts only to that origin. See `bridge.ts` for the protocol.
42
+ */
43
+ import { SizableText, Spinner, XStack, YStack } from '@hanzo/gui';
44
+ import { useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
45
+ import { slot } from '../backends/gui/slot.js';
46
+ import { accept, web } from './bridge.js';
47
+ /** A phone's width, px — the narrow preview. */
48
+ export const PHONE = 390;
49
+ export function PreviewFrame({ src, title = 'Preview', device = 'desktop', empty, toolbar, onBridge, onLoad, ref, ...rest }) {
50
+ const frame = useRef(null);
51
+ const [loading, setLoading] = useState(true);
52
+ const [nonce, setNonce] = useState(0);
53
+ const here = typeof window === 'undefined' ? undefined : window.location.href;
54
+ const url = useMemo(() => web(src, here), [src, here]);
55
+ const foreign = Boolean(url && typeof window !== 'undefined' && url.origin !== window.location.origin);
56
+ // No `allow-popups-to-escape-sandbox`: an escaped popup keeps a handle on this
57
+ // window and can move it — a framed page could send the builder's own tab to
58
+ // a look-alike sign-in.
59
+ const sandbox = ['allow-scripts', 'allow-forms', 'allow-popups']
60
+ .concat(foreign ? ['allow-same-origin'] : [])
61
+ .join(' ');
62
+ // Whether the host asked the page to let a person pick: until it has, a
63
+ // pick or a hover the page reports on its own is not a person's.
64
+ const picking = useRef(false);
65
+ // A new document has not been asked to let anyone pick: the gate closes on
66
+ // every load, and the host opens it again once the page says it is ready.
67
+ useEffect(() => {
68
+ setLoading(true);
69
+ picking.current = false;
70
+ }, [url?.href, nonce]);
71
+ useImperativeHandle(ref, () => ({
72
+ reload: () => setNonce((n) => n + 1),
73
+ post: (command) => {
74
+ if (command.type === 'preview:editable')
75
+ picking.current = command.active;
76
+ if (!url || !foreign)
77
+ return;
78
+ frame.current?.contentWindow?.postMessage(command, url.origin);
79
+ },
80
+ }), [url, foreign]);
81
+ useEffect(() => {
82
+ if (!onBridge || !url || !foreign)
83
+ return;
84
+ const origin = url.origin;
85
+ const listen = (event) => {
86
+ const said = accept(event, frame.current, origin);
87
+ if (!said)
88
+ return;
89
+ if ((said.type === 'preview:select' || said.type === 'preview:hover') && !picking.current)
90
+ return;
91
+ onBridge(said);
92
+ };
93
+ window.addEventListener('message', listen);
94
+ return () => window.removeEventListener('message', listen);
95
+ }, [onBridge, url, foreign]);
96
+ if (!url) {
97
+ return (_jsx(YStack, { ...slot('preview-frame'), flex: 1, minH: 0, items: "center", justify: "center", p: "$6", rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$sunken", ...rest, children: empty ?? (_jsxs(YStack, { items: "center", gap: "$1.5", maxW: 360, children: [_jsx(SizableText, { size: "$4", fontWeight: "600", color: "$ink", text: "center", children: src ? 'This address cannot be previewed.' : 'Nothing deployed yet.' }), _jsx(SizableText, { size: "$2", color: "$soft", text: "center", children: src ? 'Only http and https pages open here.' : 'Describe what to build and the running app appears here.' })] })) }));
98
+ }
99
+ const phone = device === 'mobile';
100
+ return (_jsxs(YStack, { ...slot('preview-frame'), "data-device": device, position: "relative", flex: 1, minH: 0, minW: 0, rounded: "$4", borderWidth: 1, borderColor: "$borderColor", bg: "$sunken", overflow: "hidden", items: "center", ...rest, children: [_jsxs(YStack, { position: "relative", flex: 1, minH: 0, width: "100%", maxW: phone ? PHONE : '100%', ...(phone ? { borderLeftWidth: 1, borderRightWidth: 1, borderColor: '$borderColor' } : null), children: [_jsx("iframe", { ref: frame, src: url.href, title: title, sandbox: sandbox, referrerPolicy: "strict-origin-when-cross-origin", onLoad: () => {
101
+ setLoading(false);
102
+ onLoad?.();
103
+ }, style: { display: 'block', width: '100%', height: '100%', border: 0, background: 'transparent' } }, `${url.href}#${nonce}`), loading ? (_jsxs(XStack, { position: "absolute", t: 0, r: 0, b: 0, l: 0, items: "center", justify: "center", gap: "$2", bg: "$sunken", pointerEvents: "none", "aria-hidden": true, children: [_jsx(Spinner, { size: "small", maxW: 16, maxH: 16 }), _jsx(SizableText, { size: "$2", color: "$soft", children: "Loading preview\u2026" })] })) : null] }), toolbar ? (_jsx(XStack, { ...slot('preview-toolbar'), position: "absolute", b: "$4", self: "center", items: "center", gap: "$1", p: "$1.5", rounded: 999, borderWidth: 1, borderColor: "$borderColor", bg: "$background", shadowColor: "rgba(0,0,0,0.4)", shadowRadius: 16, shadowOffset: { width: 0, height: 6 }, children: toolbar })) : null] }));
104
+ }
105
+ //# sourceMappingURL=PreviewFrame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PreviewFrame.js","sourceRoot":"","sources":["../../src/agents/PreviewFrame.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ 'use client';"use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.SUGGESTIONS = void 0;
5
+ exports.Suggestions = Suggestions;
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ /**
8
+ * Suggestions — the row of asks above the composer, and a way to put it away.
9
+ *
10
+ * Ported from build-v2 `components/editor/ask-ai` (the "Review security ·
11
+ * Review SEO · Improve accessibility" chips) (MIT, derived from OSW Studio and
12
+ * DeepSite — see NOTICE). A chip SENDS its words as the next turn in whatever
13
+ * mode the composer is in — it does not fill the box and wait — which is what
14
+ * v2 settled on, so `onPick` hands the words out and the host sends them.
15
+ *
16
+ * The row scrolls sideways rather than wrapping or widening its column: three
17
+ * chips must not push a phone's composer off the bottom or its page sideways.
18
+ */
19
+ const gui_1 = require("@hanzo/gui");
20
+ const lucide_icons_2_1 = require("@hanzogui/lucide-icons-2");
21
+ const button_1 = require("../backends/gui/button.cjs");
22
+ const slot_1 = require("../backends/gui/slot.cjs");
23
+ /** v2's three, for a host that has nothing more specific to offer. */
24
+ exports.SUGGESTIONS = ['Review security', 'Review SEO', 'Improve accessibility'];
25
+ function Suggestions({ items, onPick, onDismiss, label = 'Suggestions', ...rest }) {
26
+ if (items.length === 0)
27
+ return null;
28
+ return ((0, jsx_runtime_1.jsxs)(gui_1.XStack, { ...(0, slot_1.slot)('suggestions'), role: "group", "aria-label": label, items: "center", gap: "$1.5", minW: 0, ...rest, children: [(0, jsx_runtime_1.jsx)(gui_1.ScrollView, { horizontal: true, flex: 1, minW: 0, showsHorizontalScrollIndicator: false, children: (0, jsx_runtime_1.jsx)(gui_1.XStack, { gap: "$1.5", items: "center", children: items.map((item) => ((0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", variant: "outline", size: "sm", minHeight: 24, px: "$2.5", rounded: 999, bg: "transparent", onClick: () => onPick(item), children: (0, jsx_runtime_1.jsx)(gui_1.SizableText, { size: "$1", color: "$quiet", numberOfLines: 1, children: item }) }, item))) }) }), onDismiss ? ((0, jsx_runtime_1.jsx)(button_1.Button, { type: "button", variant: "ghost", size: "icon-sm", minHeight: 24, minWidth: 24, "aria-label": `Hide ${label.toLowerCase()}`, title: `Hide ${label.toLowerCase()}`, onClick: onDismiss, children: (0, jsx_runtime_1.jsx)(lucide_icons_2_1.X, { size: 13 }) })) : null] }));
29
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Suggestions — the row of asks above the composer, and a way to put it away.
3
+ *
4
+ * Ported from build-v2 `components/editor/ask-ai` (the "Review security ·
5
+ * Review SEO · Improve accessibility" chips) (MIT, derived from OSW Studio and
6
+ * DeepSite — see NOTICE). A chip SENDS its words as the next turn in whatever
7
+ * mode the composer is in — it does not fill the box and wait — which is what
8
+ * v2 settled on, so `onPick` hands the words out and the host sends them.
9
+ *
10
+ * The row scrolls sideways rather than wrapping or widening its column: three
11
+ * chips must not push a phone's composer off the bottom or its page sideways.
12
+ */
13
+ import { XStack } from '@hanzo/gui';
14
+ import type { ComponentProps } from 'react';
15
+ type Row = Omit<ComponentProps<typeof XStack>, 'children'>;
16
+ /** v2's three, for a host that has nothing more specific to offer. */
17
+ export declare const SUGGESTIONS: readonly string[];
18
+ export interface SuggestionsProps extends Row {
19
+ items: readonly string[];
20
+ onPick: (item: string) => void;
21
+ /** Omit and the row cannot be dismissed. */
22
+ onDismiss?: () => void;
23
+ /** The group's accessible name. */
24
+ label?: string;
25
+ }
26
+ export declare function Suggestions({ items, onPick, onDismiss, label, ...rest }: SuggestionsProps): import("react").JSX.Element | null;
27
+ export {};
28
+ //# sourceMappingURL=Suggestions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Suggestions.d.ts","sourceRoot":"","sources":["../../src/agents/Suggestions.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,EAA2B,MAAM,EAAE,MAAM,YAAY,CAAA;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAK3C,KAAK,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;AAE1D,sEAAsE;AACtE,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAA+D,CAAA;AAExG,MAAM,WAAW,gBAAiB,SAAQ,GAAG;IAC3C,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAqB,EAAE,GAAG,IAAI,EAAE,EAAE,gBAAgB,sCAyCzG"}
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * Suggestions — the row of asks above the composer, and a way to put it away.
5
+ *
6
+ * Ported from build-v2 `components/editor/ask-ai` (the "Review security ·
7
+ * Review SEO · Improve accessibility" chips) (MIT, derived from OSW Studio and
8
+ * DeepSite — see NOTICE). A chip SENDS its words as the next turn in whatever
9
+ * mode the composer is in — it does not fill the box and wait — which is what
10
+ * v2 settled on, so `onPick` hands the words out and the host sends them.
11
+ *
12
+ * The row scrolls sideways rather than wrapping or widening its column: three
13
+ * chips must not push a phone's composer off the bottom or its page sideways.
14
+ */
15
+ import { ScrollView, SizableText, XStack } from '@hanzo/gui';
16
+ import { X } from '@hanzogui/lucide-icons-2';
17
+ import { Button } from '../backends/gui/button.js';
18
+ import { slot } from '../backends/gui/slot.js';
19
+ /** v2's three, for a host that has nothing more specific to offer. */
20
+ export const SUGGESTIONS = ['Review security', 'Review SEO', 'Improve accessibility'];
21
+ export function Suggestions({ items, onPick, onDismiss, label = 'Suggestions', ...rest }) {
22
+ if (items.length === 0)
23
+ return null;
24
+ return (_jsxs(XStack, { ...slot('suggestions'), role: "group", "aria-label": label, items: "center", gap: "$1.5", minW: 0, ...rest, children: [_jsx(ScrollView, { horizontal: true, flex: 1, minW: 0, showsHorizontalScrollIndicator: false, children: _jsx(XStack, { gap: "$1.5", items: "center", children: items.map((item) => (_jsx(Button, { type: "button", variant: "outline", size: "sm", minHeight: 24, px: "$2.5", rounded: 999, bg: "transparent", onClick: () => onPick(item), children: _jsx(SizableText, { size: "$1", color: "$quiet", numberOfLines: 1, children: item }) }, item))) }) }), onDismiss ? (_jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", minHeight: 24, minWidth: 24, "aria-label": `Hide ${label.toLowerCase()}`, title: `Hide ${label.toLowerCase()}`, onClick: onDismiss, children: _jsx(X, { size: 13 }) })) : null] }));
25
+ }
26
+ //# sourceMappingURL=Suggestions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Suggestions.js","sourceRoot":"","sources":["../../src/agents/Suggestions.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,0BAA0B,CAAA;AAG5C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAI3C,sEAAsE;AACtE,MAAM,CAAC,MAAM,WAAW,GAAsB,CAAC,iBAAiB,EAAE,YAAY,EAAE,uBAAuB,CAAC,CAAA;AAWxG,MAAM,UAAU,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,GAAG,aAAa,EAAE,GAAG,IAAI,EAAoB;IACxG,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,OAAO,CACL,MAAC,MAAM,OAAK,IAAI,CAAC,aAAa,CAAC,EAAE,IAAI,EAAC,OAAO,gBAAa,KAAK,EAAE,KAAK,EAAC,QAAQ,EAAC,GAAG,EAAC,MAAM,EAAC,IAAI,EAAE,CAAC,KAAM,IAAI,aAC1G,KAAC,UAAU,IAAC,UAAU,QAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,8BAA8B,EAAE,KAAK,YAC5E,KAAC,MAAM,IAAC,GAAG,EAAC,MAAM,EAAC,KAAK,EAAC,QAAQ,YAC9B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACnB,KAAC,MAAM,IAEL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,SAAS,EAAE,EAAE,EACb,EAAE,EAAC,MAAM,EACT,OAAO,EAAE,GAAG,EACZ,EAAE,EAAC,aAAa,EAChB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,YAE3B,KAAC,WAAW,IAAC,IAAI,EAAC,IAAI,EAAC,KAAK,EAAC,QAAQ,EAAC,aAAa,EAAE,CAAC,YACnD,IAAI,GACO,IAZT,IAAI,CAaF,CACV,CAAC,GACK,GACE,EACZ,SAAS,CAAC,CAAC,CAAC,CACX,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,SAAS,EACd,SAAS,EAAE,EAAE,EACb,QAAQ,EAAE,EAAE,gBACA,QAAQ,KAAK,CAAC,WAAW,EAAE,EAAE,EACzC,KAAK,EAAE,QAAQ,KAAK,CAAC,WAAW,EAAE,EAAE,EACpC,OAAO,EAAE,SAAS,YAElB,KAAC,CAAC,IAAC,IAAI,EAAE,EAAE,GAAI,GACR,CACV,CAAC,CAAC,CAAC,IAAI,IACD,CACV,CAAA;AACH,CAAC"}