@buoy-gg/ask-buoy 7.0.35 → 7.0.38

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 (286) hide show
  1. package/README.md +73 -15
  2. package/lib/commonjs/blocks/AskBlocks.js +1 -338
  3. package/lib/commonjs/blocks/BlockRenderer.js +1 -250
  4. package/lib/commonjs/blocks/ChromePrototypes.js +1 -514
  5. package/lib/commonjs/blocks/DataBlocks.js +1 -688
  6. package/lib/commonjs/blocks/ExtraBlocks.js +1 -1854
  7. package/lib/commonjs/blocks/MediaBlocks.js +1 -140
  8. package/lib/commonjs/blocks/ReceiptBlocks.js +1 -586
  9. package/lib/commonjs/blocks/blockText.js +1 -0
  10. package/lib/commonjs/blocks/blockText.test.js +1 -0
  11. package/lib/commonjs/blocks/context.js +1 -42
  12. package/lib/commonjs/blocks/icons.js +1 -96
  13. package/lib/commonjs/blocks/index.js +1 -95
  14. package/lib/commonjs/blocks/listRow.test.js +1 -55
  15. package/lib/commonjs/blocks/pageState.js +1 -34
  16. package/lib/commonjs/blocks/pageState.test.js +1 -57
  17. package/lib/commonjs/blocks/primitives.js +1 -401
  18. package/lib/commonjs/blocks/primitivesIndex.js +1 -62
  19. package/lib/commonjs/components/ApprovalCard.js +1 -140
  20. package/lib/commonjs/components/AskBuoyHeader.js +1 -164
  21. package/lib/commonjs/components/AskBuoyIcon.js +1 -19
  22. package/lib/commonjs/components/AskBuoyModal.js +1 -353
  23. package/lib/commonjs/components/AskBuoySettings.js +1 -69
  24. package/lib/commonjs/components/ChangesBar.js +1 -211
  25. package/lib/commonjs/components/Composer.js +1 -175
  26. package/lib/commonjs/components/EmptyState.js +1 -154
  27. package/lib/commonjs/components/KeyboardPad.js +1 -0
  28. package/lib/commonjs/components/Markdown.js +1 -252
  29. package/lib/commonjs/components/MessageList.js +1 -683
  30. package/lib/commonjs/components/QueuedMessages.js +1 -0
  31. package/lib/commonjs/components/ThinkingStrip.js +1 -223
  32. package/lib/commonjs/components/TypingDots.js +1 -63
  33. package/lib/commonjs/components/markdownParse.js +1 -0
  34. package/lib/commonjs/components/markdownParse.test.js +1 -0
  35. package/lib/commonjs/components/useCopyAction.js +1 -50
  36. package/lib/commonjs/index.js +1 -252
  37. package/lib/commonjs/preset.js +1 -90
  38. package/lib/commonjs/store/activityGroups.js +1 -0
  39. package/lib/commonjs/store/activityGroups.test.js +1 -0
  40. package/lib/commonjs/store/askBuoySettings.js +1 -67
  41. package/lib/commonjs/store/askBuoyStore.js +1 -365
  42. package/lib/commonjs/store/blockPlacement.js +1 -0
  43. package/lib/commonjs/store/blockPlacement.test.js +1 -0
  44. package/lib/commonjs/store/queue.test.js +1 -0
  45. package/lib/commonjs/store/resetConversation.js +1 -0
  46. package/lib/commonjs/store/restorePending.test.js +1 -0
  47. package/lib/commonjs/store/restoredIds.test.js +1 -47
  48. package/lib/commonjs/store/suggestions.js +1 -0
  49. package/lib/commonjs/store/suggestions.test.js +1 -0
  50. package/lib/commonjs/store/systemLine.test.js +1 -0
  51. package/lib/commonjs/store/ticketPrompt.js +1 -0
  52. package/lib/commonjs/store/traceText.js +1 -81
  53. package/lib/commonjs/store/traceText.test.js +1 -112
  54. package/lib/commonjs/store/transcriptPersistence.js +1 -208
  55. package/lib/commonjs/store/transcriptPersistence.test.js +1 -185
  56. package/lib/commonjs/store/turnRendering.test.js +1 -0
  57. package/lib/commonjs/store/useAskBuoy.js +1 -400
  58. package/lib/commonjs/store/useAskBuoySettings.js +1 -14
  59. package/lib/commonjs/sync/askBuoySyncAdapter.js +1 -119
  60. package/lib/commonjs/sync/askBuoySyncAdapter.test.js +1 -141
  61. package/lib/commonjs/sync/wire.js +1 -58
  62. package/lib/commonjs/types.js +1 -6
  63. package/lib/module/blocks/AskBlocks.js +1 -331
  64. package/lib/module/blocks/BlockRenderer.js +1 -245
  65. package/lib/module/blocks/ChromePrototypes.js +1 -503
  66. package/lib/module/blocks/DataBlocks.js +1 -674
  67. package/lib/module/blocks/ExtraBlocks.js +1 -1827
  68. package/lib/module/blocks/MediaBlocks.js +1 -135
  69. package/lib/module/blocks/ReceiptBlocks.js +1 -574
  70. package/lib/module/blocks/blockText.js +1 -0
  71. package/lib/module/blocks/blockText.test.js +1 -0
  72. package/lib/module/blocks/context.js +1 -35
  73. package/lib/module/blocks/icons.js +1 -91
  74. package/lib/module/blocks/index.js +1 -8
  75. package/lib/module/blocks/listRow.test.js +1 -56
  76. package/lib/module/blocks/pageState.js +1 -30
  77. package/lib/module/blocks/pageState.test.js +1 -56
  78. package/lib/module/blocks/primitives.js +1 -389
  79. package/lib/module/blocks/primitivesIndex.js +1 -5
  80. package/lib/module/components/ApprovalCard.js +1 -135
  81. package/lib/module/components/AskBuoyHeader.js +1 -161
  82. package/lib/module/components/AskBuoyIcon.js +1 -8
  83. package/lib/module/components/AskBuoyModal.js +1 -348
  84. package/lib/module/components/AskBuoySettings.js +1 -64
  85. package/lib/module/components/ChangesBar.js +1 -206
  86. package/lib/module/components/Composer.js +1 -170
  87. package/lib/module/components/EmptyState.js +1 -149
  88. package/lib/module/components/KeyboardPad.js +1 -0
  89. package/lib/module/components/Markdown.js +1 -246
  90. package/lib/module/components/MessageList.js +1 -677
  91. package/lib/module/components/QueuedMessages.js +1 -0
  92. package/lib/module/components/ThinkingStrip.js +1 -218
  93. package/lib/module/components/TypingDots.js +1 -58
  94. package/lib/module/components/markdownParse.js +1 -0
  95. package/lib/module/components/markdownParse.test.js +1 -0
  96. package/lib/module/components/useCopyAction.js +1 -46
  97. package/lib/module/index.js +1 -34
  98. package/lib/module/preset.js +1 -73
  99. package/lib/module/store/activityGroups.js +1 -0
  100. package/lib/module/store/activityGroups.test.js +1 -0
  101. package/lib/module/store/askBuoySettings.js +1 -62
  102. package/lib/module/store/askBuoyStore.js +1 -361
  103. package/lib/module/store/blockPlacement.js +1 -0
  104. package/lib/module/store/blockPlacement.test.js +1 -0
  105. package/lib/module/store/queue.test.js +1 -0
  106. package/lib/module/store/resetConversation.js +1 -0
  107. package/lib/module/store/restorePending.test.js +1 -0
  108. package/lib/module/store/restoredIds.test.js +1 -46
  109. package/lib/module/store/suggestions.js +1 -0
  110. package/lib/module/store/suggestions.test.js +1 -0
  111. package/lib/module/store/systemLine.test.js +1 -0
  112. package/lib/module/store/ticketPrompt.js +1 -0
  113. package/lib/module/store/traceText.js +1 -75
  114. package/lib/module/store/traceText.test.js +1 -111
  115. package/lib/module/store/transcriptPersistence.js +1 -198
  116. package/lib/module/store/transcriptPersistence.test.js +1 -184
  117. package/lib/module/store/turnRendering.test.js +1 -0
  118. package/lib/module/store/useAskBuoy.js +1 -394
  119. package/lib/module/store/useAskBuoySettings.js +1 -9
  120. package/lib/module/sync/askBuoySyncAdapter.js +1 -114
  121. package/lib/module/sync/askBuoySyncAdapter.test.js +1 -140
  122. package/lib/module/sync/wire.js +1 -47
  123. package/lib/module/types.js +1 -4
  124. package/lib/typescript/blocks/DataBlocks.d.ts +11 -0
  125. package/lib/typescript/blocks/ExtraBlocks.d.ts +18 -2
  126. package/lib/typescript/blocks/blockText.d.ts +14 -0
  127. package/lib/typescript/blocks/blockText.test.d.ts +2 -0
  128. package/lib/typescript/blocks/primitives.d.ts +16 -1
  129. package/lib/typescript/components/ApprovalCard.d.ts +9 -1
  130. package/lib/typescript/components/AskBuoyHeader.d.ts +31 -1
  131. package/lib/typescript/components/Composer.d.ts +16 -1
  132. package/lib/typescript/components/EmptyState.d.ts +5 -1
  133. package/lib/typescript/components/KeyboardPad.d.ts +33 -0
  134. package/lib/typescript/components/Markdown.d.ts +0 -10
  135. package/lib/typescript/components/MessageList.d.ts +7 -2
  136. package/lib/typescript/components/QueuedMessages.d.ts +10 -0
  137. package/lib/typescript/components/markdownParse.d.ts +49 -0
  138. package/lib/typescript/components/markdownParse.test.d.ts +2 -0
  139. package/lib/typescript/preset.d.ts +4 -2
  140. package/lib/typescript/store/activityGroups.d.ts +29 -0
  141. package/lib/typescript/store/activityGroups.test.d.ts +2 -0
  142. package/lib/typescript/store/askBuoySettings.d.ts +22 -0
  143. package/lib/typescript/store/askBuoyStore.d.ts +174 -9
  144. package/lib/typescript/store/blockPlacement.d.ts +30 -0
  145. package/lib/typescript/store/blockPlacement.test.d.ts +2 -0
  146. package/lib/typescript/store/queue.test.d.ts +2 -0
  147. package/lib/typescript/store/resetConversation.d.ts +38 -0
  148. package/lib/typescript/store/restorePending.test.d.ts +2 -0
  149. package/lib/typescript/store/suggestions.d.ts +32 -0
  150. package/lib/typescript/store/suggestions.test.d.ts +2 -0
  151. package/lib/typescript/store/systemLine.test.d.ts +2 -0
  152. package/lib/typescript/store/ticketPrompt.d.ts +11 -0
  153. package/lib/typescript/store/transcriptPersistence.d.ts +41 -2
  154. package/lib/typescript/store/turnRendering.test.d.ts +2 -0
  155. package/lib/typescript/store/useAskBuoy.d.ts +26 -3
  156. package/lib/typescript/sync/askBuoySyncAdapter.d.ts +29 -6
  157. package/package.json +10 -10
  158. package/lib/commonjs/blocks/AskBlocks.js.map +0 -1
  159. package/lib/commonjs/blocks/BlockRenderer.js.map +0 -1
  160. package/lib/commonjs/blocks/ChromePrototypes.js.map +0 -1
  161. package/lib/commonjs/blocks/DataBlocks.js.map +0 -1
  162. package/lib/commonjs/blocks/ExtraBlocks.js.map +0 -1
  163. package/lib/commonjs/blocks/MediaBlocks.js.map +0 -1
  164. package/lib/commonjs/blocks/ReceiptBlocks.js.map +0 -1
  165. package/lib/commonjs/blocks/context.js.map +0 -1
  166. package/lib/commonjs/blocks/icons.js.map +0 -1
  167. package/lib/commonjs/blocks/index.js.map +0 -1
  168. package/lib/commonjs/blocks/listRow.test.js.map +0 -1
  169. package/lib/commonjs/blocks/pageState.js.map +0 -1
  170. package/lib/commonjs/blocks/pageState.test.js.map +0 -1
  171. package/lib/commonjs/blocks/primitives.js.map +0 -1
  172. package/lib/commonjs/blocks/primitivesIndex.js.map +0 -1
  173. package/lib/commonjs/components/ApprovalCard.js.map +0 -1
  174. package/lib/commonjs/components/AskBuoyHeader.js.map +0 -1
  175. package/lib/commonjs/components/AskBuoyIcon.js.map +0 -1
  176. package/lib/commonjs/components/AskBuoyModal.js.map +0 -1
  177. package/lib/commonjs/components/AskBuoySettings.js.map +0 -1
  178. package/lib/commonjs/components/ChangesBar.js.map +0 -1
  179. package/lib/commonjs/components/Composer.js.map +0 -1
  180. package/lib/commonjs/components/EmptyState.js.map +0 -1
  181. package/lib/commonjs/components/Markdown.js.map +0 -1
  182. package/lib/commonjs/components/MessageList.js.map +0 -1
  183. package/lib/commonjs/components/ThinkingStrip.js.map +0 -1
  184. package/lib/commonjs/components/TypingDots.js.map +0 -1
  185. package/lib/commonjs/components/useCopyAction.js.map +0 -1
  186. package/lib/commonjs/index.js.map +0 -1
  187. package/lib/commonjs/preset.js.map +0 -1
  188. package/lib/commonjs/store/askBuoySettings.js.map +0 -1
  189. package/lib/commonjs/store/askBuoyStore.js.map +0 -1
  190. package/lib/commonjs/store/restoredIds.test.js.map +0 -1
  191. package/lib/commonjs/store/traceText.js.map +0 -1
  192. package/lib/commonjs/store/traceText.test.js.map +0 -1
  193. package/lib/commonjs/store/transcriptPersistence.js.map +0 -1
  194. package/lib/commonjs/store/transcriptPersistence.test.js.map +0 -1
  195. package/lib/commonjs/store/useAskBuoy.js.map +0 -1
  196. package/lib/commonjs/store/useAskBuoySettings.js.map +0 -1
  197. package/lib/commonjs/sync/askBuoySyncAdapter.js.map +0 -1
  198. package/lib/commonjs/sync/askBuoySyncAdapter.test.js.map +0 -1
  199. package/lib/commonjs/sync/wire.js.map +0 -1
  200. package/lib/commonjs/types.js.map +0 -1
  201. package/lib/module/blocks/AskBlocks.js.map +0 -1
  202. package/lib/module/blocks/BlockRenderer.js.map +0 -1
  203. package/lib/module/blocks/ChromePrototypes.js.map +0 -1
  204. package/lib/module/blocks/DataBlocks.js.map +0 -1
  205. package/lib/module/blocks/ExtraBlocks.js.map +0 -1
  206. package/lib/module/blocks/MediaBlocks.js.map +0 -1
  207. package/lib/module/blocks/ReceiptBlocks.js.map +0 -1
  208. package/lib/module/blocks/context.js.map +0 -1
  209. package/lib/module/blocks/icons.js.map +0 -1
  210. package/lib/module/blocks/index.js.map +0 -1
  211. package/lib/module/blocks/listRow.test.js.map +0 -1
  212. package/lib/module/blocks/pageState.js.map +0 -1
  213. package/lib/module/blocks/pageState.test.js.map +0 -1
  214. package/lib/module/blocks/primitives.js.map +0 -1
  215. package/lib/module/blocks/primitivesIndex.js.map +0 -1
  216. package/lib/module/components/ApprovalCard.js.map +0 -1
  217. package/lib/module/components/AskBuoyHeader.js.map +0 -1
  218. package/lib/module/components/AskBuoyIcon.js.map +0 -1
  219. package/lib/module/components/AskBuoyModal.js.map +0 -1
  220. package/lib/module/components/AskBuoySettings.js.map +0 -1
  221. package/lib/module/components/ChangesBar.js.map +0 -1
  222. package/lib/module/components/Composer.js.map +0 -1
  223. package/lib/module/components/EmptyState.js.map +0 -1
  224. package/lib/module/components/Markdown.js.map +0 -1
  225. package/lib/module/components/MessageList.js.map +0 -1
  226. package/lib/module/components/ThinkingStrip.js.map +0 -1
  227. package/lib/module/components/TypingDots.js.map +0 -1
  228. package/lib/module/components/useCopyAction.js.map +0 -1
  229. package/lib/module/index.js.map +0 -1
  230. package/lib/module/preset.js.map +0 -1
  231. package/lib/module/store/askBuoySettings.js.map +0 -1
  232. package/lib/module/store/askBuoyStore.js.map +0 -1
  233. package/lib/module/store/restoredIds.test.js.map +0 -1
  234. package/lib/module/store/traceText.js.map +0 -1
  235. package/lib/module/store/traceText.test.js.map +0 -1
  236. package/lib/module/store/transcriptPersistence.js.map +0 -1
  237. package/lib/module/store/transcriptPersistence.test.js.map +0 -1
  238. package/lib/module/store/useAskBuoy.js.map +0 -1
  239. package/lib/module/store/useAskBuoySettings.js.map +0 -1
  240. package/lib/module/sync/askBuoySyncAdapter.js.map +0 -1
  241. package/lib/module/sync/askBuoySyncAdapter.test.js.map +0 -1
  242. package/lib/module/sync/wire.js.map +0 -1
  243. package/lib/module/types.js.map +0 -1
  244. package/lib/typescript/blocks/AskBlocks.d.ts.map +0 -1
  245. package/lib/typescript/blocks/BlockRenderer.d.ts.map +0 -1
  246. package/lib/typescript/blocks/ChromePrototypes.d.ts.map +0 -1
  247. package/lib/typescript/blocks/DataBlocks.d.ts.map +0 -1
  248. package/lib/typescript/blocks/ExtraBlocks.d.ts.map +0 -1
  249. package/lib/typescript/blocks/MediaBlocks.d.ts.map +0 -1
  250. package/lib/typescript/blocks/ReceiptBlocks.d.ts.map +0 -1
  251. package/lib/typescript/blocks/context.d.ts.map +0 -1
  252. package/lib/typescript/blocks/icons.d.ts.map +0 -1
  253. package/lib/typescript/blocks/index.d.ts.map +0 -1
  254. package/lib/typescript/blocks/listRow.test.d.ts.map +0 -1
  255. package/lib/typescript/blocks/pageState.d.ts.map +0 -1
  256. package/lib/typescript/blocks/pageState.test.d.ts.map +0 -1
  257. package/lib/typescript/blocks/primitives.d.ts.map +0 -1
  258. package/lib/typescript/blocks/primitivesIndex.d.ts.map +0 -1
  259. package/lib/typescript/components/ApprovalCard.d.ts.map +0 -1
  260. package/lib/typescript/components/AskBuoyHeader.d.ts.map +0 -1
  261. package/lib/typescript/components/AskBuoyIcon.d.ts.map +0 -1
  262. package/lib/typescript/components/AskBuoyModal.d.ts.map +0 -1
  263. package/lib/typescript/components/AskBuoySettings.d.ts.map +0 -1
  264. package/lib/typescript/components/ChangesBar.d.ts.map +0 -1
  265. package/lib/typescript/components/Composer.d.ts.map +0 -1
  266. package/lib/typescript/components/EmptyState.d.ts.map +0 -1
  267. package/lib/typescript/components/Markdown.d.ts.map +0 -1
  268. package/lib/typescript/components/MessageList.d.ts.map +0 -1
  269. package/lib/typescript/components/ThinkingStrip.d.ts.map +0 -1
  270. package/lib/typescript/components/TypingDots.d.ts.map +0 -1
  271. package/lib/typescript/components/useCopyAction.d.ts.map +0 -1
  272. package/lib/typescript/index.d.ts.map +0 -1
  273. package/lib/typescript/preset.d.ts.map +0 -1
  274. package/lib/typescript/store/askBuoySettings.d.ts.map +0 -1
  275. package/lib/typescript/store/askBuoyStore.d.ts.map +0 -1
  276. package/lib/typescript/store/restoredIds.test.d.ts.map +0 -1
  277. package/lib/typescript/store/traceText.d.ts.map +0 -1
  278. package/lib/typescript/store/traceText.test.d.ts.map +0 -1
  279. package/lib/typescript/store/transcriptPersistence.d.ts.map +0 -1
  280. package/lib/typescript/store/transcriptPersistence.test.d.ts.map +0 -1
  281. package/lib/typescript/store/useAskBuoy.d.ts.map +0 -1
  282. package/lib/typescript/store/useAskBuoySettings.d.ts.map +0 -1
  283. package/lib/typescript/sync/askBuoySyncAdapter.d.ts.map +0 -1
  284. package/lib/typescript/sync/askBuoySyncAdapter.test.d.ts.map +0 -1
  285. package/lib/typescript/sync/wire.d.ts.map +0 -1
  286. package/lib/typescript/types.d.ts.map +0 -1
