@btndprojects/loam-ui-native 0.0.0-stage → 0.1.1

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 (269) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -2
  3. package/dist/accordion/index.js +3 -0
  4. package/dist/adaptive/index.js +2 -0
  5. package/dist/alert/index.js +3 -0
  6. package/dist/analyzer/index.js +6 -0
  7. package/dist/announcement/index.js +6 -0
  8. package/dist/audio-player/index.js +3 -0
  9. package/dist/avatar/index.js +3 -0
  10. package/dist/avatar-group/index.js +3 -0
  11. package/dist/badge/index.js +5 -0
  12. package/dist/banner/index.js +2 -0
  13. package/dist/board/index.js +7 -0
  14. package/dist/button/index.js +5 -0
  15. package/dist/camera-permission/index.js +13 -0
  16. package/dist/capture-result/index.js +18 -0
  17. package/dist/card/index.js +4 -0
  18. package/dist/card-form/index.js +10 -0
  19. package/dist/carousel/index.js +2 -0
  20. package/dist/chart/index.js +6 -0
  21. package/dist/charts/index.js +7 -0
  22. package/dist/checkbox/index.js +7 -0
  23. package/dist/checklist/index.js +10 -0
  24. package/dist/checkout/index.js +13 -0
  25. package/dist/chip/index.js +7 -0
  26. package/dist/chunk-223Q2T2Q.js +229 -0
  27. package/dist/chunk-2A5NIQAK.js +254 -0
  28. package/dist/chunk-2GK6PHGE.js +363 -0
  29. package/dist/chunk-2WUTXHMU.js +1 -0
  30. package/dist/chunk-2ZZ7TDJ4.js +324 -0
  31. package/dist/chunk-35OFI3JG.js +499 -0
  32. package/dist/chunk-3ARE4TES.js +195 -0
  33. package/dist/chunk-3ECPOSKO.js +1 -0
  34. package/dist/chunk-3ENTMPQY.js +229 -0
  35. package/dist/chunk-3HJH6FF4.js +98 -0
  36. package/dist/chunk-3NMD74ZU.js +4 -0
  37. package/dist/chunk-3WPW4KUN.js +182 -0
  38. package/dist/chunk-423B7SPN.js +993 -0
  39. package/dist/chunk-47FWHGUN.js +394 -0
  40. package/dist/chunk-4BXMXBJO.js +141 -0
  41. package/dist/chunk-4DS5ZWVC.js +83 -0
  42. package/dist/chunk-4GBOGOTV.js +295 -0
  43. package/dist/chunk-4SZYY6AN.js +99 -0
  44. package/dist/chunk-4YIP3CWS.js +237 -0
  45. package/dist/chunk-4YQOR7JM.js +204 -0
  46. package/dist/chunk-4ZAHCY44.js +177 -0
  47. package/dist/chunk-52X2VYTD.js +228 -0
  48. package/dist/chunk-5P26LBDL.js +1 -0
  49. package/dist/chunk-5XLRYDAX.js +1 -0
  50. package/dist/chunk-5YNTNN5A.js +177 -0
  51. package/dist/chunk-6HT2LP62.js +504 -0
  52. package/dist/chunk-6N33LFQA.js +35 -0
  53. package/dist/chunk-6X6PQ443.js +432 -0
  54. package/dist/chunk-7CFF4HXS.js +126 -0
  55. package/dist/chunk-7O2FMUPT.js +755 -0
  56. package/dist/chunk-AI4DWZCD.js +162 -0
  57. package/dist/chunk-AWJOCGFZ.js +213 -0
  58. package/dist/chunk-AZRX6SAC.js +285 -0
  59. package/dist/chunk-B54QE2FN.js +1 -0
  60. package/dist/chunk-BC475SJH.js +1 -0
  61. package/dist/chunk-BEDBFJND.js +202 -0
  62. package/dist/chunk-BTTFCMKG.js +166 -0
  63. package/dist/chunk-BV3B2HYZ.js +1635 -0
  64. package/dist/chunk-C2NTXVWM.js +98 -0
  65. package/dist/chunk-CDRZHT42.js +424 -0
  66. package/dist/chunk-CJ5EOYZE.js +62 -0
  67. package/dist/chunk-CUMUNPXY.js +128 -0
  68. package/dist/chunk-CUS3ZSCU.js +1 -0
  69. package/dist/chunk-CYRBHQQZ.js +411 -0
  70. package/dist/chunk-DHWADYZX.js +144 -0
  71. package/dist/chunk-DKCSPATL.js +1 -0
  72. package/dist/chunk-DM5QUKKO.js +326 -0
  73. package/dist/chunk-DYBH2I6W.js +1 -0
  74. package/dist/chunk-DZ255O2F.js +1 -0
  75. package/dist/chunk-E35BPSGW.js +1 -0
  76. package/dist/chunk-EJBDRVIH.js +166 -0
  77. package/dist/chunk-F43NP42L.js +1 -0
  78. package/dist/chunk-F5XNPWS7.js +1024 -0
  79. package/dist/chunk-FMYDDECK.js +1521 -0
  80. package/dist/chunk-G3HOYSF7.js +1 -0
  81. package/dist/chunk-GDKZTW34.js +395 -0
  82. package/dist/chunk-GL7B2DOW.js +134 -0
  83. package/dist/chunk-GNNJ4GCC.js +471 -0
  84. package/dist/chunk-GNZ56EUI.js +1 -0
  85. package/dist/chunk-H6NIOQHK.js +346 -0
  86. package/dist/chunk-H6PC7RDA.js +1 -0
  87. package/dist/chunk-HET4LLMX.js +129 -0
  88. package/dist/chunk-HPPW424V.js +334 -0
  89. package/dist/chunk-HQOQIBJI.js +1 -0
  90. package/dist/chunk-HU2EQNRZ.js +44 -0
  91. package/dist/chunk-HZ6CNMAF.js +870 -0
  92. package/dist/chunk-IIQTAY3J.js +715 -0
  93. package/dist/chunk-ITTYJZWX.js +271 -0
  94. package/dist/chunk-IVNRBPGC.js +1018 -0
  95. package/dist/chunk-J4KLDGI4.js +1 -0
  96. package/dist/chunk-J7Q7VCVC.js +254 -0
  97. package/dist/chunk-JDEOITQ2.js +1 -0
  98. package/dist/chunk-JNH2TYIN.js +96 -0
  99. package/dist/chunk-JNY4ZHAR.js +634 -0
  100. package/dist/chunk-JRLTGLN4.js +1 -0
  101. package/dist/chunk-JTRJJLKL.js +1 -0
  102. package/dist/chunk-JUAMLEHX.js +379 -0
  103. package/dist/chunk-JXJB2X6M.js +131 -0
  104. package/dist/chunk-KMI5ML5I.js +262 -0
  105. package/dist/chunk-KTAC4MGE.js +4 -0
  106. package/dist/chunk-LAECSR4H.js +178 -0
  107. package/dist/chunk-LK4BCSGX.js +1 -0
  108. package/dist/chunk-LOE5YNN3.js +470 -0
  109. package/dist/chunk-LRJNDEIA.js +302 -0
  110. package/dist/chunk-LSS54GLJ.js +116 -0
  111. package/dist/chunk-LZLHELAG.js +137 -0
  112. package/dist/chunk-M2LUXGKZ.js +1 -0
  113. package/dist/chunk-MOUJOP55.js +425 -0
  114. package/dist/chunk-N32RGOA5.js +159 -0
  115. package/dist/chunk-N5ZNE2YE.js +1 -0
  116. package/dist/chunk-NBNCBML6.js +1 -0
  117. package/dist/chunk-NKB7BZYK.js +167 -0
  118. package/dist/chunk-NQYBUO3K.js +1795 -0
  119. package/dist/chunk-NY2U3PBI.js +59 -0
  120. package/dist/chunk-O4AEHWII.js +464 -0
  121. package/dist/chunk-O7AE6DAF.js +146 -0
  122. package/dist/chunk-OETCUXQP.js +134 -0
  123. package/dist/chunk-OOPPQH27.js +179 -0
  124. package/dist/chunk-OPXFZ4Y5.js +204 -0
  125. package/dist/chunk-P23EQNRQ.js +338 -0
  126. package/dist/chunk-PJXUJYS6.js +248 -0
  127. package/dist/chunk-PNWUWOBF.js +1 -0
  128. package/dist/chunk-PUPM2YGF.js +376 -0
  129. package/dist/chunk-PZXZJBMP.js +620 -0
  130. package/dist/chunk-Q72LJOVE.js +169 -0
  131. package/dist/chunk-QCDXZBC5.js +247 -0
  132. package/dist/chunk-QDYDBCFP.js +197 -0
  133. package/dist/chunk-QJJ6MADV.js +274 -0
  134. package/dist/chunk-QKXCPTFS.js +349 -0
  135. package/dist/chunk-QWCMU5B2.js +860 -0
  136. package/dist/chunk-RIBDXGUG.js +108 -0
  137. package/dist/chunk-RJQOOHT2.js +214 -0
  138. package/dist/chunk-RNGLIHFA.js +191 -0
  139. package/dist/chunk-RQ3HASCC.js +6 -0
  140. package/dist/chunk-RSOJT5YW.js +124 -0
  141. package/dist/chunk-RTIKSY6A.js +1 -0
  142. package/dist/chunk-RUZHTGKB.js +237 -0
  143. package/dist/chunk-RW6ZL2FQ.js +284 -0
  144. package/dist/chunk-S7F6XLTK.js +540 -0
  145. package/dist/chunk-SBMNWWBV.js +155 -0
  146. package/dist/chunk-SDTQPRRB.js +1 -0
  147. package/dist/chunk-SYNOJOQO.js +377 -0
  148. package/dist/chunk-T753XT36.js +1 -0
  149. package/dist/chunk-TKQYWZ5V.js +196 -0
  150. package/dist/chunk-TKVFVF5D.js +95 -0
  151. package/dist/chunk-TOXAGRDQ.js +144 -0
  152. package/dist/chunk-TUTI5HOZ.js +112 -0
  153. package/dist/chunk-U7TFM2JA.js +140 -0
  154. package/dist/chunk-UC2WGUP3.js +627 -0
  155. package/dist/chunk-UWFLYMAR.js +1126 -0
  156. package/dist/chunk-UWSZB7BJ.js +1 -0
  157. package/dist/chunk-UYG5L34B.js +87 -0
  158. package/dist/chunk-VBOXAEPI.js +336 -0
  159. package/dist/chunk-VCDBXW5H.js +188 -0
  160. package/dist/chunk-VCXPHHDS.js +1 -0
  161. package/dist/chunk-VEAYTRPX.js +414 -0
  162. package/dist/chunk-VFCUIDRT.js +1 -0
  163. package/dist/chunk-VQHPQEUH.js +273 -0
  164. package/dist/chunk-VXDZFJGP.js +874 -0
  165. package/dist/chunk-WS56BL3D.js +1 -0
  166. package/dist/chunk-WSW6ZFAQ.js +98 -0
  167. package/dist/chunk-XNUVB5OL.js +375 -0
  168. package/dist/chunk-XOSCY2CW.js +242 -0
  169. package/dist/chunk-XXXEFXY5.js +99 -0
  170. package/dist/chunk-Y5CSSPV4.js +1 -0
  171. package/dist/chunk-Y6DU4J47.js +1 -0
  172. package/dist/chunk-YC6WORFL.js +535 -0
  173. package/dist/chunk-YDGVJETP.js +60 -0
  174. package/dist/chunk-YF4NSSMT.js +366 -0
  175. package/dist/chunk-YG3ZJHGU.js +223 -0
  176. package/dist/chunk-YIJ55TBC.js +1 -0
  177. package/dist/chunk-YKZ4RZZF.js +1 -0
  178. package/dist/chunk-YLLCXTMC.js +37 -0
  179. package/dist/chunk-YTA74UZR.js +1 -0
  180. package/dist/chunk-YTFKPRUK.js +845 -0
  181. package/dist/chunk-Z7H7VSFZ.js +323 -0
  182. package/dist/chunk-ZK2H4O5P.js +1 -0
  183. package/dist/chunk-ZVFE5QGU.js +524 -0
  184. package/dist/coachmark/index.js +4 -0
  185. package/dist/code-block/index.js +4 -0
  186. package/dist/color-field/index.js +7 -0
  187. package/dist/commerce/index.js +20 -0
  188. package/dist/connectivity/index.js +2 -0
  189. package/dist/context-menu/index.js +5 -0
  190. package/dist/copy-button/index.js +3 -0
  191. package/dist/data-grid/index.js +24 -0
  192. package/dist/date-range-picker/index.js +13 -0
  193. package/dist/description-list/index.js +2 -0
  194. package/dist/dialog/index.js +3 -0
  195. package/dist/empty-state/index.js +3 -0
  196. package/dist/error-summary/index.js +3 -0
  197. package/dist/fab/index.js +2 -0
  198. package/dist/file-upload/index.js +9 -0
  199. package/dist/filter-bar/index.js +8 -0
  200. package/dist/flow-run/index.js +14 -0
  201. package/dist/form/index.js +3 -0
  202. package/dist/gallery/index.js +2 -0
  203. package/dist/header/index.js +5 -0
  204. package/dist/hold-to-confirm/index.js +4 -0
  205. package/dist/index.d.ts +22883 -0
  206. package/dist/index.js +158 -0
  207. package/dist/infinite-list/index.js +2 -0
  208. package/dist/inline-edit/index.js +5 -0
  209. package/dist/input/index.js +5 -0
  210. package/dist/interactions/index.js +2 -0
  211. package/dist/invoice/index.js +10 -0
  212. package/dist/kbd/index.js +1 -0
  213. package/dist/keyboard/index.js +3 -0
  214. package/dist/list-row/index.js +7 -0
  215. package/dist/log-viewer/index.js +2 -0
  216. package/dist/map-view/index.js +3 -0
  217. package/dist/markdown/index.js +6 -0
  218. package/dist/metric/index.js +4 -0
  219. package/dist/money/index.js +3 -0
  220. package/dist/nav-drawer/index.js +2 -0
  221. package/dist/navigation/index.js +2 -0
  222. package/dist/notification-center/index.js +16 -0
  223. package/dist/number-roll/index.js +3 -0
  224. package/dist/one-handed/index.js +5 -0
  225. package/dist/os-surfaces/index.js +3 -0
  226. package/dist/otp/index.js +7 -0
  227. package/dist/page-header/index.js +1 -0
  228. package/dist/payment-method/index.js +12 -0
  229. package/dist/payment-status/index.js +16 -0
  230. package/dist/permission/index.js +2 -0
  231. package/dist/picker/index.js +7 -0
  232. package/dist/progress/index.js +5 -0
  233. package/dist/pull-to-refresh/index.js +4 -0
  234. package/dist/radio-group/index.js +6 -0
  235. package/dist/rating/index.js +2 -0
  236. package/dist/receivables/index.js +20 -0
  237. package/dist/refund/index.js +16 -0
  238. package/dist/save-status/index.js +3 -0
  239. package/dist/scroll-area/index.js +1 -0
  240. package/dist/search-bar/index.js +5 -0
  241. package/dist/segmented-control/index.js +5 -0
  242. package/dist/sheet/index.js +4 -0
  243. package/dist/skeleton/index.js +2 -0
  244. package/dist/slider/index.js +5 -0
  245. package/dist/spinner/index.js +2 -0
  246. package/dist/split-button/index.js +7 -0
  247. package/dist/spotlight/index.js +2 -0
  248. package/dist/stage-timeline/index.js +4 -0
  249. package/dist/status-dot/index.js +2 -0
  250. package/dist/stepper/index.js +6 -0
  251. package/dist/streaming-text/index.js +3 -0
  252. package/dist/survey/index.js +19 -0
  253. package/dist/switch/index.js +5 -0
  254. package/dist/system-state/index.js +4 -0
  255. package/dist/tab-bar/index.js +2 -0
  256. package/dist/tabs/index.js +2 -0
  257. package/dist/textarea/index.js +6 -0
  258. package/dist/thinking/index.js +2 -0
  259. package/dist/timeline/index.js +4 -0
  260. package/dist/toast/index.js +2 -0
  261. package/dist/toolbar/index.js +2 -0
  262. package/dist/tour/index.js +11 -0
  263. package/dist/truncation-notice/index.js +2 -0
  264. package/dist/update-notice/index.js +11 -0
  265. package/dist/video-player/index.js +2 -0
  266. package/dist/viewfinder/index.js +5 -0
  267. package/dist/widget/index.js +4 -0
  268. package/dist/wizard/index.js +6 -0
  269. package/package.json +76 -3