@@ -1,1827 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Second-wave blocks from the survey (plan §11). Prototype-quality on purpose:
5
- * each one exists so it can be judged on the review page, and the ones that
6
- * survive get the same care as the first wave.
7
- */
8
- import { useEffect, useRef, useState } from "react";
9
- import { Animated, Image, Pressable, ScrollView, StyleSheet, Switch, Text, TextInput, View } from "react-native";
10
- import { AlertTriangle, Check, ChevronDown, ChevronRight, night, NightSegmented, RefreshCw, Search, X } from "@buoy-gg/shared-ui";
11
- import { BlockRenderer } from "./BlockRenderer";
12
- import { useBlockHandlers } from "./context";
13
- import { ActionRow, blockStyles as b, Card, More, toneColor, usePaged } from "./primitives";
14
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
15
- const fmt = v => typeof v === "string" ? v : v === undefined ? "—" : JSON.stringify(v);
16
-
17
- // ---------------------------------------------------------------- Suggestions
18
- export function Suggestions({
19
- block
20
- }) {
21
- const h = useBlockHandlers();
22
- return /*#__PURE__*/_jsx(View, {
23
- style: styles.chips,
24
- testID: `buoy-block-suggestions-${block.id}`,
25
- children: block.chips.slice(0, 4).map(c => /*#__PURE__*/_jsx(Pressable, {
26
- disabled: !!h.busy,
27
- onPress: () => void h.runAction({
28
- label: c.label,
29
- send: c.send ?? c.label
30
- }, block.id),
31
- style: ({
32
- pressed
33
- }) => [styles.chip, pressed && styles.pressed],
34
- accessibilityRole: "button",
35
- children: /*#__PURE__*/_jsx(Text, {
36
- style: styles.chipText,
37
- children: c.label
38
- })
39
- }, c.label))
40
- });
41
- }
42
-
43
- // ---------------------------------------------------------------- MultiSelect
44
- export function MultiSelect({
45
- block
46
- }) {
47
- const h = useBlockHandlers();
48
- const answer = h.answered[block.id];
49
- const locked = !!answer;
50
- const [picked, setPicked] = useState([]);
51
- const chosen = answer?.kind === "multi" ? answer.optionIds : picked;
52
- const toggle = id => setPicked(p => p.includes(id) ? p.filter(x => x !== id) : [...p, id]);
53
- const ok = picked.length >= (block.min ?? 1) && (!block.max || picked.length <= block.max);
54
- return /*#__PURE__*/_jsxs(Card, {
55
- testID: `buoy-block-multi-${block.id}`,
56
- tone: locked ? undefined : "info",
57
- children: [/*#__PURE__*/_jsx(Text, {
58
- style: styles.question,
59
- children: block.question
60
- }), /*#__PURE__*/_jsx(View, {
61
- style: styles.optionsBox,
62
- children: block.options.map((o, i) => {
63
- const on = chosen.includes(o.id);
64
- return /*#__PURE__*/_jsxs(Pressable, {
65
- disabled: locked,
66
- onPress: () => toggle(o.id),
67
- style: [styles.option, i > 0 && b.rowDivider, locked && !on && styles.dim],
68
- accessibilityRole: "checkbox",
69
- accessibilityState: {
70
- checked: on
71
- },
72
- children: [/*#__PURE__*/_jsx(View, {
73
- style: [styles.checkbox, on && styles.checkboxOn],
74
- children: on ? /*#__PURE__*/_jsx(Check, {
75
- size: 11,
76
- color: night.color.onAccent
77
- }) : null
78
- }), /*#__PURE__*/_jsxs(View, {
79
- style: styles.flex,
80
- children: [/*#__PURE__*/_jsx(Text, {
81
- style: styles.optionLabel,
82
- children: o.label
83
- }), o.detail ? /*#__PURE__*/_jsx(Text, {
84
- style: styles.optionDetail,
85
- children: o.detail
86
- }) : null]
87
- })]
88
- }, o.id);
89
- })
90
- }), locked ? null : /*#__PURE__*/_jsx(View, {
91
- style: styles.rowEnd,
92
- children: /*#__PURE__*/_jsx(Pressable, {
93
- testID: "buoy-block-multi-submit",
94
- disabled: !ok,
95
- onPress: () => h.answer({
96
- blockId: block.id,
97
- kind: "multi",
98
- optionIds: picked,
99
- labels: block.options.filter(o => picked.includes(o.id)).map(o => o.label)
100
- }),
101
- style: [styles.button, styles.buttonPrimary, !ok && styles.disabled],
102
- children: /*#__PURE__*/_jsx(Text, {
103
- style: styles.buttonTextPrimary,
104
- children: block.submitLabel ?? `Use ${picked.length || ""}`.trim()
105
- })
106
- })
107
- })]
108
- });
109
- }
110
-
111
- // ---------------------------------------------------------------- Select (long list)
112
- export function Select({
113
- block
114
- }) {
115
- const h = useBlockHandlers();
116
- const answer = h.answered[block.id];
117
- const [q, setQ] = useState("");
118
- const [open, setOpen] = useState(false);
119
- const chosen = answer?.kind === "select" ? answer.label : null;
120
- const items = block.options.filter(o => !q || o.label.toLowerCase().includes(q.toLowerCase())).slice(0, 8);
121
- return /*#__PURE__*/_jsxs(Card, {
122
- testID: `buoy-block-select-${block.id}`,
123
- tone: answer ? undefined : "info",
124
- children: [/*#__PURE__*/_jsx(Text, {
125
- style: styles.question,
126
- children: block.label
127
- }), chosen ? /*#__PURE__*/_jsx(Text, {
128
- style: styles.decided,
129
- children: chosen
130
- }) : /*#__PURE__*/_jsxs(View, {
131
- style: styles.selectBox,
132
- children: [/*#__PURE__*/_jsxs(Pressable, {
133
- onPress: () => setOpen(v => !v),
134
- style: styles.selectField,
135
- accessibilityRole: "button",
136
- children: [/*#__PURE__*/_jsx(Text, {
137
- style: styles.selectPlaceholder,
138
- children: open ? "Choose…" : `${block.options.length} options`
139
- }), /*#__PURE__*/_jsx(ChevronDown, {
140
- size: 14,
141
- color: night.color.textSecondary
142
- })]
143
- }), open && /*#__PURE__*/_jsxs(_Fragment, {
144
- children: [block.searchable !== false && /*#__PURE__*/_jsxs(View, {
145
- style: styles.search,
146
- children: [/*#__PURE__*/_jsx(Search, {
147
- size: 12,
148
- color: night.color.textSecondary
149
- }), /*#__PURE__*/_jsx(TextInput, {
150
- style: styles.searchInput,
151
- value: q,
152
- onChangeText: setQ,
153
- placeholder: "Search",
154
- placeholderTextColor: night.color.placeholder,
155
- autoCapitalize: "none",
156
- autoCorrect: false
157
- })]
158
- }), items.map((o, i) => /*#__PURE__*/_jsxs(Pressable, {
159
- onPress: () => h.answer({
160
- blockId: block.id,
161
- kind: "select",
162
- optionId: o.id,
163
- label: o.label
164
- }),
165
- style: [styles.option, i > 0 && b.rowDivider],
166
- accessibilityRole: "button",
167
- children: [/*#__PURE__*/_jsxs(View, {
168
- style: styles.flex,
169
- children: [/*#__PURE__*/_jsx(Text, {
170
- style: styles.optionLabel,
171
- children: o.label
172
- }), o.detail ? /*#__PURE__*/_jsx(Text, {
173
- style: styles.optionDetail,
174
- children: o.detail
175
- }) : null]
176
- }), /*#__PURE__*/_jsx(ChevronRight, {
177
- size: 12,
178
- color: night.color.textTertiary
179
- })]
180
- }, o.id)), block.options.length > items.length ? /*#__PURE__*/_jsxs(Text, {
181
- style: styles.hint,
182
- children: [block.options.length - items.length, " more \u2014 keep typing"]
183
- }) : null]
184
- })]
185
- })]
186
- });
187
- }
188
-
189
- // ---------------------------------------------------------------- Slider
190
- /**
191
- * Tap anywhere on the track to jump there, or use the − / + steppers. No drag
192
- * on purpose: a drag inside a scrolling transcript fights the list for the
193
- * gesture, and a tap-to-place slider does the job with none of that.
194
- */
195
- function SliderControl({
196
- min,
197
- max,
198
- step = 1,
199
- value,
200
- unit,
201
- onChange,
202
- disabled
203
- }) {
204
- const width = useRef(0);
205
- const pct = max > min ? (value - min) / (max - min) * 100 : 0;
206
- const quantise = raw => Math.min(max, Math.max(min, +(Math.round((raw - min) / step) * step + min).toFixed(6)));
207
- const bump = d => !disabled && onChange(quantise(value + d * step));
208
- const onTrackPress = e => {
209
- if (disabled || width.current <= 0) return;
210
- const ratio = Math.min(1, Math.max(0, e.nativeEvent.locationX / width.current));
211
- onChange(quantise(min + ratio * (max - min)));
212
- };
213
- const onLayout = e => {
214
- width.current = e.nativeEvent.layout.width;
215
- };
216
- return /*#__PURE__*/_jsxs(View, {
217
- style: styles.sliderRow,
218
- children: [/*#__PURE__*/_jsx(Pressable, {
219
- disabled: disabled,
220
- onPress: () => bump(-1),
221
- style: styles.stepBtn,
222
- accessibilityRole: "button",
223
- accessibilityLabel: "Decrease",
224
- children: /*#__PURE__*/_jsx(Text, {
225
- style: styles.stepText,
226
- children: "\u2212"
227
- })
228
- }), /*#__PURE__*/_jsx(Pressable, {
229
- style: styles.trackHit,
230
- onLayout: onLayout,
231
- onPress: onTrackPress,
232
- disabled: disabled,
233
- accessibilityRole: "adjustable",
234
- accessibilityValue: {
235
- min,
236
- max,
237
- now: value
238
- },
239
- accessibilityActions: [{
240
- name: "increment"
241
- }, {
242
- name: "decrement"
243
- }],
244
- onAccessibilityAction: e => bump(e.nativeEvent.actionName === "increment" ? 1 : -1),
245
- children: /*#__PURE__*/_jsxs(View, {
246
- style: styles.track,
247
- pointerEvents: "none",
248
- children: [/*#__PURE__*/_jsx(View, {
249
- style: [styles.fill, {
250
- width: `${pct}%`
251
- }]
252
- }), /*#__PURE__*/_jsx(View, {
253
- style: [styles.thumb, {
254
- left: `${pct}%`
255
- }]
256
- })]
257
- })
258
- }), /*#__PURE__*/_jsx(Pressable, {
259
- disabled: disabled,
260
- onPress: () => bump(1),
261
- style: styles.stepBtn,
262
- accessibilityRole: "button",
263
- accessibilityLabel: "Increase",
264
- children: /*#__PURE__*/_jsx(Text, {
265
- style: styles.stepText,
266
- children: "+"
267
- })
268
- }), /*#__PURE__*/_jsxs(Text, {
269
- style: styles.sliderValue,
270
- children: [value, unit ? ` ${unit}` : ""]
271
- })]
272
- });
273
- }
274
- export function Slider({
275
- block
276
- }) {
277
- const h = useBlockHandlers();
278
- const answer = h.answered[block.id];
279
- const [v, setV] = useState(block.value ?? block.min);
280
- return /*#__PURE__*/_jsxs(Card, {
281
- testID: `buoy-block-slider-${block.id}`,
282
- tone: answer ? undefined : "info",
283
- children: [/*#__PURE__*/_jsx(Text, {
284
- style: styles.question,
285
- children: block.label
286
- }), /*#__PURE__*/_jsx(View, {
287
- style: styles.pad,
288
- children: /*#__PURE__*/_jsx(SliderControl, {
289
- min: block.min,
290
- max: block.max,
291
- step: block.step,
292
- value: answer?.kind === "slider" ? answer.value : v,
293
- unit: block.unit,
294
- onChange: setV,
295
- disabled: !!answer
296
- })
297
- }), answer ? null : /*#__PURE__*/_jsx(View, {
298
- style: styles.rowEnd,
299
- children: /*#__PURE__*/_jsx(Pressable, {
300
- onPress: () => h.answer({
301
- blockId: block.id,
302
- kind: "slider",
303
- value: v,
304
- unit: block.unit
305
- }),
306
- style: [styles.button, styles.buttonPrimary],
307
- children: /*#__PURE__*/_jsxs(Text, {
308
- style: styles.buttonTextPrimary,
309
- children: ["Use ", v, block.unit ? ` ${block.unit}` : ""]
310
- })
311
- })
312
- })]
313
- });
314
- }
315
-
316
- // ---------------------------------------------------------------- DateTime
317
- export function DateTime({
318
- block
319
- }) {
320
- const h = useBlockHandlers();
321
- const answer = h.answered[block.id];
322
- const [text, setText] = useState("");
323
- const presets = block.presets ?? [{
324
- label: "Now",
325
- value: new Date().toISOString()
326
- }, {
327
- label: "Tomorrow",
328
- value: new Date(Date.now() + 864e5).toISOString()
329
- }, {
330
- label: "+7 days",
331
- value: new Date(Date.now() + 7 * 864e5).toISOString()
332
- }, {
333
- label: "+30 days",
334
- value: new Date(Date.now() + 30 * 864e5).toISOString()
335
- }];
336
- return /*#__PURE__*/_jsxs(Card, {
337
- testID: `buoy-block-datetime-${block.id}`,
338
- tone: answer ? undefined : "info",
339
- children: [/*#__PURE__*/_jsx(Text, {
340
- style: styles.question,
341
- children: block.label
342
- }), answer ? /*#__PURE__*/_jsx(Text, {
343
- style: styles.decided,
344
- children: answer.kind === "dateTime" ? answer.label ?? answer.value : "(skipped)"
345
- }) : /*#__PURE__*/_jsxs(_Fragment, {
346
- children: [/*#__PURE__*/_jsx(View, {
347
- style: [styles.chips, styles.pad],
348
- children: presets.map(p => /*#__PURE__*/_jsx(Pressable, {
349
- onPress: () => h.answer({
350
- blockId: block.id,
351
- kind: "dateTime",
352
- value: p.value,
353
- label: p.label
354
- }),
355
- style: styles.chip,
356
- children: /*#__PURE__*/_jsx(Text, {
357
- style: styles.chipText,
358
- children: p.label
359
- })
360
- }, p.label))
361
- }), /*#__PURE__*/_jsxs(View, {
362
- style: [styles.inputRow, styles.pad],
363
- children: [/*#__PURE__*/_jsx(TextInput, {
364
- style: styles.input,
365
- value: text,
366
- onChangeText: setText,
367
- placeholder: block.mode === "time" ? "14:30" : "2026-09-15",
368
- placeholderTextColor: night.color.placeholder,
369
- keyboardType: "numbers-and-punctuation"
370
- }), /*#__PURE__*/_jsx(Pressable, {
371
- disabled: !text.trim(),
372
- onPress: () => h.answer({
373
- blockId: block.id,
374
- kind: "dateTime",
375
- value: text.trim()
376
- }),
377
- style: [styles.button, styles.buttonPrimary, !text.trim() && styles.disabled],
378
- children: /*#__PURE__*/_jsx(Text, {
379
- style: styles.buttonTextPrimary,
380
- children: "Use"
381
- })
382
- })]
383
- })]
384
- })]
385
- });
386
- }
387
-
388
- // ---------------------------------------------------------------- Form / Proposal
389
- function FieldRow({
390
- f,
391
- value,
392
- onChange,
393
- disabled
394
- }) {
395
- if (f.type === "toggle") {
396
- return /*#__PURE__*/_jsxs(View, {
397
- style: styles.fieldRow,
398
- children: [/*#__PURE__*/_jsx(Text, {
399
- style: styles.fieldLabel,
400
- children: f.label
401
- }), /*#__PURE__*/_jsx(Switch, {
402
- value: !!value,
403
- onValueChange: onChange,
404
- disabled: disabled,
405
- trackColor: {
406
- true: night.color.accent,
407
- false: night.color.fillTertiary
408
- },
409
- thumbColor: night.color.knob
410
- })]
411
- });
412
- }
413
- if (f.type === "select") {
414
- return /*#__PURE__*/_jsxs(View, {
415
- style: styles.fieldCol,
416
- children: [/*#__PURE__*/_jsx(Text, {
417
- style: styles.fieldLabel,
418
- children: f.label
419
- }), /*#__PURE__*/_jsx(View, {
420
- style: styles.chips,
421
- children: f.options.map(o => /*#__PURE__*/_jsx(Pressable, {
422
- disabled: disabled,
423
- onPress: () => onChange(o.id),
424
- style: [styles.chip, value === o.id && styles.chipOn],
425
- children: /*#__PURE__*/_jsx(Text, {
426
- style: [styles.chipText, value === o.id && styles.chipTextOn],
427
- children: o.label
428
- })
429
- }, o.id))
430
- })]
431
- });
432
- }
433
- if (f.type === "slider") {
434
- return /*#__PURE__*/_jsxs(View, {
435
- style: styles.fieldCol,
436
- children: [/*#__PURE__*/_jsx(Text, {
437
- style: styles.fieldLabel,
438
- children: f.label
439
- }), /*#__PURE__*/_jsx(SliderControl, {
440
- min: f.min,
441
- max: f.max,
442
- step: f.step,
443
- unit: f.unit,
444
- value: typeof value === "number" ? value : f.min,
445
- onChange: onChange,
446
- disabled: disabled
447
- })]
448
- });
449
- }
450
- return /*#__PURE__*/_jsxs(View, {
451
- style: styles.fieldRow,
452
- children: [/*#__PURE__*/_jsx(Text, {
453
- style: styles.fieldLabel,
454
- children: f.label
455
- }), /*#__PURE__*/_jsx(TextInput, {
456
- style: styles.fieldInput,
457
- value: value === undefined || value === null ? "" : String(value),
458
- onChangeText: onChange,
459
- editable: !disabled,
460
- placeholder: f.placeholder ?? "",
461
- placeholderTextColor: night.color.placeholder,
462
- keyboardType: f.type === "number" ? "numeric" : "ascii-capable",
463
- secureTextEntry: f.type === "secret",
464
- autoCapitalize: "none",
465
- autoCorrect: false
466
- })]
467
- });
468
- }
469
- function useFormValues(fields) {
470
- const [values, setValues] = useState(() => Object.fromEntries(fields.map(f => [f.key, f.value])));
471
- return {
472
- values,
473
- set: (k, v) => setValues(m => ({
474
- ...m,
475
- [k]: v
476
- }))
477
- };
478
- }
479
- export function Form({
480
- block
481
- }) {
482
- const h = useBlockHandlers();
483
- const answer = h.answered[block.id];
484
- const {
485
- values,
486
- set
487
- } = useFormValues(block.fields);
488
- return /*#__PURE__*/_jsxs(Card, {
489
- title: block.title,
490
- testID: `buoy-block-form-${block.id}`,
491
- tone: answer ? undefined : "info",
492
- children: [/*#__PURE__*/_jsx(View, {
493
- style: styles.pad,
494
- children: block.fields.map(f => /*#__PURE__*/_jsx(FieldRow, {
495
- f: f,
496
- value: values[f.key],
497
- onChange: v => set(f.key, v),
498
- disabled: !!answer
499
- }, f.key))
500
- }), answer ? /*#__PURE__*/_jsx(Text, {
501
- style: styles.decided,
502
- children: "Sent"
503
- }) : /*#__PURE__*/_jsx(View, {
504
- style: styles.rowEnd,
505
- children: /*#__PURE__*/_jsx(Pressable, {
506
- onPress: () => h.answer({
507
- blockId: block.id,
508
- kind: "form",
509
- values
510
- }),
511
- style: [styles.button, styles.buttonPrimary],
512
- children: /*#__PURE__*/_jsx(Text, {
513
- style: styles.buttonTextPrimary,
514
- children: block.submitLabel ?? "Send"
515
- })
516
- })
517
- })]
518
- });
519
- }
520
- export function Proposal({
521
- block
522
- }) {
523
- const h = useBlockHandlers();
524
- const answer = h.answered[block.id];
525
- const {
526
- values,
527
- set
528
- } = useFormValues(block.fields);
529
- const approved = answer?.kind === "proposal" ? answer.approved : null;
530
- return /*#__PURE__*/_jsxs(Card, {
531
- testID: `buoy-block-proposal-${block.id}`,
532
- tone: answer ? undefined : "warning",
533
- children: [/*#__PURE__*/_jsx(Text, {
534
- style: styles.confirmTitle,
535
- children: block.title
536
- }), /*#__PURE__*/_jsx(Text, {
537
- style: styles.confirmChange,
538
- children: block.change
539
- }), /*#__PURE__*/_jsx(View, {
540
- style: styles.pad,
541
- children: block.fields.map(f => /*#__PURE__*/_jsx(FieldRow, {
542
- f: f,
543
- value: values[f.key],
544
- onChange: v => set(f.key, v),
545
- disabled: !!answer
546
- }, f.key))
547
- }), block.consequence ? /*#__PURE__*/_jsx(Text, {
548
- style: styles.consequence,
549
- children: block.consequence
550
- }) : null, /*#__PURE__*/_jsx(View, {
551
- style: styles.actionsRow,
552
- children: answer ? /*#__PURE__*/_jsx(Text, {
553
- style: styles.decided,
554
- children: approved ? "✓ Applied with these values" : "✕ Not applied"
555
- }) : /*#__PURE__*/_jsxs(_Fragment, {
556
- children: [/*#__PURE__*/_jsx(Pressable, {
557
- onPress: () => h.answer({
558
- blockId: block.id,
559
- kind: "proposal",
560
- approved: true,
561
- values
562
- }),
563
- style: [styles.button, styles.buttonPrimary],
564
- children: /*#__PURE__*/_jsx(Text, {
565
- style: styles.buttonTextPrimary,
566
- children: block.approveLabel ?? "Apply"
567
- })
568
- }), /*#__PURE__*/_jsx(Pressable, {
569
- onPress: () => h.answer({
570
- blockId: block.id,
571
- kind: "proposal",
572
- approved: false
573
- }),
574
- style: [styles.button, styles.buttonPlate],
575
- children: /*#__PURE__*/_jsx(Text, {
576
- style: styles.buttonTextPlate,
577
- children: "Not now"
578
- })
579
- })]
580
- })
581
- })]
582
- });
583
- }
584
-
585
- // ---------------------------------------------------------------- Claim (citations + verify)
586
- export function Claim({
587
- block
588
- }) {
589
- const h = useBlockHandlers();
590
- const [open, setOpen] = useState(null);
591
- const state = h.actionState?.[`${block.id}:${block.verify?.label ?? "Verify"}`];
592
- const verified = block.verified || state === "done";
593
- return /*#__PURE__*/_jsxs(View, {
594
- style: styles.claim,
595
- testID: `buoy-block-claim-${block.id}`,
596
- children: [/*#__PURE__*/_jsxs(Text, {
597
- style: styles.claimText,
598
- children: [block.text, block.sources.map((s, i) => /*#__PURE__*/_jsxs(Text, {
599
- onPress: () => setOpen(open === i ? null : i),
600
- style: styles.cite,
601
- children: [" [", i + 1, "]"]
602
- }, i)), verified ? /*#__PURE__*/_jsx(Text, {
603
- style: styles.verified,
604
- children: " \u2713 verified"
605
- }) : null]
606
- }), open !== null && block.sources[open] ? /*#__PURE__*/_jsxs(View, {
607
- style: styles.citeBox,
608
- children: [/*#__PURE__*/_jsxs(Text, {
609
- style: styles.citeLabel,
610
- children: ["[", open + 1, "] ", block.sources[open].label]
611
- }), block.sources[open].detail ? /*#__PURE__*/_jsx(Text, {
612
- style: styles.citeDetail,
613
- children: block.sources[open].detail
614
- }) : null]
615
- }) : null, block.verify && !verified ? /*#__PURE__*/_jsxs(Pressable, {
616
- onPress: () => void h.runAction(block.verify, block.id),
617
- style: styles.verifyBtn,
618
- accessibilityRole: "button",
619
- children: [/*#__PURE__*/_jsx(RefreshCw, {
620
- size: 11,
621
- color: night.color.accent
622
- }), /*#__PURE__*/_jsx(Text, {
623
- style: styles.verifyText,
624
- children: state === "running" ? "Checking…" : block.verify.label
625
- })]
626
- }) : null]
627
- });
628
- }
629
-
630
- // ---------------------------------------------------------------- Details / Tabs
631
- export function Details({
632
- block
633
- }) {
634
- const [open, setOpen] = useState(!!block.open);
635
- return /*#__PURE__*/_jsxs(Card, {
636
- testID: `buoy-block-details-${block.id}`,
637
- children: [/*#__PURE__*/_jsxs(Pressable, {
638
- onPress: () => setOpen(v => !v),
639
- style: b.row,
640
- accessibilityRole: "button",
641
- accessibilityState: {
642
- expanded: open
643
- },
644
- children: [/*#__PURE__*/_jsx(Text, {
645
- style: b.rowTitle,
646
- children: block.summary
647
- }), open ? /*#__PURE__*/_jsx(ChevronDown, {
648
- size: 12,
649
- color: night.color.textTertiary
650
- }) : /*#__PURE__*/_jsx(ChevronRight, {
651
- size: 12,
652
- color: night.color.textTertiary
653
- })]
654
- }), open ? /*#__PURE__*/_jsx(Text, {
655
- style: styles.detailsBody,
656
- selectable: true,
657
- children: block.body
658
- }) : null]
659
- });
660
- }
661
-
662
- /**
663
- * The tool-header segmented control, not a strip of this block's own.
664
- *
665
- * `NightSegmented` is what the dial settings and the network tool mount, so a
666
- * tabbed block now reads as part of the same product rather than as a
667
- * lookalike drawn next to it. `sm` is its compact variant, which is what a
668
- * control inside a chat bubble wants.
669
- *
670
- * Keyed by INDEX, not label: two tabs may legitimately share a label, and a
671
- * duplicate key would collapse them into one.
672
- */
673
- export function Tabs({
674
- block
675
- }) {
676
- const [i, setI] = useState(0);
677
- const tabs = block.tabs.map((t, k) => ({
678
- key: String(k),
679
- label: t.label
680
- }));
681
- const active = block.tabs[i];
682
- return /*#__PURE__*/_jsxs(View, {
683
- style: styles.tabsWrap,
684
- testID: `buoy-block-tabs-${block.id}`,
685
- children: [/*#__PURE__*/_jsx(NightSegmented, {
686
- tabs: tabs,
687
- activeKey: String(i),
688
- onChange: key => setI(Number(key)),
689
- size: "sm"
690
- }), active ? /*#__PURE__*/_jsx(BlockRenderer, {
691
- block: active.block
692
- }) : null]
693
- });
694
- }
695
-
696
- // ---------------------------------------------------------------- Timeline
697
- /** Ten fits a phone without the answer above it scrolling away. */
698
- const TIMELINE_CAP = 10;
699
- export function Timeline({
700
- block
701
- }) {
702
- /**
703
- * The cap used to be a bare `.slice(0, 10)` while the "+N more" line below
704
- * compared `total` against the FULL event array — so eleven events with a
705
- * matching total rendered ten and said nothing about the eleventh, and a
706
- * total larger than the array rendered a "+N more" that was only ever a
707
- * label. Both counts come from the pager now.
708
- */
709
- const paged = usePaged(block.events, TIMELINE_CAP);
710
- return /*#__PURE__*/_jsxs(Card, {
711
- title: block.title ?? "What happened",
712
- source: block.source,
713
- testID: `buoy-block-timeline-${block.id}`,
714
- children: [paged.visible.map((e, i) => /*#__PURE__*/_jsxs(View, {
715
- style: styles.tlRow,
716
- children: [/*#__PURE__*/_jsx(Text, {
717
- style: styles.tlAt,
718
- children: e.at
719
- }), /*#__PURE__*/_jsxs(View, {
720
- style: styles.tlLine,
721
- children: [/*#__PURE__*/_jsx(View, {
722
- style: [styles.tlDot, {
723
- backgroundColor: toneColor(e.tone ?? "muted")
724
- }]
725
- }), i < paged.visible.length - 1 ? /*#__PURE__*/_jsx(View, {
726
- style: styles.tlStem
727
- }) : null]
728
- }), /*#__PURE__*/_jsxs(View, {
729
- style: styles.flex,
730
- children: [/*#__PURE__*/_jsx(Text, {
731
- style: styles.tlSource,
732
- children: e.source.toUpperCase()
733
- }), /*#__PURE__*/_jsx(Text, {
734
- style: b.rowTitle,
735
- numberOfLines: 2,
736
- children: e.label
737
- })]
738
- })]
739
- }, i)), /*#__PURE__*/_jsx(More, {
740
- paged: paged
741
- })]
742
- });
743
- }
744
-
745
- // ---------------------------------------------------------------- Sparkline
746
- export function Sparkline({
747
- block
748
- }) {
749
- const s = block.series.slice(-60);
750
- const max = Math.max(1, ...s);
751
- const min = Math.min(...s, 0);
752
- const H = 44;
753
- return /*#__PURE__*/_jsxs(Card, {
754
- title: block.title,
755
- source: block.source,
756
- testID: `buoy-block-sparkline-${block.id}`,
757
- children: [/*#__PURE__*/_jsxs(View, {
758
- style: styles.sparkHead,
759
- children: [/*#__PURE__*/_jsxs(Text, {
760
- style: styles.sparkCurrent,
761
- children: [block.current ?? s[s.length - 1], block.unit ? /*#__PURE__*/_jsxs(Text, {
762
- style: styles.sparkUnit,
763
- children: [" ", block.unit]
764
- }) : null]
765
- }), block.live ? /*#__PURE__*/_jsx(LivePill, {}) : null]
766
- }), /*#__PURE__*/_jsx(View, {
767
- style: [styles.spark, {
768
- height: H
769
- }],
770
- children: s.map((v, i) => /*#__PURE__*/_jsx(View, {
771
- style: [styles.sparkBar, {
772
- height: Math.max(2, (v - min) / (max - min || 1) * H),
773
- backgroundColor: i === s.length - 1 ? night.color.accent : night.color.accentBorderStrong
774
- }]
775
- }, i))
776
- }), block.label ? /*#__PURE__*/_jsx(Text, {
777
- style: styles.hint,
778
- children: block.label
779
- }) : null]
780
- });
781
- }
782
- export function LivePill() {
783
- const o = useRef(new Animated.Value(1)).current;
784
- useEffect(() => {
785
- const loop = Animated.loop(Animated.sequence([Animated.timing(o, {
786
- toValue: 0.3,
787
- duration: 700,
788
- useNativeDriver: true
789
- }), Animated.timing(o, {
790
- toValue: 1,
791
- duration: 700,
792
- useNativeDriver: true
793
- })]));
794
- loop.start();
795
- return () => loop.stop();
796
- }, [o]);
797
- return /*#__PURE__*/_jsxs(View, {
798
- style: styles.live,
799
- children: [/*#__PURE__*/_jsx(Animated.View, {
800
- style: [styles.liveDot, {
801
- opacity: o
802
- }]
803
- }), /*#__PURE__*/_jsx(Text, {
804
- style: styles.liveText,
805
- children: "LIVE"
806
- })]
807
- });
808
- }
809
-
810
- // ---------------------------------------------------------------- Compare
811
- export function Compare({
812
- block
813
- }) {
814
- const keys = [...new Set([...block.left.pairs.map(p => p.key), ...block.right.pairs.map(p => p.key)])];
815
- const l = Object.fromEntries(block.left.pairs.map(p => [p.key, p.value]));
816
- const r = Object.fromEntries(block.right.pairs.map(p => [p.key, p.value]));
817
- return /*#__PURE__*/_jsxs(Card, {
818
- title: block.title,
819
- source: block.source,
820
- testID: `buoy-block-compare-${block.id}`,
821
- children: [/*#__PURE__*/_jsxs(View, {
822
- style: styles.cmpHead,
823
- children: [/*#__PURE__*/_jsx(Text, {
824
- style: styles.cmpKey
825
- }), /*#__PURE__*/_jsx(Text, {
826
- style: styles.cmpCol,
827
- children: block.left.title
828
- }), /*#__PURE__*/_jsx(Text, {
829
- style: styles.cmpCol,
830
- children: block.right.title
831
- })]
832
- }), keys.map((k, i) => {
833
- const diff = JSON.stringify(l[k]) !== JSON.stringify(r[k]);
834
- return /*#__PURE__*/_jsxs(View, {
835
- style: [styles.cmpRow, i > 0 && b.rowDivider, diff && styles.cmpDiff],
836
- children: [/*#__PURE__*/_jsx(Text, {
837
- style: styles.cmpKey,
838
- numberOfLines: 1,
839
- children: k
840
- }), /*#__PURE__*/_jsx(Text, {
841
- style: [styles.cmpVal, diff && {
842
- color: night.color.danger
843
- }],
844
- numberOfLines: 2,
845
- children: fmt(l[k])
846
- }), /*#__PURE__*/_jsx(Text, {
847
- style: [styles.cmpVal, diff && {
848
- color: night.color.accent
849
- }],
850
- numberOfLines: 2,
851
- children: fmt(r[k])
852
- })]
853
- }, k);
854
- })]
855
- });
856
- }
857
-
858
- // ---------------------------------------------------------------- Card / carousel
859
- function CardBody({
860
- c,
861
- id
862
- }) {
863
- return /*#__PURE__*/_jsxs(_Fragment, {
864
- children: [c.image ? /*#__PURE__*/_jsx(Image, {
865
- source: {
866
- uri: c.image
867
- },
868
- style: styles.cardImage,
869
- resizeMode: "contain",
870
- accessibilityLabel: c.title
871
- }) : null, /*#__PURE__*/_jsxs(View, {
872
- style: styles.cardText,
873
- children: [/*#__PURE__*/_jsx(Text, {
874
- style: styles.cardTitle,
875
- numberOfLines: 2,
876
- children: c.title
877
- }), c.subtitle ? /*#__PURE__*/_jsx(Text, {
878
- style: b.rowSub,
879
- numberOfLines: 2,
880
- children: c.subtitle
881
- }) : null, c.facts?.slice(0, 4).map(f => /*#__PURE__*/_jsxs(View, {
882
- style: styles.fact,
883
- children: [/*#__PURE__*/_jsx(Text, {
884
- style: styles.factLabel,
885
- children: f.label
886
- }), /*#__PURE__*/_jsx(Text, {
887
- style: [styles.factValue, f.tone && {
888
- color: toneColor(f.tone)
889
- }],
890
- children: f.value
891
- })]
892
- }, f.label))]
893
- }), /*#__PURE__*/_jsx(ActionRow, {
894
- actions: c.actions,
895
- blockId: id
896
- })]
897
- });
898
- }
899
- export function CardView({
900
- block
901
- }) {
902
- return /*#__PURE__*/_jsx(Card, {
903
- source: block.source,
904
- testID: `buoy-block-card-${block.id}`,
905
- children: /*#__PURE__*/_jsx(CardBody, {
906
- c: block,
907
- id: block.id
908
- })
909
- });
910
- }
911
- export function CardCarousel({
912
- block
913
- }) {
914
- return /*#__PURE__*/_jsxs(View, {
915
- testID: `buoy-block-cardcarousel-${block.id}`,
916
- children: [block.title ? /*#__PURE__*/_jsx(Text, {
917
- style: styles.carouselTitle,
918
- children: block.title
919
- }) : null, /*#__PURE__*/_jsx(ScrollView, {
920
- horizontal: true,
921
- showsHorizontalScrollIndicator: false,
922
- snapToInterval: 232,
923
- decelerationRate: "fast",
924
- contentContainerStyle: styles.carousel,
925
- children: block.cards.slice(0, 8).map((c, i) => /*#__PURE__*/_jsx(View, {
926
- style: styles.carouselCard,
927
- children: /*#__PURE__*/_jsx(CardBody, {
928
- c: c,
929
- id: `${block.id}-${i}`
930
- })
931
- }, `${c.title}-${i}`))
932
- })]
933
- });
934
- }
935
-
936
- // ---------------------------------------------------------------- Screenshot
937
- export function Screenshot({
938
- block
939
- }) {
940
- const [big, setBig] = useState(false);
941
- return /*#__PURE__*/_jsxs(Card, {
942
- title: block.route ? `Screen · ${block.route}` : "Screen",
943
- source: block.source,
944
- testID: `buoy-block-screenshot-${block.id}`,
945
- children: [/*#__PURE__*/_jsx(Pressable, {
946
- onPress: () => setBig(v => !v),
947
- accessibilityRole: "imagebutton",
948
- accessibilityLabel: block.caption ?? "Screenshot",
949
- children: /*#__PURE__*/_jsx(Image, {
950
- source: {
951
- uri: block.url
952
- },
953
- style: [styles.shot, big && styles.shotBig],
954
- resizeMode: "contain"
955
- })
956
- }), block.caption ? /*#__PURE__*/_jsx(Text, {
957
- style: styles.hint,
958
- children: block.caption
959
- }) : null]
960
- });
961
- }
962
-
963
- // ---------------------------------------------------------------- Plan / Checkpoint / Task
964
- export function Plan({
965
- block
966
- }) {
967
- const done = block.steps.filter(s => s.state === "done").length;
968
- return /*#__PURE__*/_jsxs(Card, {
969
- title: block.title,
970
- testID: `buoy-block-plan-${block.id}`,
971
- tone: block.pending ? "info" : undefined,
972
- children: [/*#__PURE__*/_jsx(View, {
973
- style: styles.progress,
974
- children: /*#__PURE__*/_jsx(View, {
975
- style: [styles.progressFill, {
976
- width: `${done / Math.max(1, block.steps.length) * 100}%`
977
- }]
978
- })
979
- }), block.steps.map((s, i) => /*#__PURE__*/_jsxs(View, {
980
- style: [styles.step, i > 0 && b.rowDivider],
981
- children: [/*#__PURE__*/_jsx(View, {
982
- style: [styles.stepMark, s.state === "done" && styles.stepDone, s.state === "failed" && styles.stepFailed, s.state === "running" && styles.stepRunning],
983
- children: s.state === "done" ? /*#__PURE__*/_jsx(Check, {
984
- size: 10,
985
- color: night.color.onAccent
986
- }) : s.state === "failed" ? /*#__PURE__*/_jsx(X, {
987
- size: 10,
988
- color: night.color.text
989
- }) : /*#__PURE__*/_jsx(Text, {
990
- style: styles.stepNum,
991
- children: i + 1
992
- })
993
- }), /*#__PURE__*/_jsxs(Text, {
994
- style: [b.rowTitle, s.state === "done" && styles.muted],
995
- children: [s.text, s.state === "running" ? "…" : ""]
996
- })]
997
- }, i)), /*#__PURE__*/_jsx(ActionRow, {
998
- actions: block.actions ?? (block.pending ? [{
999
- label: "Go",
1000
- primary: true,
1001
- send: "Go ahead with the plan."
1002
- }, {
1003
- label: "Change it",
1004
- send: "Let me change the plan first."
1005
- }] : undefined),
1006
- blockId: block.id
1007
- })]
1008
- });
1009
- }
1010
- export function Checkpoint({
1011
- block
1012
- }) {
1013
- const h = useBlockHandlers();
1014
- return /*#__PURE__*/_jsxs(Pressable, {
1015
- testID: `buoy-block-checkpoint-${block.id}`,
1016
- disabled: !block.restore,
1017
- onPress: () => block.restore && void h.runAction(block.restore, block.id),
1018
- style: styles.checkpoint,
1019
- accessibilityRole: "button",
1020
- children: [/*#__PURE__*/_jsx(View, {
1021
- style: styles.cpFlag
1022
- }), /*#__PURE__*/_jsxs(Text, {
1023
- style: styles.cpText,
1024
- children: [block.label, block.at ? ` · ${block.at}` : ""]
1025
- }), block.restore ? /*#__PURE__*/_jsx(Text, {
1026
- style: styles.cpRestore,
1027
- children: block.restore.label
1028
- }) : null]
1029
- });
1030
- }
1031
- export function Task({
1032
- block
1033
- }) {
1034
- const color = block.status === "failed" ? night.color.danger : block.status === "done" ? night.color.accent : night.color.info;
1035
- return /*#__PURE__*/_jsxs(Card, {
1036
- testID: `buoy-block-task-${block.id}`,
1037
- children: [/*#__PURE__*/_jsxs(View, {
1038
- style: styles.taskHead,
1039
- children: [/*#__PURE__*/_jsx(Text, {
1040
- style: styles.cardTitle,
1041
- children: block.title
1042
- }), /*#__PURE__*/_jsx(View, {
1043
- style: [b.pill, {
1044
- backgroundColor: `${color}22`
1045
- }],
1046
- children: /*#__PURE__*/_jsx(Text, {
1047
- style: [b.pillText, {
1048
- color
1049
- }],
1050
- children: block.status.toUpperCase()
1051
- })
1052
- })]
1053
- }), block.progress !== undefined ? /*#__PURE__*/_jsx(View, {
1054
- style: [styles.progress, styles.pad],
1055
- children: /*#__PURE__*/_jsx(View, {
1056
- style: [styles.progressFill, {
1057
- width: `${Math.round(block.progress * 100)}%`,
1058
- backgroundColor: color
1059
- }]
1060
- })
1061
- }) : null, block.detail ? /*#__PURE__*/_jsx(Text, {
1062
- style: styles.hint,
1063
- children: block.detail
1064
- }) : null, /*#__PURE__*/_jsx(ActionRow, {
1065
- actions: block.actions,
1066
- blockId: block.id
1067
- })]
1068
- });
1069
- }
1070
-
1071
- // ---------------------------------------------------------------- Banner / File / Upload / NotBuilt
1072
- export function Banner({
1073
- block
1074
- }) {
1075
- const color = block.tone === "danger" ? night.color.danger : block.tone === "warning" ? night.color.warning : night.color.info;
1076
- return /*#__PURE__*/_jsxs(View, {
1077
- style: [styles.banner, {
1078
- borderColor: color,
1079
- backgroundColor: `${color}1A`
1080
- }],
1081
- testID: `buoy-block-banner-${block.id}`,
1082
- children: [/*#__PURE__*/_jsx(AlertTriangle, {
1083
- size: 13,
1084
- color: color
1085
- }), /*#__PURE__*/_jsx(Text, {
1086
- style: [styles.bannerText, {
1087
- color
1088
- }],
1089
- numberOfLines: 2,
1090
- children: block.text
1091
- }), block.actions?.[0] ? /*#__PURE__*/_jsx(ActionRow, {
1092
- actions: block.actions.slice(0, 1),
1093
- blockId: block.id,
1094
- align: "right"
1095
- }) : null]
1096
- });
1097
- }
1098
- export function File({
1099
- block
1100
- }) {
1101
- return /*#__PURE__*/_jsxs(Card, {
1102
- testID: `buoy-block-file-${block.id}`,
1103
- children: [/*#__PURE__*/_jsxs(View, {
1104
- style: b.row,
1105
- children: [/*#__PURE__*/_jsx(View, {
1106
- style: styles.fileIcon,
1107
- children: /*#__PURE__*/_jsx(Text, {
1108
- style: styles.fileExt,
1109
- children: (block.type ?? block.name.split(".").pop() ?? "file").toUpperCase().slice(0, 4)
1110
- })
1111
- }), /*#__PURE__*/_jsxs(View, {
1112
- style: styles.flex,
1113
- children: [/*#__PURE__*/_jsx(Text, {
1114
- style: b.rowTitle,
1115
- numberOfLines: 1,
1116
- children: block.name
1117
- }), block.size ? /*#__PURE__*/_jsx(Text, {
1118
- style: b.rowSub,
1119
- children: block.size
1120
- }) : null]
1121
- })]
1122
- }), /*#__PURE__*/_jsx(ActionRow, {
1123
- actions: block.actions,
1124
- blockId: block.id
1125
- })]
1126
- });
1127
- }
1128
- export function Upload({
1129
- block
1130
- }) {
1131
- const h = useBlockHandlers();
1132
- const answer = h.answered[block.id];
1133
- return /*#__PURE__*/_jsxs(Card, {
1134
- testID: `buoy-block-upload-${block.id}`,
1135
- tone: answer ? undefined : "info",
1136
- children: [/*#__PURE__*/_jsx(Text, {
1137
- style: styles.question,
1138
- children: block.label
1139
- }), answer ? /*#__PURE__*/_jsx(Text, {
1140
- style: styles.decided,
1141
- children: answer.kind === "upload" ? `Attached ${answer.name}` : "(skipped)"
1142
- }) : /*#__PURE__*/_jsx(View, {
1143
- style: [styles.rowEnd, {
1144
- justifyContent: "flex-start"
1145
- }],
1146
- children: /*#__PURE__*/_jsx(Pressable, {
1147
- onPress: () => h.answer({
1148
- blockId: block.id,
1149
- kind: "upload",
1150
- name: "screenshot.png"
1151
- }),
1152
- style: [styles.button, styles.buttonPlate],
1153
- children: /*#__PURE__*/_jsx(Text, {
1154
- style: styles.buttonTextPlate,
1155
- children: block.accept === "image" ? "Choose a screenshot" : "Choose a file"
1156
- })
1157
- })
1158
- })]
1159
- });
1160
- }
1161
- const styles = StyleSheet.create({
1162
- flex: {
1163
- flex: 1
1164
- },
1165
- pad: {
1166
- paddingHorizontal: 12,
1167
- paddingBottom: 8
1168
- },
1169
- muted: {
1170
- color: night.color.textSecondary
1171
- },
1172
- dim: {
1173
- opacity: 0.45
1174
- },
1175
- disabled: {
1176
- opacity: 0.5
1177
- },
1178
- pressed: {
1179
- opacity: 0.7
1180
- },
1181
- question: {
1182
- color: night.color.text,
1183
- fontSize: night.font.row,
1184
- fontWeight: "600",
1185
- lineHeight: 20,
1186
- paddingHorizontal: 12,
1187
- paddingTop: 12,
1188
- paddingBottom: 8
1189
- },
1190
- hint: {
1191
- color: night.color.textTertiary,
1192
- fontSize: night.font.micro,
1193
- paddingHorizontal: 12,
1194
- paddingBottom: 10
1195
- },
1196
- decided: {
1197
- color: night.color.textSecondary,
1198
- fontSize: night.font.caption,
1199
- fontWeight: "600",
1200
- paddingHorizontal: 12,
1201
- paddingVertical: 10
1202
- },
1203
- rowEnd: {
1204
- flexDirection: "row",
1205
- justifyContent: "flex-end",
1206
- paddingHorizontal: 12,
1207
- paddingBottom: 12,
1208
- gap: 8
1209
- },
1210
- actionsRow: {
1211
- flexDirection: "row",
1212
- gap: 8,
1213
- paddingHorizontal: 12,
1214
- paddingVertical: 12,
1215
- alignItems: "center"
1216
- },
1217
- button: {
1218
- paddingHorizontal: 14,
1219
- paddingVertical: 9,
1220
- borderRadius: night.radius.row
1221
- },
1222
- buttonPrimary: {
1223
- backgroundColor: night.color.accent
1224
- },
1225
- buttonPlate: {
1226
- backgroundColor: night.color.button
1227
- },
1228
- buttonTextPrimary: {
1229
- color: night.color.onAccent,
1230
- fontSize: night.font.caption,
1231
- fontWeight: "600"
1232
- },
1233
- buttonTextPlate: {
1234
- color: night.color.text,
1235
- fontSize: night.font.caption,
1236
- fontWeight: "600"
1237
- },
1238
- chips: {
1239
- flexDirection: "row",
1240
- flexWrap: "wrap",
1241
- gap: 6
1242
- },
1243
- chip: {
1244
- paddingHorizontal: 12,
1245
- paddingVertical: 7,
1246
- borderRadius: night.radius.chip,
1247
- backgroundColor: night.color.fill,
1248
- borderWidth: StyleSheet.hairlineWidth,
1249
- borderColor: night.color.border
1250
- },
1251
- chipOn: {
1252
- backgroundColor: night.color.accentSoft,
1253
- borderColor: night.color.accentBorderStrong
1254
- },
1255
- chipText: {
1256
- color: night.color.text,
1257
- fontSize: night.font.caption
1258
- },
1259
- chipTextOn: {
1260
- color: night.color.accent,
1261
- fontWeight: "600"
1262
- },
1263
- optionsBox: {
1264
- marginHorizontal: 8,
1265
- marginBottom: 8,
1266
- borderRadius: night.radius.row,
1267
- backgroundColor: night.color.surfaceElevated,
1268
- overflow: "hidden"
1269
- },
1270
- option: {
1271
- flexDirection: "row",
1272
- alignItems: "center",
1273
- gap: 10,
1274
- paddingHorizontal: 12,
1275
- paddingVertical: 10
1276
- },
1277
- optionLabel: {
1278
- color: night.color.text,
1279
- fontSize: night.font.body,
1280
- fontWeight: "500"
1281
- },
1282
- optionDetail: {
1283
- color: night.color.textSecondary,
1284
- fontSize: night.font.caption
1285
- },
1286
- checkbox: {
1287
- width: 20,
1288
- height: 20,
1289
- borderRadius: 6,
1290
- borderWidth: 1.5,
1291
- borderColor: night.color.textTertiary,
1292
- alignItems: "center",
1293
- justifyContent: "center"
1294
- },
1295
- checkboxOn: {
1296
- backgroundColor: night.color.accent,
1297
- borderColor: night.color.accent
1298
- },
1299
- selectBox: {
1300
- marginHorizontal: 12,
1301
- marginBottom: 12,
1302
- borderRadius: night.radius.row,
1303
- backgroundColor: night.color.surfaceElevated,
1304
- overflow: "hidden"
1305
- },
1306
- selectField: {
1307
- flexDirection: "row",
1308
- alignItems: "center",
1309
- justifyContent: "space-between",
1310
- paddingHorizontal: 12,
1311
- paddingVertical: 11
1312
- },
1313
- selectPlaceholder: {
1314
- color: night.color.textSecondary,
1315
- fontSize: night.font.body
1316
- },
1317
- search: {
1318
- flexDirection: "row",
1319
- alignItems: "center",
1320
- gap: 6,
1321
- paddingHorizontal: 12,
1322
- paddingVertical: 6,
1323
- borderTopWidth: StyleSheet.hairlineWidth,
1324
- borderTopColor: night.color.separator
1325
- },
1326
- searchInput: {
1327
- flex: 1,
1328
- color: night.color.text,
1329
- fontSize: night.font.caption,
1330
- paddingVertical: 4
1331
- },
1332
- sliderRow: {
1333
- flexDirection: "row",
1334
- alignItems: "center",
1335
- gap: 8
1336
- },
1337
- stepBtn: {
1338
- width: 28,
1339
- height: 28,
1340
- borderRadius: 14,
1341
- backgroundColor: night.color.fill,
1342
- alignItems: "center",
1343
- justifyContent: "center"
1344
- },
1345
- stepText: {
1346
- color: night.color.text,
1347
- fontSize: 16,
1348
- fontWeight: "600"
1349
- },
1350
- trackHit: {
1351
- flex: 1,
1352
- height: 36,
1353
- justifyContent: "center"
1354
- },
1355
- track: {
1356
- height: 6,
1357
- borderRadius: 3,
1358
- backgroundColor: night.color.fillTertiary,
1359
- justifyContent: "center"
1360
- },
1361
- fill: {
1362
- height: 6,
1363
- borderRadius: 3,
1364
- backgroundColor: night.color.accent
1365
- },
1366
- thumb: {
1367
- position: "absolute",
1368
- width: 20,
1369
- height: 20,
1370
- borderRadius: 10,
1371
- backgroundColor: night.color.knob,
1372
- marginLeft: -10,
1373
- shadowColor: "#000",
1374
- shadowOpacity: 0.35,
1375
- shadowRadius: 3,
1376
- shadowOffset: {
1377
- width: 0,
1378
- height: 1
1379
- }
1380
- },
1381
- sliderValue: {
1382
- width: 64,
1383
- textAlign: "right",
1384
- color: night.color.text,
1385
- fontSize: night.font.caption,
1386
- fontWeight: "600"
1387
- },
1388
- inputRow: {
1389
- flexDirection: "row",
1390
- alignItems: "center",
1391
- gap: 8,
1392
- paddingBottom: 12
1393
- },
1394
- input: {
1395
- flex: 1,
1396
- height: 38,
1397
- paddingHorizontal: 12,
1398
- borderRadius: night.radius.row,
1399
- backgroundColor: night.color.surfaceElevated,
1400
- color: night.color.text,
1401
- fontSize: night.font.body
1402
- },
1403
- fieldRow: {
1404
- flexDirection: "row",
1405
- alignItems: "center",
1406
- justifyContent: "space-between",
1407
- gap: 10,
1408
- paddingVertical: 6
1409
- },
1410
- fieldCol: {
1411
- paddingVertical: 6,
1412
- gap: 6
1413
- },
1414
- fieldLabel: {
1415
- color: night.color.textSecondary,
1416
- fontSize: night.font.caption,
1417
- width: 110
1418
- },
1419
- fieldInput: {
1420
- flex: 1,
1421
- height: 34,
1422
- paddingHorizontal: 10,
1423
- borderRadius: night.radius.segment,
1424
- backgroundColor: night.color.surfaceElevated,
1425
- color: night.color.text,
1426
- fontSize: night.font.caption
1427
- },
1428
- confirmTitle: {
1429
- color: night.color.text,
1430
- fontSize: night.font.row,
1431
- fontWeight: "600",
1432
- paddingHorizontal: 12,
1433
- paddingTop: 12
1434
- },
1435
- confirmChange: {
1436
- color: night.color.text,
1437
- fontSize: night.font.body,
1438
- lineHeight: 19,
1439
- paddingHorizontal: 12,
1440
- paddingTop: 6,
1441
- paddingBottom: 6
1442
- },
1443
- consequence: {
1444
- color: night.color.warning,
1445
- fontSize: night.font.caption,
1446
- paddingHorizontal: 12
1447
- },
1448
- claim: {
1449
- gap: 6,
1450
- paddingHorizontal: 2
1451
- },
1452
- claimText: {
1453
- color: night.color.text,
1454
- fontSize: night.font.row,
1455
- lineHeight: 22
1456
- },
1457
- cite: {
1458
- color: night.color.accent,
1459
- fontSize: night.font.caption,
1460
- fontWeight: "700"
1461
- },
1462
- verified: {
1463
- color: night.color.accent,
1464
- fontSize: night.font.caption,
1465
- fontWeight: "600"
1466
- },
1467
- citeBox: {
1468
- padding: 10,
1469
- borderRadius: night.radius.row,
1470
- backgroundColor: night.color.surface,
1471
- borderWidth: StyleSheet.hairlineWidth,
1472
- borderColor: night.color.border,
1473
- gap: 2
1474
- },
1475
- citeLabel: {
1476
- color: night.color.text,
1477
- fontSize: night.font.caption,
1478
- fontWeight: "600"
1479
- },
1480
- citeDetail: {
1481
- color: night.color.textSecondary,
1482
- fontSize: night.font.caption,
1483
- fontFamily: "Menlo"
1484
- },
1485
- verifyBtn: {
1486
- alignSelf: "flex-start",
1487
- flexDirection: "row",
1488
- alignItems: "center",
1489
- gap: 5,
1490
- paddingHorizontal: 10,
1491
- paddingVertical: 5,
1492
- borderRadius: night.radius.chip,
1493
- backgroundColor: night.color.accentSoft
1494
- },
1495
- verifyText: {
1496
- color: night.color.accent,
1497
- fontSize: night.font.micro,
1498
- fontWeight: "700"
1499
- },
1500
- detailsBody: {
1501
- color: night.color.textSecondary,
1502
- fontSize: night.font.caption,
1503
- lineHeight: 18,
1504
- paddingHorizontal: 12,
1505
- paddingBottom: 12
1506
- },
1507
- tabsWrap: {
1508
- gap: 8
1509
- },
1510
- tabBar: {
1511
- flexDirection: "row",
1512
- gap: 6
1513
- },
1514
- tab: {
1515
- paddingHorizontal: 12,
1516
- paddingVertical: 6,
1517
- borderRadius: night.radius.badge,
1518
- backgroundColor: night.color.fill
1519
- },
1520
- tabOn: {
1521
- backgroundColor: night.color.accentSoft
1522
- },
1523
- tabText: {
1524
- color: night.color.textSecondary,
1525
- fontSize: night.font.caption,
1526
- fontWeight: "600"
1527
- },
1528
- tabTextOn: {
1529
- color: night.color.accent
1530
- },
1531
- tlRow: {
1532
- flexDirection: "row",
1533
- gap: 10,
1534
- paddingHorizontal: 12,
1535
- paddingVertical: 4,
1536
- alignItems: "flex-start"
1537
- },
1538
- tlAt: {
1539
- width: 46,
1540
- color: night.color.textTertiary,
1541
- fontSize: night.font.micro,
1542
- fontFamily: "Menlo",
1543
- paddingTop: 3
1544
- },
1545
- tlLine: {
1546
- width: 12,
1547
- alignItems: "center"
1548
- },
1549
- tlDot: {
1550
- width: 8,
1551
- height: 8,
1552
- borderRadius: 4,
1553
- marginTop: 5
1554
- },
1555
- tlStem: {
1556
- width: 1,
1557
- flex: 1,
1558
- minHeight: 18,
1559
- backgroundColor: night.color.separator,
1560
- marginTop: 2
1561
- },
1562
- tlSource: {
1563
- color: night.color.textTertiary,
1564
- fontSize: 9,
1565
- fontWeight: "700",
1566
- letterSpacing: 0.6
1567
- },
1568
- sparkHead: {
1569
- flexDirection: "row",
1570
- alignItems: "center",
1571
- justifyContent: "space-between",
1572
- paddingHorizontal: 12,
1573
- paddingTop: 8
1574
- },
1575
- sparkCurrent: {
1576
- color: night.color.text,
1577
- fontSize: 22,
1578
- fontWeight: "700"
1579
- },
1580
- sparkUnit: {
1581
- color: night.color.textSecondary,
1582
- fontSize: night.font.caption,
1583
- fontWeight: "500"
1584
- },
1585
- spark: {
1586
- flexDirection: "row",
1587
- alignItems: "flex-end",
1588
- gap: 2,
1589
- paddingHorizontal: 12,
1590
- paddingTop: 6,
1591
- paddingBottom: 6
1592
- },
1593
- sparkBar: {
1594
- flex: 1,
1595
- borderRadius: 1
1596
- },
1597
- live: {
1598
- flexDirection: "row",
1599
- alignItems: "center",
1600
- gap: 5,
1601
- paddingHorizontal: 8,
1602
- paddingVertical: 3,
1603
- borderRadius: night.radius.badge,
1604
- backgroundColor: night.color.dangerSoft
1605
- },
1606
- liveDot: {
1607
- width: 6,
1608
- height: 6,
1609
- borderRadius: 3,
1610
- backgroundColor: night.color.danger
1611
- },
1612
- liveText: {
1613
- color: night.color.danger,
1614
- fontSize: 9,
1615
- fontWeight: "800",
1616
- letterSpacing: 0.8
1617
- },
1618
- cmpHead: {
1619
- flexDirection: "row",
1620
- paddingHorizontal: 12,
1621
- paddingVertical: 6,
1622
- backgroundColor: night.color.fill,
1623
- gap: 8
1624
- },
1625
- cmpCol: {
1626
- flex: 1,
1627
- color: night.color.textTertiary,
1628
- fontSize: night.font.micro,
1629
- fontWeight: "700",
1630
- letterSpacing: 0.6,
1631
- textTransform: "uppercase"
1632
- },
1633
- cmpRow: {
1634
- flexDirection: "row",
1635
- paddingHorizontal: 12,
1636
- paddingVertical: 8,
1637
- gap: 8,
1638
- alignItems: "flex-start"
1639
- },
1640
- cmpDiff: {
1641
- backgroundColor: night.color.fill
1642
- },
1643
- cmpKey: {
1644
- width: 90,
1645
- color: night.color.textSecondary,
1646
- fontSize: night.font.caption
1647
- },
1648
- cmpVal: {
1649
- flex: 1,
1650
- color: night.color.text,
1651
- fontSize: night.font.caption,
1652
- fontFamily: "Menlo"
1653
- },
1654
- /**
1655
- * A fixed box the image is fitted INTO, never cropped to.
1656
- *
1657
- * This was `cover`, which is right for a decorative banner and wrong for
1658
- * everything the agent actually passes: product art, avatars and sprites are
1659
- * square, and a square scaled to fill a 2.4:1 box loses its top and bottom —
1660
- * a Charizard reduced to a band of its own middle. These pictures are the
1661
- * app's DATA, being looked at in a devtool; cropping hides the thing you
1662
- * opened the card to see. `contain` letterboxes a wide image instead, which
1663
- * costs a little space and no information. The fill behind it is the
1664
- * letterbox. Same reasoning as the screenshot block, which was already
1665
- * `contain`.
1666
- */
1667
- cardImage: {
1668
- width: "100%",
1669
- height: 140,
1670
- backgroundColor: night.color.fill
1671
- },
1672
- cardText: {
1673
- paddingHorizontal: 12,
1674
- paddingTop: 10,
1675
- paddingBottom: 4,
1676
- gap: 4
1677
- },
1678
- cardTitle: {
1679
- color: night.color.text,
1680
- fontSize: night.font.row,
1681
- fontWeight: "600"
1682
- },
1683
- fact: {
1684
- flexDirection: "row",
1685
- justifyContent: "space-between",
1686
- gap: 8
1687
- },
1688
- factLabel: {
1689
- color: night.color.textSecondary,
1690
- fontSize: night.font.caption
1691
- },
1692
- factValue: {
1693
- color: night.color.text,
1694
- fontSize: night.font.caption,
1695
- fontWeight: "500"
1696
- },
1697
- carouselTitle: {
1698
- color: night.color.text,
1699
- fontSize: night.font.caption,
1700
- fontWeight: "600",
1701
- paddingBottom: 8
1702
- },
1703
- carousel: {
1704
- gap: 8,
1705
- paddingRight: 8
1706
- },
1707
- carouselCard: {
1708
- width: 224,
1709
- borderRadius: night.radius.card,
1710
- borderWidth: StyleSheet.hairlineWidth,
1711
- borderColor: night.color.border,
1712
- backgroundColor: night.color.surface,
1713
- overflow: "hidden"
1714
- },
1715
- shot: {
1716
- width: "100%",
1717
- height: 220,
1718
- backgroundColor: night.color.fill
1719
- },
1720
- shotBig: {
1721
- height: 520
1722
- },
1723
- progress: {
1724
- height: 4,
1725
- backgroundColor: night.color.fill,
1726
- marginHorizontal: 12,
1727
- marginTop: 6,
1728
- marginBottom: 8,
1729
- borderRadius: 2,
1730
- overflow: "hidden"
1731
- },
1732
- progressFill: {
1733
- height: 4,
1734
- backgroundColor: night.color.accent
1735
- },
1736
- step: {
1737
- flexDirection: "row",
1738
- alignItems: "center",
1739
- gap: 10,
1740
- paddingHorizontal: 12,
1741
- paddingVertical: 9
1742
- },
1743
- stepMark: {
1744
- width: 20,
1745
- height: 20,
1746
- borderRadius: 10,
1747
- backgroundColor: night.color.fillTertiary,
1748
- alignItems: "center",
1749
- justifyContent: "center"
1750
- },
1751
- stepDone: {
1752
- backgroundColor: night.color.accent
1753
- },
1754
- stepFailed: {
1755
- backgroundColor: night.color.danger
1756
- },
1757
- stepRunning: {
1758
- backgroundColor: night.color.info
1759
- },
1760
- stepNum: {
1761
- color: night.color.text,
1762
- fontSize: night.font.micro,
1763
- fontWeight: "700"
1764
- },
1765
- checkpoint: {
1766
- alignSelf: "flex-start",
1767
- flexDirection: "row",
1768
- alignItems: "center",
1769
- gap: 8,
1770
- paddingHorizontal: 12,
1771
- paddingVertical: 7,
1772
- borderRadius: night.radius.chip,
1773
- backgroundColor: night.color.fill
1774
- },
1775
- cpFlag: {
1776
- width: 8,
1777
- height: 8,
1778
- borderRadius: 2,
1779
- backgroundColor: night.color.info
1780
- },
1781
- cpText: {
1782
- color: night.color.textSecondary,
1783
- fontSize: night.font.caption
1784
- },
1785
- cpRestore: {
1786
- color: night.color.accent,
1787
- fontSize: night.font.caption,
1788
- fontWeight: "600"
1789
- },
1790
- taskHead: {
1791
- flexDirection: "row",
1792
- alignItems: "center",
1793
- justifyContent: "space-between",
1794
- gap: 8,
1795
- paddingHorizontal: 12,
1796
- paddingTop: 12
1797
- },
1798
- banner: {
1799
- flexDirection: "row",
1800
- alignItems: "center",
1801
- gap: 8,
1802
- paddingLeft: 12,
1803
- paddingRight: 4,
1804
- paddingVertical: 4,
1805
- borderRadius: night.radius.row,
1806
- borderWidth: StyleSheet.hairlineWidth
1807
- },
1808
- bannerText: {
1809
- flex: 1,
1810
- fontSize: night.font.caption,
1811
- fontWeight: "600"
1812
- },
1813
- fileIcon: {
1814
- width: 40,
1815
- height: 40,
1816
- borderRadius: 8,
1817
- backgroundColor: night.color.fill,
1818
- alignItems: "center",
1819
- justifyContent: "center"
1820
- },
1821
- fileExt: {
1822
- color: night.color.textSecondary,
1823
- fontSize: 10,
1824
- fontWeight: "800"
1825
- }
1826
- });
1827
- //# sourceMappingURL=ExtraBlocks.js.map
1
+ "use strict";import{useEffect,useRef,useState}from"react";import{Animated,Image,Pressable,ScrollView,StyleSheet,Switch,Text,TextInput,View}from"react-native";import{AlertTriangle,Check,ChevronDown,ChevronRight,night,NightSegmented,RefreshCw,Search,X}from"@buoy-gg/shared-ui";import{useBlockHandlers}from"./context";import{ActionRow,blockStyles as b,Card,More,toneColor,usePaged}from"./primitives";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";const fmt=e=>"string"==typeof e?e:void 0===e?"—":JSON.stringify(e);export function Suggestions({block:e}){const t=useBlockHandlers();return _jsx(View,{style:styles.chips,testID:`buoy-block-suggestions-${e.id}`,children:e.chips.slice(0,4).map(o=>_jsx(Pressable,{disabled:!!t.busy,onPress:()=>{t.runAction({label:o.label,send:o.send??o.label},e.id)},style:({pressed:e})=>[styles.chip,e&&styles.pressed],accessibilityRole:"button",children:_jsx(Text,{style:styles.chipText,children:o.label})},o.label))})}export function MultiSelect({block:e}){const t=useBlockHandlers(),o=t.answered[e.id],l=!!o,[i,n]=useState([]),s="multi"===o?.kind?o.optionIds:i,r=i.length>=(e.min??1)&&(!e.max||i.length<=e.max);return _jsxs(Card,{testID:`buoy-block-multi-${e.id}`,tone:l?void 0:"info",children:[_jsx(Text,{style:styles.question,children:e.question}),_jsx(View,{style:styles.optionsBox,children:e.options.map((e,t)=>{const o=s.includes(e.id);return _jsxs(Pressable,{disabled:l,onPress:()=>{return t=e.id,n(e=>e.includes(t)?e.filter(e=>e!==t):[...e,t]);var t},style:[styles.option,t>0&&b.rowDivider,l&&!o&&styles.dim],accessibilityRole:"checkbox",accessibilityState:{checked:o},children:[_jsx(View,{style:[styles.checkbox,o&&styles.checkboxOn],children:o?_jsx(Check,{size:11,color:night.color.onAccent}):null}),_jsxs(View,{style:styles.flex,children:[_jsx(Text,{style:styles.optionLabel,children:e.label}),e.detail?_jsx(Text,{style:styles.optionDetail,children:e.detail}):null]})]},e.id)})}),l?null:_jsx(View,{style:styles.rowEnd,children:_jsx(Pressable,{testID:"buoy-block-multi-submit",disabled:!r,onPress:()=>t.answer({blockId:e.id,kind:"multi",optionIds:i,labels:e.options.filter(e=>i.includes(e.id)).map(e=>e.label)}),style:[styles.button,styles.buttonPrimary,!r&&styles.disabled],children:_jsx(Text,{style:styles.buttonTextPrimary,children:e.submitLabel??`Use ${i.length||""}`.trim()})})})]})}const SEARCH_FROM=8;export function Select({block:e}){const t=useBlockHandlers(),o=t.answered[e.id],[l,i]=useState(""),[n,s]=useState(!1),r="select"===o?.kind?o.label:null,a=e.options.filter(e=>!l||e.label.toLowerCase().includes(l.toLowerCase())).slice(0,8),c=!1!==e.searchable&&e.options.length>=8;return _jsxs(Card,{testID:`buoy-block-select-${e.id}`,tone:o?void 0:"info",children:[_jsx(Text,{style:styles.question,children:e.label}),r?_jsx(Text,{style:styles.decided,children:r}):_jsxs(View,{style:styles.selectBox,children:[_jsxs(Pressable,{onPress:()=>s(e=>!e),style:styles.selectField,accessibilityRole:"button",children:[_jsx(Text,{style:styles.selectPlaceholder,children:n?"Choose…":`${e.options.length} options`}),_jsx(ChevronDown,{size:14,color:night.color.textSecondary})]}),n&&_jsxs(_Fragment,{children:[c&&_jsxs(View,{style:styles.search,children:[_jsx(Search,{size:12,color:night.color.textSecondary}),_jsx(TextInput,{style:styles.searchInput,value:l,onChangeText:i,placeholder:"Search",placeholderTextColor:night.color.placeholder,autoCapitalize:"none",autoCorrect:!1})]}),a.map((o,l)=>_jsxs(Pressable,{onPress:()=>t.answer({blockId:e.id,kind:"select",optionId:o.id,label:o.label}),style:[styles.option,l>0&&b.rowDivider],accessibilityRole:"button",children:[_jsxs(View,{style:styles.flex,children:[_jsx(Text,{style:styles.optionLabel,children:o.label}),o.detail?_jsx(Text,{style:styles.optionDetail,children:o.detail}):null]}),_jsx(ChevronRight,{size:12,color:night.color.textTertiary})]},o.id)),e.options.length>a.length?_jsxs(Text,{style:styles.hint,children:[e.options.length-a.length," more — keep typing"]}):null]})]})]})}function SliderControl({min:e,max:t,step:o=1,value:l,unit:i,onChange:n,disabled:s}){const r=useRef(0),a=t>e?(l-e)/(t-e)*100:0,c=l=>Math.min(t,Math.max(e,+(Math.round((l-e)/o)*o+e).toFixed(6))),d=e=>!s&&n(c(l+e*o));return _jsxs(View,{style:styles.sliderRow,children:[_jsx(Pressable,{disabled:s,onPress:()=>d(-1),style:styles.stepBtn,accessibilityRole:"button",accessibilityLabel:"Decrease",children:_jsx(Text,{style:styles.stepText,children:"−"})}),_jsx(Pressable,{style:styles.trackHit,onLayout:e=>{r.current=e.nativeEvent.layout.width},onPress:o=>{if(s||r.current<=0)return;const l=Math.min(1,Math.max(0,o.nativeEvent.locationX/r.current));n(c(e+l*(t-e)))},disabled:s,accessibilityRole:"adjustable",accessibilityValue:{min:e,max:t,now:l},accessibilityActions:[{name:"increment"},{name:"decrement"}],onAccessibilityAction:e=>d("increment"===e.nativeEvent.actionName?1:-1),children:_jsxs(View,{style:styles.track,pointerEvents:"none",children:[_jsx(View,{style:[styles.fill,{width:`${a}%`}]}),_jsx(View,{style:[styles.thumb,{left:`${a}%`}]})]})}),_jsx(Pressable,{disabled:s,onPress:()=>d(1),style:styles.stepBtn,accessibilityRole:"button",accessibilityLabel:"Increase",children:_jsx(Text,{style:styles.stepText,children:"+"})}),_jsxs(Text,{style:styles.sliderValue,children:[l,i?` ${i}`:""]})]})}export function Slider({block:e}){const t=useBlockHandlers(),o=t.answered[e.id],[l,i]=useState(e.value??e.min);return _jsxs(Card,{testID:`buoy-block-slider-${e.id}`,tone:o?void 0:"info",children:[_jsx(Text,{style:styles.question,children:e.label}),_jsx(View,{style:styles.pad,children:_jsx(SliderControl,{min:e.min,max:e.max,step:e.step,value:"slider"===o?.kind?o.value:l,unit:e.unit,onChange:i,disabled:!!o})}),o?null:_jsx(View,{style:styles.rowEnd,children:_jsx(Pressable,{onPress:()=>t.answer({blockId:e.id,kind:"slider",value:l,unit:e.unit}),style:[styles.button,styles.buttonPrimary],children:_jsxs(Text,{style:styles.buttonTextPrimary,children:["Use ",l,e.unit?` ${e.unit}`:""]})})})]})}export function DateTime({block:e}){const t=useBlockHandlers(),o=t.answered[e.id],[l,i]=useState(""),n=e.presets??[{label:"Now",value:(new Date).toISOString()},{label:"Tomorrow",value:new Date(Date.now()+864e5).toISOString()},{label:"+7 days",value:new Date(Date.now()+6048e5).toISOString()},{label:"+30 days",value:new Date(Date.now()+2592e6).toISOString()}];return _jsxs(Card,{testID:`buoy-block-datetime-${e.id}`,tone:o?void 0:"info",children:[_jsx(Text,{style:styles.question,children:e.label}),o?_jsx(Text,{style:styles.decided,children:"dateTime"===o.kind?o.label??o.value:"(skipped)"}):_jsxs(_Fragment,{children:[_jsx(View,{style:[styles.chips,styles.pad],children:n.map(o=>_jsx(Pressable,{onPress:()=>t.answer({blockId:e.id,kind:"dateTime",value:o.value,label:o.label}),style:styles.chip,children:_jsx(Text,{style:styles.chipText,children:o.label})},o.label))}),_jsxs(View,{style:[styles.inputRow,styles.pad],children:[_jsx(TextInput,{style:styles.input,value:l,onChangeText:i,placeholder:"time"===e.mode?"14:30":"2026-09-15",placeholderTextColor:night.color.placeholder,keyboardType:"numbers-and-punctuation"}),_jsx(Pressable,{disabled:!l.trim(),onPress:()=>t.answer({blockId:e.id,kind:"dateTime",value:l.trim()}),style:[styles.button,styles.buttonPrimary,!l.trim()&&styles.disabled],children:_jsx(Text,{style:styles.buttonTextPrimary,children:"Use"})})]})]})]})}function FieldRow({f:e,value:t,onChange:o,disabled:l}){return"toggle"===e.type?_jsxs(View,{style:styles.fieldRow,children:[_jsx(Text,{style:styles.fieldLabel,children:e.label}),_jsx(Switch,{value:!!t,onValueChange:o,disabled:l,trackColor:{true:night.color.accent,false:night.color.fillTertiary},thumbColor:night.color.knob})]}):"select"===e.type?_jsxs(View,{style:styles.fieldCol,children:[_jsx(Text,{style:styles.fieldLabel,children:e.label}),_jsx(View,{style:styles.chips,children:e.options.map(e=>_jsx(Pressable,{disabled:l,onPress:()=>o(e.id),style:[styles.chip,t===e.id&&styles.chipOn],children:_jsx(Text,{style:[styles.chipText,t===e.id&&styles.chipTextOn],children:e.label})},e.id))})]}):"slider"===e.type?_jsxs(View,{style:styles.fieldCol,children:[_jsx(Text,{style:styles.fieldLabel,children:e.label}),_jsx(SliderControl,{min:e.min,max:e.max,step:e.step,unit:e.unit,value:"number"==typeof t?t:e.min,onChange:o,disabled:l})]}):_jsxs(View,{style:styles.fieldRow,children:[_jsx(Text,{style:styles.fieldLabel,children:e.label}),_jsx(TextInput,{style:styles.fieldInput,value:null==t?"":String(t),onChangeText:o,editable:!l,placeholder:e.placeholder??"",placeholderTextColor:night.color.placeholder,keyboardType:"number"===e.type?"numeric":"ascii-capable",secureTextEntry:"secret"===e.type,autoCapitalize:"none",autoCorrect:!1})]})}function useFormValues(e){const[t,o]=useState(()=>Object.fromEntries(e.map(e=>[e.key,e.value])));return{values:t,set:(e,t)=>o(o=>({...o,[e]:t}))}}export function Form({block:e}){const t=useBlockHandlers(),o=t.answered[e.id],{values:l,set:i}=useFormValues(e.fields);return _jsxs(Card,{title:e.title,testID:`buoy-block-form-${e.id}`,tone:o?void 0:"info",children:[_jsx(View,{style:styles.pad,children:e.fields.map(e=>_jsx(FieldRow,{f:e,value:l[e.key],onChange:t=>i(e.key,t),disabled:!!o},e.key))}),o?_jsx(Text,{style:styles.decided,children:"Sent"}):_jsx(View,{style:styles.rowEnd,children:_jsx(Pressable,{onPress:()=>t.answer({blockId:e.id,kind:"form",values:l}),style:[styles.button,styles.buttonPrimary],children:_jsx(Text,{style:styles.buttonTextPrimary,children:e.submitLabel??"Send"})})})]})}export function Proposal({block:e}){const t=useBlockHandlers(),o=t.answered[e.id],{values:l,set:i}=useFormValues(e.fields),n="proposal"===o?.kind?o.approved:null;return _jsxs(Card,{testID:`buoy-block-proposal-${e.id}`,tone:o?void 0:"warning",children:[_jsx(Text,{style:styles.confirmTitle,children:e.title}),_jsx(Text,{style:styles.confirmChange,children:e.change}),_jsx(View,{style:styles.pad,children:e.fields.map(e=>_jsx(FieldRow,{f:e,value:l[e.key],onChange:t=>i(e.key,t),disabled:!!o},e.key))}),e.consequence?_jsx(Text,{style:styles.consequence,children:e.consequence}):null,_jsx(View,{style:styles.actionsRow,children:o?_jsx(Text,{style:styles.decided,children:n?"✓ Applied with these values":"✕ Not applied"}):_jsxs(_Fragment,{children:[_jsx(Pressable,{onPress:()=>t.answer({blockId:e.id,kind:"proposal",approved:!0,values:l}),style:[styles.button,styles.buttonPrimary],children:_jsx(Text,{style:styles.buttonTextPrimary,children:e.approveLabel??"Apply"})}),_jsx(Pressable,{onPress:()=>t.answer({blockId:e.id,kind:"proposal",approved:!1}),style:[styles.button,styles.buttonPlate],children:_jsx(Text,{style:styles.buttonTextPlate,children:"Not now"})})]})})]})}export function Claim({block:e}){const t=useBlockHandlers(),[o,l]=useState(null),i=t.actionState?.[`${e.id}:${e.verify?.label??"Verify"}`],n=e.verified||"done"===i;return _jsxs(View,{style:styles.claim,testID:`buoy-block-claim-${e.id}`,children:[_jsxs(Text,{style:styles.claimText,children:[e.text,e.sources.map((e,t)=>_jsxs(Text,{onPress:()=>l(o===t?null:t),style:styles.cite,children:[" [",t+1,"]"]},t)),n?_jsx(Text,{style:styles.verified,children:" ✓ verified"}):null]}),null!==o&&e.sources[o]?_jsxs(View,{style:styles.citeBox,children:[_jsxs(Text,{style:styles.citeLabel,children:["[",o+1,"] ",e.sources[o].label]}),e.sources[o].detail?_jsx(Text,{style:styles.citeDetail,children:e.sources[o].detail}):null]}):null,e.verify&&!n?_jsxs(Pressable,{onPress:()=>{t.runAction(e.verify,e.id)},style:styles.verifyBtn,accessibilityRole:"button",children:[_jsx(RefreshCw,{size:11,color:night.color.accent}),_jsx(Text,{style:styles.verifyText,children:"running"===i?"Checking…":e.verify.label})]}):null]})}export function Details({block:e}){const[t,o]=useState(!!e.open);return _jsxs(Card,{testID:`buoy-block-details-${e.id}`,children:[_jsxs(Pressable,{onPress:()=>o(e=>!e),style:b.row,accessibilityRole:"button",accessibilityState:{expanded:t},children:[_jsx(Text,{style:b.rowTitle,children:e.summary}),_jsx(t?ChevronDown:ChevronRight,{size:12,color:night.color.textTertiary})]}),t?_jsx(Text,{style:styles.detailsBody,selectable:!0,children:e.body}):null]})}export function Tabs({block:e,renderNested:t}){const[o,l]=useState(0),i=e.tabs.map((e,t)=>({key:String(t),label:e.label})),n=e.tabs[o];return _jsxs(View,{style:styles.tabsWrap,testID:`buoy-block-tabs-${e.id}`,children:[_jsx(NightSegmented,{tabs:i,activeKey:String(o),onChange:e=>l(Number(e)),size:"sm"}),n&&t?t(n.block):null]})}const TIMELINE_CAP=10;export function Timeline({block:e}){const t=usePaged(e.events,10);return _jsxs(Card,{title:e.title??"What happened",source:e.source,testID:`buoy-block-timeline-${e.id}`,children:[t.visible.map((e,o)=>_jsxs(View,{style:styles.tlRow,children:[_jsx(Text,{style:styles.tlAt,children:e.at}),_jsxs(View,{style:styles.tlLine,children:[_jsx(View,{style:[styles.tlDot,{backgroundColor:toneColor(e.tone??"muted")}]}),o<t.visible.length-1?_jsx(View,{style:styles.tlStem}):null]}),_jsxs(View,{style:styles.flex,children:[_jsx(Text,{style:styles.tlSource,children:e.source.toUpperCase()}),_jsx(Text,{style:b.rowTitle,numberOfLines:2,children:e.label})]})]},o)),_jsx(More,{paged:t})]})}export function Sparkline({block:e}){const t=e.series.slice(-60),o=Math.max(1,...t),l=Math.min(...t,0);return _jsxs(Card,{title:e.title,source:e.source,testID:`buoy-block-sparkline-${e.id}`,children:[_jsxs(View,{style:styles.sparkHead,children:[_jsxs(Text,{style:styles.sparkCurrent,children:[e.current??t[t.length-1],e.unit?_jsxs(Text,{style:styles.sparkUnit,children:[" ",e.unit]}):null]}),e.live?_jsx(LivePill,{}):null]}),_jsx(View,{style:[styles.spark,{height:44}],children:t.map((e,i)=>_jsx(View,{style:[styles.sparkBar,{height:Math.max(2,(e-l)/(o-l||1)*44),backgroundColor:i===t.length-1?night.color.accent:night.color.accentBorderStrong}]},i))}),e.label?_jsx(Text,{style:styles.hint,children:e.label}):null]})}export function LivePill(){const e=useRef(new Animated.Value(1)).current;return useEffect(()=>{const t=Animated.loop(Animated.sequence([Animated.timing(e,{toValue:.3,duration:700,useNativeDriver:!0}),Animated.timing(e,{toValue:1,duration:700,useNativeDriver:!0})]));return t.start(),()=>t.stop()},[e]),_jsxs(View,{style:styles.live,children:[_jsx(Animated.View,{style:[styles.liveDot,{opacity:e}]}),_jsx(Text,{style:styles.liveText,children:"LIVE"})]})}export function Compare({block:e}){const t=[...new Set([...e.left.pairs.map(e=>e.key),...e.right.pairs.map(e=>e.key)])],o=Object.fromEntries(e.left.pairs.map(e=>[e.key,e.value])),l=Object.fromEntries(e.right.pairs.map(e=>[e.key,e.value]));return _jsxs(Card,{title:e.title,source:e.source,testID:`buoy-block-compare-${e.id}`,children:[_jsxs(View,{style:styles.cmpHead,children:[_jsx(Text,{style:styles.cmpKey}),_jsx(Text,{style:styles.cmpCol,children:e.left.title}),_jsx(Text,{style:styles.cmpCol,children:e.right.title})]}),t.map((e,t)=>{const i=JSON.stringify(o[e])!==JSON.stringify(l[e]);return _jsxs(View,{style:[styles.cmpRow,t>0&&b.rowDivider,i&&styles.cmpDiff],children:[_jsx(Text,{style:styles.cmpKey,numberOfLines:1,children:e}),_jsx(Text,{style:[styles.cmpVal,i&&{color:night.color.danger}],numberOfLines:2,children:fmt(o[e])}),_jsx(Text,{style:[styles.cmpVal,i&&{color:night.color.accent}],numberOfLines:2,children:fmt(l[e])})]},e)})]})}function CardBody({c:e,id:t}){return _jsxs(_Fragment,{children:[e.image?_jsx(Image,{source:{uri:e.image},style:styles.cardImage,resizeMode:"contain",accessibilityLabel:e.title}):null,_jsxs(View,{style:styles.cardText,children:[_jsx(Text,{style:styles.cardTitle,numberOfLines:2,children:e.title}),e.subtitle?_jsx(Text,{style:b.rowSub,numberOfLines:2,children:e.subtitle}):null,e.facts?.slice(0,4).map(e=>_jsxs(View,{style:styles.fact,children:[_jsx(Text,{style:styles.factLabel,children:e.label}),_jsx(Text,{style:[styles.factValue,e.tone&&{color:toneColor(e.tone)}],children:e.value})]},e.label))]}),_jsx(ActionRow,{actions:e.actions,blockId:t})]})}export function CardView({block:e}){return _jsx(Card,{source:e.source,testID:`buoy-block-card-${e.id}`,children:_jsx(CardBody,{c:e,id:e.id})})}export function CardCarousel({block:e}){return _jsxs(View,{testID:`buoy-block-cardcarousel-${e.id}`,children:[e.title?_jsx(Text,{style:styles.carouselTitle,children:e.title}):null,_jsx(ScrollView,{horizontal:!0,showsHorizontalScrollIndicator:!1,snapToInterval:232,decelerationRate:"fast",contentContainerStyle:styles.carousel,children:e.cards.slice(0,8).map((t,o)=>_jsx(View,{style:styles.carouselCard,children:_jsx(CardBody,{c:t,id:`${e.id}-${o}`})},`${t.title}-${o}`))})]})}export function Screenshot({block:e}){const[t,o]=useState(!1);return _jsxs(Card,{title:e.route?`Screen · ${e.route}`:"Screen",source:e.source,testID:`buoy-block-screenshot-${e.id}`,children:[_jsx(Pressable,{onPress:()=>o(e=>!e),accessibilityRole:"imagebutton",accessibilityLabel:e.caption??"Screenshot",children:_jsx(Image,{source:{uri:e.url},style:[styles.shot,t&&styles.shotBig],resizeMode:"contain"})}),e.caption?_jsx(Text,{style:styles.hint,children:e.caption}):null]})}export function Plan({block:e}){const t=e.steps.filter(e=>"done"===e.state).length;return _jsxs(Card,{title:e.title,testID:`buoy-block-plan-${e.id}`,tone:e.pending?"info":void 0,children:[_jsx(View,{style:styles.progress,children:_jsx(View,{style:[styles.progressFill,{width:t/Math.max(1,e.steps.length)*100+"%"}]})}),e.steps.map((e,t)=>_jsxs(View,{style:[styles.step,t>0&&b.rowDivider],children:[_jsx(View,{style:[styles.stepMark,"done"===e.state&&styles.stepDone,"failed"===e.state&&styles.stepFailed,"running"===e.state&&styles.stepRunning],children:"done"===e.state?_jsx(Check,{size:10,color:night.color.onAccent}):"failed"===e.state?_jsx(X,{size:10,color:night.color.text}):_jsx(Text,{style:styles.stepNum,children:t+1})}),_jsxs(Text,{style:[b.rowTitle,"done"===e.state&&styles.muted],children:[e.text,"running"===e.state?"…":""]})]},t)),_jsx(ActionRow,{actions:e.actions??(e.pending?[{label:"Go",primary:!0,send:"Go ahead with the plan."},{label:"Change it",send:"Let me change the plan first."}]:void 0),blockId:e.id})]})}export function Checkpoint({block:e}){const t=useBlockHandlers();return _jsxs(Pressable,{testID:`buoy-block-checkpoint-${e.id}`,disabled:!e.restore,onPress:()=>e.restore&&void t.runAction(e.restore,e.id),style:styles.checkpoint,accessibilityRole:"button",children:[_jsx(View,{style:styles.cpFlag}),_jsxs(Text,{style:styles.cpText,children:[e.label,e.at?` · ${e.at}`:""]}),e.restore?_jsx(Text,{style:styles.cpRestore,children:e.restore.label}):null]})}export function Task({block:e}){const t="failed"===e.status?night.color.danger:"done"===e.status?night.color.accent:night.color.info;return _jsxs(Card,{testID:`buoy-block-task-${e.id}`,children:[_jsxs(View,{style:styles.taskHead,children:[_jsx(Text,{style:styles.cardTitle,children:e.title}),_jsx(View,{style:[b.pill,{backgroundColor:`${t}22`}],children:_jsx(Text,{style:[b.pillText,{color:t}],children:e.status.toUpperCase()})})]}),void 0!==e.progress?_jsx(View,{style:[styles.progress,styles.pad],children:_jsx(View,{style:[styles.progressFill,{width:`${Math.round(100*e.progress)}%`,backgroundColor:t}]})}):null,e.detail?_jsx(Text,{style:styles.hint,children:e.detail}):null,_jsx(ActionRow,{actions:e.actions,blockId:e.id})]})}export function Banner({block:e}){const t="danger"===e.tone?night.color.danger:"warning"===e.tone?night.color.warning:night.color.info;return _jsxs(View,{style:[styles.banner,{borderColor:t,backgroundColor:`${t}1A`}],testID:`buoy-block-banner-${e.id}`,children:[_jsx(AlertTriangle,{size:13,color:t}),_jsx(Text,{style:[styles.bannerText,{color:t}],numberOfLines:2,children:e.text}),e.actions?.[0]?_jsx(ActionRow,{actions:e.actions.slice(0,1),blockId:e.id,align:"right"}):null]})}export function File({block:e}){return _jsxs(Card,{testID:`buoy-block-file-${e.id}`,children:[_jsxs(View,{style:b.row,children:[_jsx(View,{style:styles.fileIcon,children:_jsx(Text,{style:styles.fileExt,children:(e.type??e.name.split(".").pop()??"file").toUpperCase().slice(0,4)})}),_jsxs(View,{style:styles.flex,children:[_jsx(Text,{style:b.rowTitle,numberOfLines:1,children:e.name}),e.size?_jsx(Text,{style:b.rowSub,children:e.size}):null]})]}),_jsx(ActionRow,{actions:e.actions,blockId:e.id})]})}export function Upload({block:e}){const t=useBlockHandlers(),o=t.answered[e.id];return _jsxs(Card,{testID:`buoy-block-upload-${e.id}`,tone:o?void 0:"info",children:[_jsx(Text,{style:styles.question,children:e.label}),o?_jsx(Text,{style:styles.decided,children:"upload"===o.kind?`Attached ${o.name}`:"(skipped)"}):_jsx(View,{style:[styles.rowEnd,{justifyContent:"flex-start"}],children:_jsx(Pressable,{onPress:()=>t.answer({blockId:e.id,kind:"upload",name:"screenshot.png"}),style:[styles.button,styles.buttonPlate],children:_jsx(Text,{style:styles.buttonTextPlate,children:"image"===e.accept?"Choose a screenshot":"Choose a file"})})})]})}const styles=StyleSheet.create({flex:{flex:1},pad:{paddingHorizontal:12,paddingBottom:8},muted:{color:night.color.textSecondary},dim:{opacity:.45},disabled:{opacity:.5},pressed:{opacity:.7},question:{color:night.color.text,fontSize:night.font.row,fontWeight:"600",lineHeight:20,paddingHorizontal:12,paddingTop:12,paddingBottom:8},hint:{color:night.color.textTertiary,fontSize:night.font.micro,paddingHorizontal:12,paddingBottom:10},decided:{color:night.color.textSecondary,fontSize:night.font.caption,fontWeight:"600",paddingHorizontal:12,paddingVertical:10},rowEnd:{flexDirection:"row",justifyContent:"flex-end",paddingHorizontal:12,paddingBottom:12,gap:8},actionsRow:{flexDirection:"row",gap:8,paddingHorizontal:12,paddingVertical:12,alignItems:"center"},button:{paddingHorizontal:14,paddingVertical:9,borderRadius:night.radius.row},buttonPrimary:{backgroundColor:night.color.accent},buttonPlate:{backgroundColor:night.color.button},buttonTextPrimary:{color:night.color.onAccent,fontSize:night.font.caption,fontWeight:"600"},buttonTextPlate:{color:night.color.text,fontSize:night.font.caption,fontWeight:"600"},chips:{flexDirection:"row",flexWrap:"wrap",gap:6},chip:{paddingHorizontal:12,paddingVertical:7,borderRadius:night.radius.chip,backgroundColor:night.color.fill,borderWidth:StyleSheet.hairlineWidth,borderColor:night.color.border},chipOn:{backgroundColor:night.color.accentSoft,borderColor:night.color.accentBorderStrong},chipText:{color:night.color.text,fontSize:night.font.caption},chipTextOn:{color:night.color.accent,fontWeight:"600"},optionsBox:{marginHorizontal:8,marginBottom:8,borderRadius:night.radius.row,backgroundColor:night.color.surfaceElevated,overflow:"hidden"},option:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:12,paddingVertical:10},optionLabel:{color:night.color.text,fontSize:night.font.body,fontWeight:"500"},optionDetail:{color:night.color.textSecondary,fontSize:night.font.caption},checkbox:{width:20,height:20,borderRadius:6,borderWidth:1.5,borderColor:night.color.textTertiary,alignItems:"center",justifyContent:"center"},checkboxOn:{backgroundColor:night.color.accent,borderColor:night.color.accent},selectBox:{marginHorizontal:12,marginBottom:12,borderRadius:night.radius.row,backgroundColor:night.color.surfaceElevated,overflow:"hidden"},selectField:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingVertical:11},selectPlaceholder:{color:night.color.textSecondary,fontSize:night.font.body},search:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:12,paddingVertical:6,borderTopWidth:StyleSheet.hairlineWidth,borderTopColor:night.color.separator},searchInput:{flex:1,color:night.color.text,fontSize:night.font.caption,paddingVertical:4},sliderRow:{flexDirection:"row",alignItems:"center",gap:8},stepBtn:{width:28,height:28,borderRadius:14,backgroundColor:night.color.fill,alignItems:"center",justifyContent:"center"},stepText:{color:night.color.text,fontSize:16,fontWeight:"600"},trackHit:{flex:1,height:36,justifyContent:"center"},track:{height:6,borderRadius:3,backgroundColor:night.color.fillTertiary,justifyContent:"center"},fill:{height:6,borderRadius:3,backgroundColor:night.color.accent},thumb:{position:"absolute",width:20,height:20,borderRadius:10,backgroundColor:night.color.knob,marginLeft:-10,shadowColor:"#000",shadowOpacity:.35,shadowRadius:3,shadowOffset:{width:0,height:1}},sliderValue:{width:64,textAlign:"right",color:night.color.text,fontSize:night.font.caption,fontWeight:"600"},inputRow:{flexDirection:"row",alignItems:"center",gap:8,paddingBottom:12},input:{flex:1,height:38,paddingHorizontal:12,borderRadius:night.radius.row,backgroundColor:night.color.surfaceElevated,color:night.color.text,fontSize:night.font.body},fieldRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:10,paddingVertical:6},fieldCol:{paddingVertical:6,gap:6},fieldLabel:{color:night.color.textSecondary,fontSize:night.font.caption,width:110},fieldInput:{flex:1,height:34,paddingHorizontal:10,borderRadius:night.radius.segment,backgroundColor:night.color.surfaceElevated,color:night.color.text,fontSize:night.font.caption},confirmTitle:{color:night.color.text,fontSize:night.font.row,fontWeight:"600",paddingHorizontal:12,paddingTop:12},confirmChange:{color:night.color.text,fontSize:night.font.body,lineHeight:19,paddingHorizontal:12,paddingTop:6,paddingBottom:6},consequence:{color:night.color.warning,fontSize:night.font.caption,paddingHorizontal:12},claim:{gap:6,paddingHorizontal:2},claimText:{color:night.color.text,fontSize:night.font.row,lineHeight:22},cite:{color:night.color.accent,fontSize:night.font.caption,fontWeight:"700"},verified:{color:night.color.accent,fontSize:night.font.caption,fontWeight:"600"},citeBox:{padding:10,borderRadius:night.radius.row,backgroundColor:night.color.surface,borderWidth:StyleSheet.hairlineWidth,borderColor:night.color.border,gap:2},citeLabel:{color:night.color.text,fontSize:night.font.caption,fontWeight:"600"},citeDetail:{color:night.color.textSecondary,fontSize:night.font.caption,fontFamily:"Menlo"},verifyBtn:{alignSelf:"flex-start",flexDirection:"row",alignItems:"center",gap:5,paddingHorizontal:10,paddingVertical:5,borderRadius:night.radius.chip,backgroundColor:night.color.accentSoft},verifyText:{color:night.color.accent,fontSize:night.font.micro,fontWeight:"700"},detailsBody:{color:night.color.textSecondary,fontSize:night.font.caption,lineHeight:18,paddingHorizontal:12,paddingBottom:12},tabsWrap:{gap:8},tabBar:{flexDirection:"row",gap:6},tab:{paddingHorizontal:12,paddingVertical:6,borderRadius:night.radius.badge,backgroundColor:night.color.fill},tabOn:{backgroundColor:night.color.accentSoft},tabText:{color:night.color.textSecondary,fontSize:night.font.caption,fontWeight:"600"},tabTextOn:{color:night.color.accent},tlRow:{flexDirection:"row",gap:10,paddingHorizontal:12,paddingVertical:4,alignItems:"flex-start"},tlAt:{width:46,color:night.color.textTertiary,fontSize:night.font.micro,fontFamily:"Menlo",paddingTop:3},tlLine:{width:12,alignItems:"center"},tlDot:{width:8,height:8,borderRadius:4,marginTop:5},tlStem:{width:1,flex:1,minHeight:18,backgroundColor:night.color.separator,marginTop:2},tlSource:{color:night.color.textTertiary,fontSize:9,fontWeight:"700",letterSpacing:.6},sparkHead:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",paddingHorizontal:12,paddingTop:8},sparkCurrent:{color:night.color.text,fontSize:22,fontWeight:"700"},sparkUnit:{color:night.color.textSecondary,fontSize:night.font.caption,fontWeight:"500"},spark:{flexDirection:"row",alignItems:"flex-end",gap:2,paddingHorizontal:12,paddingTop:6,paddingBottom:6},sparkBar:{flex:1,borderRadius:1},live:{flexDirection:"row",alignItems:"center",gap:5,paddingHorizontal:8,paddingVertical:3,borderRadius:night.radius.badge,backgroundColor:night.color.dangerSoft},liveDot:{width:6,height:6,borderRadius:3,backgroundColor:night.color.danger},liveText:{color:night.color.danger,fontSize:9,fontWeight:"800",letterSpacing:.8},cmpHead:{flexDirection:"row",paddingHorizontal:12,paddingVertical:6,backgroundColor:night.color.fill,gap:8},cmpCol:{flex:1,color:night.color.textTertiary,fontSize:night.font.micro,fontWeight:"700",letterSpacing:.6,textTransform:"uppercase"},cmpRow:{flexDirection:"row",paddingHorizontal:12,paddingVertical:8,gap:8,alignItems:"flex-start"},cmpDiff:{backgroundColor:night.color.fill},cmpKey:{width:90,color:night.color.textSecondary,fontSize:night.font.caption},cmpVal:{flex:1,color:night.color.text,fontSize:night.font.caption,fontFamily:"Menlo"},cardImage:{width:"100%",height:140,backgroundColor:night.color.fill},cardText:{paddingHorizontal:12,paddingTop:10,paddingBottom:4,gap:4},cardTitle:{color:night.color.text,fontSize:night.font.row,fontWeight:"600"},fact:{flexDirection:"row",justifyContent:"space-between",gap:8},factLabel:{color:night.color.textSecondary,fontSize:night.font.caption},factValue:{color:night.color.text,fontSize:night.font.caption,fontWeight:"500"},carouselTitle:{color:night.color.text,fontSize:night.font.caption,fontWeight:"600",paddingBottom:8},carousel:{gap:8,paddingRight:8},carouselCard:{width:224,borderRadius:night.radius.card,borderWidth:StyleSheet.hairlineWidth,borderColor:night.color.border,backgroundColor:night.color.surface,overflow:"hidden"},shot:{width:"100%",height:220,backgroundColor:night.color.fill},shotBig:{height:520},progress:{height:4,backgroundColor:night.color.fill,marginHorizontal:12,marginTop:6,marginBottom:8,borderRadius:2,overflow:"hidden"},progressFill:{height:4,backgroundColor:night.color.accent},step:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:12,paddingVertical:9},stepMark:{width:20,height:20,borderRadius:10,backgroundColor:night.color.fillTertiary,alignItems:"center",justifyContent:"center"},stepDone:{backgroundColor:night.color.accent},stepFailed:{backgroundColor:night.color.danger},stepRunning:{backgroundColor:night.color.info},stepNum:{color:night.color.text,fontSize:night.font.micro,fontWeight:"700"},checkpoint:{alignSelf:"flex-start",flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:12,paddingVertical:7,borderRadius:night.radius.chip,backgroundColor:night.color.fill},cpFlag:{width:8,height:8,borderRadius:2,backgroundColor:night.color.info},cpText:{color:night.color.textSecondary,fontSize:night.font.caption},cpRestore:{color:night.color.accent,fontSize:night.font.caption,fontWeight:"600"},taskHead:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:8,paddingHorizontal:12,paddingTop:12},banner:{flexDirection:"row",alignItems:"center",gap:8,paddingLeft:12,paddingRight:4,paddingVertical:4,borderRadius:night.radius.row,borderWidth:StyleSheet.hairlineWidth},bannerText:{flex:1,fontSize:night.font.caption,fontWeight:"600"},fileIcon:{width:40,height:40,borderRadius:8,backgroundColor:night.color.fill,alignItems:"center",justifyContent:"center"},fileExt:{color:night.color.textSecondary,fontSize:10,fontWeight:"800"}});