@@ -0,0 +1,860 @@
1
+ import { Textarea } from './chunk-BTTFCMKG.js';
2
+ import { KeyboardSpacer } from './chunk-HPPW424V.js';
3
+ import { Sheet } from './chunk-ZVFE5QGU.js';
4
+ import { Badge } from './chunk-SBMNWWBV.js';
5
+ import { Button } from './chunk-3ARE4TES.js';
6
+ import { Icon } from './chunk-TKVFVF5D.js';
7
+ import { iconNameOr } from '@btndprojects/loam-icons';
8
+ import * as React from 'react';
9
+ import { View, Text, Pressable, ScrollView } from 'react-native';
10
+ import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
11
+ import { nodeType, SEVERITIES, rule, RUN_STATES, flowStepWalk, nodeCount, runStateFor } from '@btndprojects/loam-workflow';
12
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
+
14
+ function flowIconName(name) {
15
+ return iconNameOr(name, "circle");
16
+ }
17
+ var FLOW_RUN_STATE_ICON = {
18
+ idle: "circle",
19
+ queued: "list-ol",
20
+ running: "loader",
21
+ ok: "check-circle",
22
+ err: "alert-triangle",
23
+ skipped: "skip-forward",
24
+ waiting: "user"
25
+ };
26
+ var FLOW_TONE_BADGE = {
27
+ accent: "accent",
28
+ info: "info",
29
+ warn: "warn",
30
+ danger: "danger",
31
+ good: "good",
32
+ "text-3": "neutral"
33
+ };
34
+ function FlowApprovalSheet({
35
+ node,
36
+ type,
37
+ context,
38
+ layout = "sheet",
39
+ open = false,
40
+ onOpenChange,
41
+ detents = ["half", "full"],
42
+ noteField = false,
43
+ noteLabel = "Note (optional)",
44
+ noteValue,
45
+ onNoteChange,
46
+ noteError,
47
+ safeAreaBottom = 0,
48
+ rejectLabel = "Reject",
49
+ approveLabel = "Approve",
50
+ motion = "full",
51
+ onDecide,
52
+ onIntent,
53
+ style,
54
+ testID
55
+ }) {
56
+ const theme = useLoamTheme();
57
+ const { styles } = useStyles(sheetStyles);
58
+ const def = type ?? nodeType(node.type);
59
+ const labelId = React.useId();
60
+ const errorId = React.useId();
61
+ const [internalNote, setInternalNote] = React.useState("");
62
+ const note = noteValue ?? internalNote;
63
+ const setNote = (next) => {
64
+ if (noteValue === void 0) setInternalNote(next);
65
+ onNoteChange?.(next);
66
+ };
67
+ const decide = (decision) => {
68
+ const trimmed = note.trim();
69
+ onDecide?.(decision, trimmed || void 0);
70
+ onIntent?.({
71
+ t: "approve",
72
+ nodeId: node.id,
73
+ decision,
74
+ ...trimmed ? { note: trimmed } : {}
75
+ });
76
+ onOpenChange?.(false);
77
+ };
78
+ const body = /* @__PURE__ */ jsxs(View, { testID, style: [styles.body, style], children: [
79
+ layout === "inline" ? /* @__PURE__ */ jsx(
80
+ Text,
81
+ {
82
+ accessibilityRole: "header",
83
+ style: styles.title,
84
+ ...{ "aria-level": 2 },
85
+ children: context.title
86
+ }
87
+ ) : null,
88
+ /* @__PURE__ */ jsx(Text, { style: styles.eyebrow, children: def.label }),
89
+ /* @__PURE__ */ jsxs(Text, { style: styles.nodeLine, children: [
90
+ node.label,
91
+ node.detail ? ` \xB7 ${node.detail}` : ""
92
+ ] }),
93
+ /* @__PURE__ */ jsx(Text, { style: styles.blurb, children: def.blurb }),
94
+ /* @__PURE__ */ jsx(View, { style: styles.context, children: typeof context.body === "string" ? /* @__PURE__ */ jsx(Text, { style: styles.contextText, children: context.body }) : context.body }),
95
+ /* @__PURE__ */ jsxs(View, { style: styles.section, children: [
96
+ /* @__PURE__ */ jsx(
97
+ Text,
98
+ {
99
+ accessibilityRole: "header",
100
+ style: styles.eyebrow,
101
+ ...{ "aria-level": 3 },
102
+ children: "Configuration"
103
+ }
104
+ ),
105
+ def.config.map(([key, description]) => /* @__PURE__ */ jsxs(View, { style: styles.configRow, children: [
106
+ /* @__PURE__ */ jsx(Text, { style: styles.configKey, children: key }),
107
+ /* @__PURE__ */ jsx(Text, { style: styles.configValue, children: description })
108
+ ] }, key))
109
+ ] }),
110
+ /* @__PURE__ */ jsxs(View, { style: styles.waiting, children: [
111
+ /* @__PURE__ */ jsxs(View, { style: styles.waitingHead, children: [
112
+ /* @__PURE__ */ jsx(
113
+ Icon,
114
+ {
115
+ name: "user",
116
+ size: theme.icon.xs,
117
+ color: theme.color.accentOnSoft,
118
+ strokeWidth: theme.icon.stroke
119
+ }
120
+ ),
121
+ /* @__PURE__ */ jsx(
122
+ Text,
123
+ {
124
+ accessibilityRole: "header",
125
+ style: styles.waitingEyebrow,
126
+ ...{ "aria-level": 3 },
127
+ children: "Waiting on you"
128
+ }
129
+ )
130
+ ] }),
131
+ /* @__PURE__ */ jsx(Text, { style: styles.waitingBody, children: "Approve is recorded with your name, the time and what you were shown. Reject continues the run along the rejected edge." })
132
+ ] }),
133
+ noteField ? /* @__PURE__ */ jsxs(View, { style: styles.section, children: [
134
+ /* @__PURE__ */ jsx(Text, { nativeID: labelId, style: styles.fieldLabel, children: noteLabel }),
135
+ /* @__PURE__ */ jsx(
136
+ Textarea,
137
+ {
138
+ rows: 2,
139
+ value: note,
140
+ onChangeText: setNote,
141
+ error: Boolean(noteError),
142
+ "aria-labelledby": labelId,
143
+ ...noteError ? { "aria-describedby": errorId, "aria-invalid": true } : null
144
+ }
145
+ ),
146
+ noteError ? /* @__PURE__ */ jsx(Text, { nativeID: errorId, accessibilityLiveRegion: "polite", style: styles.fieldError, children: noteError }) : null,
147
+ /* @__PURE__ */ jsx(KeyboardSpacer, {})
148
+ ] }) : null,
149
+ /* @__PURE__ */ jsxs(View, { style: [styles.commit, { marginBottom: safeAreaBottom }], children: [
150
+ /* @__PURE__ */ jsx(View, { style: styles.rejectSlot, children: /* @__PURE__ */ jsx(
151
+ Button,
152
+ {
153
+ variant: "outline",
154
+ size: "lg",
155
+ fullWidth: true,
156
+ leadingIcon: "x",
157
+ accessibilityLabel: rejectLabel,
158
+ onPress: () => decide("rejected"),
159
+ children: rejectLabel
160
+ }
161
+ ) }),
162
+ /* @__PURE__ */ jsx(View, { style: styles.approveSlot, children: /* @__PURE__ */ jsx(
163
+ Button,
164
+ {
165
+ variant: "primary",
166
+ size: "lg",
167
+ fullWidth: true,
168
+ leadingIcon: "check",
169
+ accessibilityLabel: approveLabel,
170
+ onPress: () => decide("approved"),
171
+ children: approveLabel
172
+ }
173
+ ) })
174
+ ] })
175
+ ] });
176
+ if (layout === "inline") return body;
177
+ return /* @__PURE__ */ jsx(
178
+ Sheet,
179
+ {
180
+ open,
181
+ title: context.title,
182
+ detents,
183
+ motion,
184
+ onOpenChange,
185
+ children: body
186
+ }
187
+ );
188
+ }
189
+ var sheetStyles = createStyleSheet((theme) => ({
190
+ body: {
191
+ gap: theme.space.s3
192
+ },
193
+ title: {
194
+ fontFamily: theme.font.display,
195
+ fontWeight: theme.font.displayWeight,
196
+ fontSize: theme.type.title2.fontSize,
197
+ lineHeight: theme.type.title2.lineHeight,
198
+ color: theme.color.text
199
+ },
200
+ eyebrow: {
201
+ fontFamily: theme.font.mono,
202
+ fontSize: theme.fontSize[10],
203
+ letterSpacing: theme.fontSize[10] * theme.tracking.caps,
204
+ textTransform: "uppercase",
205
+ color: theme.color.text3
206
+ },
207
+ nodeLine: {
208
+ fontFamily: theme.font.mono,
209
+ fontSize: theme.fontSize[11],
210
+ color: theme.color.text3
211
+ },
212
+ blurb: {
213
+ fontFamily: theme.font.sans,
214
+ fontSize: theme.fontSize[12],
215
+ lineHeight: theme.fontSize[12] * theme.lineHeight.normal,
216
+ color: theme.color.text2
217
+ },
218
+ context: {
219
+ gap: theme.space.s2
220
+ },
221
+ contextText: {
222
+ fontFamily: theme.font.sans,
223
+ fontSize: theme.fontSize[13],
224
+ lineHeight: theme.fontSize[13] * theme.lineHeight.normal,
225
+ color: theme.color.text
226
+ },
227
+ section: {
228
+ gap: theme.space.s2
229
+ },
230
+ configRow: {
231
+ gap: theme.space[2]
232
+ },
233
+ configKey: {
234
+ fontFamily: theme.font.sans,
235
+ fontWeight: theme.fontWeight.bold,
236
+ fontSize: theme.fontSize[12],
237
+ color: theme.color.text2
238
+ },
239
+ configValue: {
240
+ fontFamily: theme.font.sans,
241
+ fontSize: theme.fontSize[11],
242
+ lineHeight: theme.fontSize[11] * theme.lineHeight.normal,
243
+ color: theme.color.text3
244
+ },
245
+ waiting: {
246
+ gap: theme.space.s1,
247
+ borderRadius: theme.radius.sm,
248
+ padding: theme.space[10],
249
+ backgroundColor: theme.color.accentSoft,
250
+ // The spec draws this card as `--accent-soft` on a **visible** `--accent`
251
+ // edge rather than the usual invisible-until-high-contrast `edge.accent`,
252
+ // because it is the one block on the screen that must be found first. An
253
+ // accent border is a graphical edge held to 3:1, so it reads the *measured*
254
+ // accent (`focus.ringColor`), not the raw one —
255
+ // `loam/accent-edge-must-be-measured`.
256
+ borderWidth: theme.borderWidth.base,
257
+ borderColor: theme.focus.ringColor
258
+ },
259
+ waitingHead: {
260
+ flexDirection: "row",
261
+ alignItems: "center",
262
+ gap: theme.space.s2
263
+ },
264
+ waitingEyebrow: {
265
+ fontFamily: theme.font.mono,
266
+ fontSize: theme.fontSize[10],
267
+ letterSpacing: theme.fontSize[10] * theme.tracking.caps,
268
+ textTransform: "uppercase",
269
+ color: theme.color.accentOnSoft
270
+ },
271
+ waitingBody: {
272
+ fontFamily: theme.font.sans,
273
+ fontSize: theme.fontSize[12],
274
+ lineHeight: theme.fontSize[12] * theme.lineHeight.snug,
275
+ color: theme.color.accentOnSoft
276
+ },
277
+ fieldLabel: {
278
+ fontFamily: theme.font.sans,
279
+ fontWeight: theme.fontWeight.semibold,
280
+ fontSize: theme.fontSize[11],
281
+ color: theme.color.text2
282
+ },
283
+ fieldError: {
284
+ fontFamily: theme.font.sans,
285
+ fontSize: theme.fontSize[12],
286
+ color: theme.color.dangerOnSoft
287
+ },
288
+ commit: {
289
+ flexDirection: "row",
290
+ alignItems: "stretch",
291
+ gap: theme.space.s2
292
+ },
293
+ // Approve is the wider half: the decision the flow is waiting for, and the one
294
+ // an approver reaches for with a thumb. The `lg` control tier already clears
295
+ // the 44px touch minimum; `space[50]` is the spec's taller commit bar.
296
+ rejectSlot: {
297
+ flex: 1,
298
+ minHeight: theme.space[50]
299
+ },
300
+ approveSlot: {
301
+ flexGrow: 1.4,
302
+ flexShrink: 1,
303
+ flexBasis: 0,
304
+ minHeight: theme.space[50]
305
+ }
306
+ }));
307
+ function FlowStepSheet({
308
+ node = null,
309
+ type,
310
+ layout = "sheet",
311
+ issues = [],
312
+ open,
313
+ onOpenChange,
314
+ detents = ["half", "full"],
315
+ canApprove = false,
316
+ approveLabel = "Decide this approval",
317
+ onApprove,
318
+ motion = "full",
319
+ style,
320
+ testID
321
+ }) {
322
+ const theme = useLoamTheme();
323
+ const def = type ?? (node ? nodeType(node.type) : null);
324
+ const tone = def ? def.tone : "text-3";
325
+ const { styles } = useStyles(sheetStyles2, { tone });
326
+ const mine = React.useMemo(
327
+ () => node ? issues.filter((i) => i.node === node.id).slice().sort((a, b) => SEVERITIES[a.sev].rank - SEVERITIES[b.sev].rank) : [],
328
+ [issues, node]
329
+ );
330
+ const isOpen = open ?? node != null;
331
+ const human = def?.kind === "human";
332
+ const body = node && def ? /* @__PURE__ */ jsxs(View, { testID, style: [styles.body, style], children: [
333
+ /* @__PURE__ */ jsxs(View, { style: styles.head, children: [
334
+ /* @__PURE__ */ jsx(View, { style: styles.tile, children: /* @__PURE__ */ jsx(
335
+ Icon,
336
+ {
337
+ name: flowIconName(def.icon),
338
+ size: theme.icon.sm,
339
+ color: theme.color.text,
340
+ strokeWidth: theme.icon.stroke
341
+ }
342
+ ) }),
343
+ /* @__PURE__ */ jsx(Text, { style: styles.eyebrow, children: def.label })
344
+ ] }),
345
+ layout === "inline" ? /* @__PURE__ */ jsx(
346
+ Text,
347
+ {
348
+ accessibilityRole: "header",
349
+ style: styles.inlineTitle,
350
+ ...{ "aria-level": 2 },
351
+ children: node.label
352
+ }
353
+ ) : null,
354
+ /* @__PURE__ */ jsx(Text, { style: styles.detail, children: node.detail || def.label.toLowerCase() }),
355
+ /* @__PURE__ */ jsx(Text, { style: styles.blurb, children: def.blurb }),
356
+ /* @__PURE__ */ jsxs(View, { style: styles.section, children: [
357
+ /* @__PURE__ */ jsx(
358
+ Text,
359
+ {
360
+ accessibilityRole: "header",
361
+ style: styles.eyebrow,
362
+ ...{ "aria-level": 3 },
363
+ children: "Configuration"
364
+ }
365
+ ),
366
+ def.config.map(([key, description]) => /* @__PURE__ */ jsxs(View, { style: styles.configRow, children: [
367
+ /* @__PURE__ */ jsx(Text, { style: styles.configKey, children: key }),
368
+ /* @__PURE__ */ jsx(Text, { style: styles.configValue, children: description })
369
+ ] }, key))
370
+ ] }),
371
+ mine.length > 0 ? /* @__PURE__ */ jsxs(View, { accessibilityLabel: "Validation", style: styles.section, children: [
372
+ /* @__PURE__ */ jsx(
373
+ Text,
374
+ {
375
+ accessibilityRole: "header",
376
+ style: styles.eyebrow,
377
+ ...{ "aria-level": 3 },
378
+ children: "Validation"
379
+ }
380
+ ),
381
+ mine.map((issue) => /* @__PURE__ */ jsx(IssueRow, { issue }, `${issue.rule}:${issue.msg}`))
382
+ ] }) : null,
383
+ human && canApprove && onApprove ? /* @__PURE__ */ jsx(
384
+ Button,
385
+ {
386
+ variant: "primary",
387
+ size: "lg",
388
+ fullWidth: true,
389
+ leadingIcon: "user",
390
+ onPress: () => onApprove(node.id),
391
+ children: approveLabel
392
+ }
393
+ ) : null
394
+ ] }) : null;
395
+ if (layout === "inline") return /* @__PURE__ */ jsx(Fragment, { children: body });
396
+ return /* @__PURE__ */ jsx(
397
+ Sheet,
398
+ {
399
+ open: isOpen,
400
+ title: node ? node.label : void 0,
401
+ detents,
402
+ motion,
403
+ onOpenChange,
404
+ children: body
405
+ }
406
+ );
407
+ }
408
+ function IssueRow({ issue }) {
409
+ const sev = SEVERITIES[issue.sev];
410
+ const { styles } = useStyles(issueSheet, { sev: sev.tone });
411
+ const why = rule(issue.rule)?.why;
412
+ return /* @__PURE__ */ jsxs(View, { style: styles.box, children: [
413
+ /* @__PURE__ */ jsx(Badge, { variant: FLOW_TONE_BADGE[sev.tone], size: "sm", leadingIcon: flowIconName(sev.icon), children: sev.label }),
414
+ /* @__PURE__ */ jsx(Text, { style: styles.msg, children: issue.msg }),
415
+ why ? /* @__PURE__ */ jsx(Text, { style: styles.why, children: why }) : null
416
+ ] });
417
+ }
418
+ var sheetStyles2 = createStyleSheet((theme) => ({
419
+ body: {
420
+ gap: theme.space.s3
421
+ },
422
+ head: {
423
+ flexDirection: "row",
424
+ alignItems: "center",
425
+ gap: theme.space.s2
426
+ },
427
+ // The type tile: the node's identity, carried by a glyph as well as a tint.
428
+ tile: {
429
+ width: theme.space[26],
430
+ height: theme.space[26],
431
+ borderRadius: theme.radius.sm,
432
+ alignItems: "center",
433
+ justifyContent: "center",
434
+ borderWidth: theme.borderWidth.base,
435
+ borderColor: "transparent",
436
+ variants: {
437
+ tone: {
438
+ accent: { backgroundColor: theme.color.accentSoft, borderColor: theme.edge.accent },
439
+ info: { backgroundColor: theme.color.infoSoft, borderColor: theme.edge.info },
440
+ warn: { backgroundColor: theme.color.warnSoft, borderColor: theme.edge.warn },
441
+ danger: { backgroundColor: theme.color.dangerSoft, borderColor: theme.edge.danger },
442
+ good: { backgroundColor: theme.color.goodSoft, borderColor: theme.edge.good },
443
+ "text-3": { backgroundColor: theme.color.surface3, borderColor: theme.edge.neutral }
444
+ }
445
+ }
446
+ },
447
+ eyebrow: {
448
+ fontFamily: theme.font.mono,
449
+ fontSize: theme.fontSize[10],
450
+ letterSpacing: theme.fontSize[10] * theme.tracking.caps,
451
+ textTransform: "uppercase",
452
+ color: theme.color.text3
453
+ },
454
+ inlineTitle: {
455
+ fontFamily: theme.font.display,
456
+ fontWeight: theme.font.displayWeight,
457
+ fontSize: theme.type.title3.fontSize,
458
+ lineHeight: theme.type.title3.lineHeight,
459
+ color: theme.color.text
460
+ },
461
+ detail: {
462
+ fontFamily: theme.font.mono,
463
+ fontSize: theme.fontSize[12],
464
+ color: theme.color.text2
465
+ },
466
+ blurb: {
467
+ fontFamily: theme.font.sans,
468
+ fontSize: theme.fontSize[12],
469
+ lineHeight: theme.fontSize[12] * theme.lineHeight.normal,
470
+ color: theme.color.text2
471
+ },
472
+ section: {
473
+ gap: theme.space.s2
474
+ },
475
+ configRow: {
476
+ gap: theme.space[2]
477
+ },
478
+ configKey: {
479
+ fontFamily: theme.font.sans,
480
+ fontWeight: theme.fontWeight.bold,
481
+ fontSize: theme.fontSize[12],
482
+ color: theme.color.text2
483
+ },
484
+ configValue: {
485
+ fontFamily: theme.font.sans,
486
+ fontSize: theme.fontSize[11],
487
+ lineHeight: theme.fontSize[11] * theme.lineHeight.normal,
488
+ color: theme.color.text3
489
+ }
490
+ }));
491
+ var issueSheet = createStyleSheet((theme) => ({
492
+ box: {
493
+ gap: theme.space.s1,
494
+ borderRadius: theme.radius.sm,
495
+ padding: theme.space[10],
496
+ borderWidth: theme.borderWidth.base,
497
+ variants: {
498
+ sev: {
499
+ danger: { backgroundColor: theme.color.dangerSoft, borderColor: theme.edge.danger },
500
+ warn: { backgroundColor: theme.color.warnSoft, borderColor: theme.edge.warn },
501
+ info: { backgroundColor: theme.color.infoSoft, borderColor: theme.edge.info }
502
+ }
503
+ }
504
+ },
505
+ msg: {
506
+ fontFamily: theme.font.sans,
507
+ fontWeight: theme.fontWeight.semibold,
508
+ fontSize: theme.fontSize[12],
509
+ lineHeight: theme.fontSize[12] * theme.lineHeight.snug,
510
+ variants: {
511
+ sev: {
512
+ danger: { color: theme.color.dangerOnSoft },
513
+ warn: { color: theme.color.warnOnSoft },
514
+ info: { color: theme.color.infoOnSoft }
515
+ }
516
+ }
517
+ },
518
+ why: {
519
+ fontFamily: theme.font.sans,
520
+ fontSize: theme.fontSize[11],
521
+ lineHeight: theme.fontSize[11] * theme.lineHeight.normal,
522
+ variants: {
523
+ sev: {
524
+ danger: { color: theme.color.dangerOnSoft },
525
+ warn: { color: theme.color.warnOnSoft },
526
+ info: { color: theme.color.infoOnSoft }
527
+ }
528
+ }
529
+ }
530
+ }));
531
+ function useToneInk(tone) {
532
+ const theme = useLoamTheme();
533
+ switch (tone) {
534
+ case "accent":
535
+ return theme.color.accentOnSoft;
536
+ case "info":
537
+ return theme.color.infoOnSoft;
538
+ case "warn":
539
+ return theme.color.warnOnSoft;
540
+ case "danger":
541
+ return theme.color.dangerOnSoft;
542
+ case "good":
543
+ return theme.color.goodOnSoft;
544
+ case "text-3":
545
+ default:
546
+ return theme.color.text2;
547
+ }
548
+ }
549
+ function FlowStepRow({
550
+ node,
551
+ type,
552
+ depth = 0,
553
+ branchLabel,
554
+ repeat = false,
555
+ note = false,
556
+ orphan = false,
557
+ runState = "idle",
558
+ canDecide = false,
559
+ last = false,
560
+ onPress,
561
+ accessibilityLabel,
562
+ style,
563
+ testID
564
+ }) {
565
+ const theme = useLoamTheme();
566
+ const def = type ?? nodeType(node.type);
567
+ const human = def.kind === "human";
568
+ const running = runState !== "idle";
569
+ const tone = running ? RUN_STATES[runState].tone : def.tone;
570
+ const glyph = running ? FLOW_RUN_STATE_ICON[runState] : flowIconName(def.icon);
571
+ const { styles } = useStyles(sheet, { tone, note });
572
+ const ink = useToneInk(tone);
573
+ const detail = node.detail || def.label.toLowerCase();
574
+ const name = accessibilityLabel ?? `${def.label}: ${node.label}` + (human && canDecide ? " \u2014 waiting on you, tap to approve" : "") + (repeat ? " \u2014 repeats" : "") + (orphan ? " \u2014 not reachable from the trigger" : "");
575
+ return /* @__PURE__ */ jsxs(
576
+ Pressable,
577
+ {
578
+ accessibilityRole: "button",
579
+ accessibilityLabel: name,
580
+ testID,
581
+ onPress: onPress ? () => onPress(node.id) : void 0,
582
+ style: ({ pressed }) => [
583
+ styles.row,
584
+ // The indent is the edge information: `flowStepWalk` already clamped the
585
+ // depth, so this can never walk off the phone.
586
+ { paddingStart: theme.space[12] + depth * theme.space[16] },
587
+ pressed && styles.rowPressed,
588
+ style
589
+ ],
590
+ children: [
591
+ /* @__PURE__ */ jsxs(View, { style: styles.rail, pointerEvents: "none", children: [
592
+ /* @__PURE__ */ jsx(View, { style: styles.node, children: /* @__PURE__ */ jsx(Icon, { name: glyph, size: theme.icon.xs, color: ink, strokeWidth: theme.icon.stroke }) }),
593
+ last ? null : /* @__PURE__ */ jsx(View, { style: styles.connector })
594
+ ] }),
595
+ /* @__PURE__ */ jsxs(View, { style: styles.card, children: [
596
+ /* @__PURE__ */ jsxs(View, { style: styles.titleRow, children: [
597
+ branchLabel ? /* @__PURE__ */ jsx(Badge, { variant: "warn", size: "sm", children: branchLabel }) : null,
598
+ /* @__PURE__ */ jsx(Text, { numberOfLines: 1, style: styles.label, children: node.label }),
599
+ repeat ? /* @__PURE__ */ jsx(
600
+ Icon,
601
+ {
602
+ name: "refresh",
603
+ size: theme.icon.xs,
604
+ color: theme.color.text2,
605
+ strokeWidth: theme.icon.stroke
606
+ }
607
+ ) : null,
608
+ running ? /* @__PURE__ */ jsx(Badge, { variant: FLOW_TONE_BADGE[tone], size: "sm", leadingIcon: glyph, children: RUN_STATES[runState].label }) : null,
609
+ human && canDecide ? /* @__PURE__ */ jsx(Badge, { variant: "accent", size: "sm", leadingIcon: "user", children: "Tap to decide" }) : null,
610
+ orphan ? /* @__PURE__ */ jsx(Badge, { variant: "danger", size: "sm", leadingIcon: "alert-triangle", children: "Not reachable" }) : null,
611
+ note ? /* @__PURE__ */ jsx(Badge, { variant: "warn", size: "sm", leadingIcon: "edit", children: "Note" }) : null
612
+ ] }),
613
+ /* @__PURE__ */ jsxs(Text, { numberOfLines: 1, style: styles.sub, children: [
614
+ def.label,
615
+ " \xB7 ",
616
+ detail
617
+ ] })
618
+ ] }),
619
+ /* @__PURE__ */ jsx(
620
+ Icon,
621
+ {
622
+ name: "chevron-right",
623
+ size: theme.icon.sm,
624
+ color: theme.color.text3,
625
+ strokeWidth: theme.icon.stroke
626
+ }
627
+ )
628
+ ]
629
+ }
630
+ );
631
+ }
632
+ function FlowStepList({
633
+ graph,
634
+ steps,
635
+ run = null,
636
+ presetLabel = "Flow",
637
+ canApprove = false,
638
+ label = "Flow steps",
639
+ safeAreaBottom = 0,
640
+ onStepOpen,
641
+ onOpenMap,
642
+ onIntent,
643
+ style,
644
+ testID
645
+ }) {
646
+ const theme = useLoamTheme();
647
+ const { styles } = useStyles(listSheet);
648
+ const walked = React.useMemo(() => steps ?? flowStepWalk(graph), [steps, graph]);
649
+ const count = React.useMemo(() => nodeCount(graph), [graph]);
650
+ return /* @__PURE__ */ jsxs(View, { accessibilityLabel: label, testID, style: [styles.root, style], children: [
651
+ /* @__PURE__ */ jsxs(View, { style: styles.header, children: [
652
+ /* @__PURE__ */ jsxs(View, { style: styles.headerText, children: [
653
+ /* @__PURE__ */ jsxs(
654
+ Text,
655
+ {
656
+ accessibilityRole: "header",
657
+ numberOfLines: 1,
658
+ style: styles.title,
659
+ ...{ "aria-level": 2 },
660
+ children: [
661
+ presetLabel,
662
+ " flow"
663
+ ]
664
+ }
665
+ ),
666
+ /* @__PURE__ */ jsxs(Text, { numberOfLines: 1, style: styles.headerSub, children: [
667
+ count,
668
+ " steps \xB7 read-only on a phone"
669
+ ] })
670
+ ] }),
671
+ /* @__PURE__ */ jsx(
672
+ Button,
673
+ {
674
+ variant: "tonal",
675
+ size: "sm",
676
+ leadingIcon: run ? "refresh" : "play",
677
+ onPress: () => onIntent?.({ t: "run" }),
678
+ children: run ? "Replay" : "Run"
679
+ }
680
+ )
681
+ ] }),
682
+ /* @__PURE__ */ jsx(ScrollView, { style: styles.scroll, contentContainerStyle: styles.scrollContent, role: "list", children: walked.map((step, i) => /* @__PURE__ */ jsx(View, { role: "listitem", children: /* @__PURE__ */ jsx(
683
+ FlowStepRow,
684
+ {
685
+ node: step.node,
686
+ type: step.type,
687
+ depth: step.depth,
688
+ ...step.branchLabel ? { branchLabel: step.branchLabel } : {},
689
+ repeat: step.repeat,
690
+ note: step.note,
691
+ orphan: step.orphan,
692
+ runState: run ? runStateFor(graph, run.trace, run.index, step.node.id) : "idle",
693
+ canDecide: canApprove && step.type.kind === "human",
694
+ last: i === walked.length - 1,
695
+ ...onStepOpen ? { onPress: onStepOpen } : {}
696
+ }
697
+ ) }, step.key)) }),
698
+ /* @__PURE__ */ jsxs(View, { style: [styles.footer, { paddingBottom: theme.space[12] + safeAreaBottom }], children: [
699
+ onOpenMap ? /* @__PURE__ */ jsx(Button, { variant: "outline", size: "md", fullWidth: true, leadingIcon: "map-pin", onPress: onOpenMap, children: "Open the map" }) : null,
700
+ /* @__PURE__ */ jsx(Text, { style: styles.footerNote, children: "Approving a run on a phone: yes. Rewiring sixteen nodes on a phone: no." })
701
+ ] })
702
+ ] });
703
+ }
704
+ var sheet = createStyleSheet((theme) => ({
705
+ row: {
706
+ flexDirection: "row",
707
+ alignItems: "stretch",
708
+ gap: theme.space.s2,
709
+ // The row is a real tap target before its content is measured.
710
+ minHeight: theme.space[60],
711
+ paddingEnd: theme.space[12],
712
+ paddingVertical: theme.space.s2
713
+ },
714
+ rowPressed: {
715
+ backgroundColor: theme.state.pressed
716
+ },
717
+ rail: {
718
+ width: theme.space[26],
719
+ alignItems: "center"
720
+ },
721
+ // The status tile: a tone plus a glyph, never a tone alone. The edge box lives
722
+ // on the base so every tone is the same size, and it becomes a real outline
723
+ // under `prefers-contrast: more`, where the soft fill collapses to `surface`.
724
+ node: {
725
+ marginTop: theme.space[14],
726
+ width: theme.space[22],
727
+ height: theme.space[22],
728
+ borderRadius: theme.radius.full,
729
+ alignItems: "center",
730
+ justifyContent: "center",
731
+ borderWidth: theme.borderWidth.base,
732
+ borderColor: "transparent",
733
+ variants: {
734
+ tone: {
735
+ accent: { backgroundColor: theme.color.accentSoft, borderColor: theme.edge.accent },
736
+ info: { backgroundColor: theme.color.infoSoft, borderColor: theme.edge.info },
737
+ warn: { backgroundColor: theme.color.warnSoft, borderColor: theme.edge.warn },
738
+ danger: { backgroundColor: theme.color.dangerSoft, borderColor: theme.edge.danger },
739
+ good: { backgroundColor: theme.color.goodSoft, borderColor: theme.edge.good },
740
+ "text-3": { backgroundColor: theme.color.surface3, borderColor: theme.edge.neutral }
741
+ }
742
+ }
743
+ },
744
+ // A drawn rule rather than a gap, which is the cheat sheet's test for reaching
745
+ // for the static `borderWidth.*` ramp.
746
+ connector: {
747
+ flex: 1,
748
+ width: theme.borderWidth.heavy,
749
+ marginTop: theme.space.s1,
750
+ backgroundColor: theme.color.border
751
+ },
752
+ card: {
753
+ flex: 1,
754
+ gap: theme.space.s1,
755
+ borderRadius: theme.radius.sm,
756
+ padding: theme.space.s2,
757
+ variants: {
758
+ // A note is not part of the run (W14): dashed is the shape channel, the
759
+ // warn tint the colour one, and the row also carries a "Note" pill.
760
+ note: {
761
+ true: {
762
+ backgroundColor: theme.color.warnSoft,
763
+ borderWidth: theme.borderWidth.base,
764
+ borderColor: theme.edge.warn,
765
+ borderStyle: "dashed"
766
+ },
767
+ false: { backgroundColor: theme.color.surface2 }
768
+ }
769
+ }
770
+ },
771
+ titleRow: {
772
+ flexDirection: "row",
773
+ alignItems: "center",
774
+ flexWrap: "wrap",
775
+ gap: theme.space.s2
776
+ },
777
+ // Both inks re-resolve on the note card. `audit-contrast` caught the web row
778
+ // reading `--text-3` on `--warn-soft` at 2.88:1 in dark mode over a pressed
779
+ // state layer — the plain surface inks are measured against the neutral ramp
780
+ // only, so on a tone tint they need the tint's own measured ink. The native
781
+ // audit has no equivalent rule, which is exactly why this is written down.
782
+ label: {
783
+ flex: 1,
784
+ fontFamily: theme.font.sans,
785
+ fontWeight: theme.fontWeight.extrabold,
786
+ fontSize: theme.fontSize[14],
787
+ variants: {
788
+ note: {
789
+ true: { color: theme.color.warnOnSoft },
790
+ false: { color: theme.color.text }
791
+ }
792
+ }
793
+ },
794
+ sub: {
795
+ fontFamily: theme.font.mono,
796
+ fontSize: theme.fontSize[11],
797
+ variants: {
798
+ note: {
799
+ true: { color: theme.color.warnOnSoft },
800
+ false: { color: theme.color.text3 }
801
+ }
802
+ }
803
+ }
804
+ }));
805
+ var listSheet = createStyleSheet((theme) => ({
806
+ root: {
807
+ flex: 1,
808
+ backgroundColor: theme.color.bg
809
+ },
810
+ header: {
811
+ flexDirection: "row",
812
+ alignItems: "center",
813
+ gap: theme.space.s3,
814
+ paddingHorizontal: theme.space[12],
815
+ paddingVertical: theme.space[10],
816
+ backgroundColor: theme.color.surface,
817
+ borderBottomWidth: theme.borderWidth.base,
818
+ borderBottomColor: theme.color.border
819
+ },
820
+ headerText: {
821
+ flex: 1
822
+ },
823
+ title: {
824
+ fontFamily: theme.font.sans,
825
+ fontWeight: theme.type.headline.fontWeight,
826
+ // The theme already resolved the platform's headline metrics, so there is no
827
+ // `platform` prop here and no `Platform.select`.
828
+ fontSize: theme.type.headline.fontSize,
829
+ lineHeight: theme.type.headline.lineHeight,
830
+ letterSpacing: theme.type.headline.letterSpacing,
831
+ color: theme.color.text
832
+ },
833
+ headerSub: {
834
+ fontFamily: theme.font.mono,
835
+ fontSize: theme.fontSize[11],
836
+ color: theme.color.text3
837
+ },
838
+ scroll: {
839
+ flex: 1
840
+ },
841
+ scrollContent: {
842
+ paddingBottom: theme.space.s3
843
+ },
844
+ footer: {
845
+ gap: theme.space.s2,
846
+ paddingHorizontal: theme.space[12],
847
+ paddingTop: theme.space[12],
848
+ backgroundColor: theme.color.surface,
849
+ borderTopWidth: theme.borderWidth.base,
850
+ borderTopColor: theme.color.border
851
+ },
852
+ footerNote: {
853
+ fontFamily: theme.font.sans,
854
+ fontSize: theme.fontSize[11],
855
+ lineHeight: theme.fontSize[11] * theme.lineHeight.snug,
856
+ color: theme.color.text3
857
+ }
858
+ }));
859
+
860
+ export { FLOW_RUN_STATE_ICON, FLOW_TONE_BADGE, FlowApprovalSheet, FlowStepList, FlowStepRow, FlowStepSheet, flowIconName };