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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/LICENSE +21 -0
  2. package/dist/accordion/index.js +3 -0
  3. package/dist/adaptive/index.js +2 -0
  4. package/dist/alert/index.js +3 -0
  5. package/dist/analyzer/index.js +6 -0
  6. package/dist/announcement/index.js +6 -0
  7. package/dist/audio-player/index.js +3 -0
  8. package/dist/avatar/index.js +3 -0
  9. package/dist/avatar-group/index.js +3 -0
  10. package/dist/badge/index.js +5 -0
  11. package/dist/banner/index.js +2 -0
  12. package/dist/board/index.js +7 -0
  13. package/dist/button/index.js +5 -0
  14. package/dist/camera-permission/index.js +13 -0
  15. package/dist/capture-result/index.js +18 -0
  16. package/dist/card/index.js +4 -0
  17. package/dist/card-form/index.js +10 -0
  18. package/dist/carousel/index.js +2 -0
  19. package/dist/chart/index.js +6 -0
  20. package/dist/charts/index.js +7 -0
  21. package/dist/checkbox/index.js +7 -0
  22. package/dist/checklist/index.js +10 -0
  23. package/dist/checkout/index.js +13 -0
  24. package/dist/chip/index.js +7 -0
  25. package/dist/chunk-223Q2T2Q.js +229 -0
  26. package/dist/chunk-2A5NIQAK.js +254 -0
  27. package/dist/chunk-2GK6PHGE.js +363 -0
  28. package/dist/chunk-2WUTXHMU.js +1 -0
  29. package/dist/chunk-2ZZ7TDJ4.js +324 -0
  30. package/dist/chunk-35OFI3JG.js +499 -0
  31. package/dist/chunk-3ARE4TES.js +195 -0
  32. package/dist/chunk-3ECPOSKO.js +1 -0
  33. package/dist/chunk-3ENTMPQY.js +229 -0
  34. package/dist/chunk-3HJH6FF4.js +98 -0
  35. package/dist/chunk-3NMD74ZU.js +4 -0
  36. package/dist/chunk-3WPW4KUN.js +182 -0
  37. package/dist/chunk-47FWHGUN.js +394 -0
  38. package/dist/chunk-4BXMXBJO.js +141 -0
  39. package/dist/chunk-4DS5ZWVC.js +83 -0
  40. package/dist/chunk-4GBOGOTV.js +295 -0
  41. package/dist/chunk-4SZYY6AN.js +99 -0
  42. package/dist/chunk-4YIP3CWS.js +237 -0
  43. package/dist/chunk-4YQOR7JM.js +204 -0
  44. package/dist/chunk-4ZAHCY44.js +177 -0
  45. package/dist/chunk-52X2VYTD.js +228 -0
  46. package/dist/chunk-5P26LBDL.js +1 -0
  47. package/dist/chunk-5XLRYDAX.js +1 -0
  48. package/dist/chunk-5YNTNN5A.js +177 -0
  49. package/dist/chunk-66SG2H23.js +129 -0
  50. package/dist/chunk-6HT2LP62.js +504 -0
  51. package/dist/chunk-6N33LFQA.js +35 -0
  52. package/dist/chunk-6X6PQ443.js +432 -0
  53. package/dist/chunk-7CFF4HXS.js +126 -0
  54. package/dist/chunk-7O2FMUPT.js +755 -0
  55. package/dist/chunk-AI4DWZCD.js +162 -0
  56. package/dist/chunk-AWJOCGFZ.js +213 -0
  57. package/dist/chunk-AZRX6SAC.js +285 -0
  58. package/dist/chunk-B54QE2FN.js +1 -0
  59. package/dist/chunk-BC475SJH.js +1 -0
  60. package/dist/chunk-BEDBFJND.js +202 -0
  61. package/dist/chunk-BTTFCMKG.js +166 -0
  62. package/dist/chunk-BV3B2HYZ.js +1635 -0
  63. package/dist/chunk-C2NTXVWM.js +98 -0
  64. package/dist/chunk-CDRZHT42.js +424 -0
  65. package/dist/chunk-CJ5EOYZE.js +62 -0
  66. package/dist/chunk-CUMUNPXY.js +128 -0
  67. package/dist/chunk-CUS3ZSCU.js +1 -0
  68. package/dist/chunk-CYRBHQQZ.js +411 -0
  69. package/dist/chunk-DHWADYZX.js +144 -0
  70. package/dist/chunk-DKCSPATL.js +1 -0
  71. package/dist/chunk-DM5QUKKO.js +326 -0
  72. package/dist/chunk-DSJBXLUG.js +845 -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-FIF2M24N.js +1521 -0
  80. package/dist/chunk-FOKG57CR.js +993 -0
  81. package/dist/chunk-G3HOYSF7.js +1 -0
  82. package/dist/chunk-GDKZTW34.js +395 -0
  83. package/dist/chunk-GL7B2DOW.js +134 -0
  84. package/dist/chunk-GNNJ4GCC.js +471 -0
  85. package/dist/chunk-GNZ56EUI.js +1 -0
  86. package/dist/chunk-H6NIOQHK.js +346 -0
  87. package/dist/chunk-H6PC7RDA.js +1 -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-IIQTAY3J.js +715 -0
  92. package/dist/chunk-ITTYJZWX.js +271 -0
  93. package/dist/chunk-IVNRBPGC.js +1018 -0
  94. package/dist/chunk-J4KLDGI4.js +1 -0
  95. package/dist/chunk-J7Q7VCVC.js +254 -0
  96. package/dist/chunk-JDEOITQ2.js +1 -0
  97. package/dist/chunk-JNH2TYIN.js +96 -0
  98. package/dist/chunk-JRLTGLN4.js +1 -0
  99. package/dist/chunk-JTRJJLKL.js +1 -0
  100. package/dist/chunk-JUAMLEHX.js +379 -0
  101. package/dist/chunk-JXJB2X6M.js +131 -0
  102. package/dist/chunk-KMI5ML5I.js +262 -0
  103. package/dist/chunk-KTAC4MGE.js +4 -0
  104. package/dist/chunk-LAECSR4H.js +178 -0
  105. package/dist/chunk-LK4BCSGX.js +1 -0
  106. package/dist/chunk-LOE5YNN3.js +470 -0
  107. package/dist/chunk-LRJNDEIA.js +302 -0
  108. package/dist/chunk-LSS54GLJ.js +116 -0
  109. package/dist/chunk-LZLHELAG.js +137 -0
  110. package/dist/chunk-M2LUXGKZ.js +1 -0
  111. package/dist/chunk-MOUJOP55.js +425 -0
  112. package/dist/chunk-N32RGOA5.js +159 -0
  113. package/dist/chunk-N5ZNE2YE.js +1 -0
  114. package/dist/chunk-NBNCBML6.js +1 -0
  115. package/dist/chunk-NKB7BZYK.js +167 -0
  116. package/dist/chunk-NQYBUO3K.js +1795 -0
  117. package/dist/chunk-NY2U3PBI.js +59 -0
  118. package/dist/chunk-O4AEHWII.js +464 -0
  119. package/dist/chunk-O7AE6DAF.js +146 -0
  120. package/dist/chunk-OETCUXQP.js +134 -0
  121. package/dist/chunk-OOPPQH27.js +179 -0
  122. package/dist/chunk-OPXFZ4Y5.js +204 -0
  123. package/dist/chunk-P23EQNRQ.js +338 -0
  124. package/dist/chunk-PJXUJYS6.js +248 -0
  125. package/dist/chunk-PNWUWOBF.js +1 -0
  126. package/dist/chunk-PUPM2YGF.js +376 -0
  127. package/dist/chunk-PZXZJBMP.js +620 -0
  128. package/dist/chunk-Q72LJOVE.js +169 -0
  129. package/dist/chunk-QCDXZBC5.js +247 -0
  130. package/dist/chunk-QDYDBCFP.js +197 -0
  131. package/dist/chunk-QJJ6MADV.js +274 -0
  132. package/dist/chunk-QKXCPTFS.js +349 -0
  133. package/dist/chunk-QWCMU5B2.js +860 -0
  134. package/dist/chunk-RGQWWKLA.js +634 -0
  135. package/dist/chunk-RIBDXGUG.js +108 -0
  136. package/dist/chunk-RJQOOHT2.js +214 -0
  137. package/dist/chunk-RNGLIHFA.js +191 -0
  138. package/dist/chunk-RQ3HASCC.js +6 -0
  139. package/dist/chunk-RSOJT5YW.js +124 -0
  140. package/dist/chunk-RTIKSY6A.js +1 -0
  141. package/dist/chunk-RUZHTGKB.js +237 -0
  142. package/dist/chunk-RW6ZL2FQ.js +284 -0
  143. package/dist/chunk-S7F6XLTK.js +540 -0
  144. package/dist/chunk-SBMNWWBV.js +155 -0
  145. package/dist/chunk-SDTQPRRB.js +1 -0
  146. package/dist/chunk-SYNOJOQO.js +377 -0
  147. package/dist/chunk-T753XT36.js +1 -0
  148. package/dist/chunk-TKQYWZ5V.js +196 -0
  149. package/dist/chunk-TKVFVF5D.js +95 -0
  150. package/dist/chunk-TOXAGRDQ.js +144 -0
  151. package/dist/chunk-TUTI5HOZ.js +112 -0
  152. package/dist/chunk-U7TFM2JA.js +140 -0
  153. package/dist/chunk-UC2WGUP3.js +627 -0
  154. package/dist/chunk-UWFLYMAR.js +1126 -0
  155. package/dist/chunk-UWSZB7BJ.js +1 -0
  156. package/dist/chunk-UYG5L34B.js +87 -0
  157. package/dist/chunk-VBOXAEPI.js +336 -0
  158. package/dist/chunk-VCDBXW5H.js +188 -0
  159. package/dist/chunk-VCXPHHDS.js +1 -0
  160. package/dist/chunk-VEAYTRPX.js +414 -0
  161. package/dist/chunk-VFCUIDRT.js +1 -0
  162. package/dist/chunk-VQHPQEUH.js +273 -0
  163. package/dist/chunk-VXDZFJGP.js +874 -0
  164. package/dist/chunk-WS56BL3D.js +1 -0
  165. package/dist/chunk-WSW6ZFAQ.js +98 -0
  166. package/dist/chunk-WVKKJA6U.js +870 -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-Z7H7VSFZ.js +323 -0
  181. package/dist/chunk-ZK2H4O5P.js +1 -0
  182. package/dist/chunk-ZVFE5QGU.js +524 -0
  183. package/dist/coachmark/index.js +4 -0
  184. package/dist/code-block/index.js +4 -0
  185. package/dist/color-field/index.js +7 -0
  186. package/dist/commerce/index.js +20 -0
  187. package/dist/connectivity/index.js +2 -0
  188. package/dist/context-menu/index.js +5 -0
  189. package/dist/copy-button/index.js +3 -0
  190. package/dist/data-grid/index.js +24 -0
  191. package/dist/date-range-picker/index.js +13 -0
  192. package/dist/description-list/index.js +2 -0
  193. package/dist/dialog/index.js +3 -0
  194. package/dist/empty-state/index.js +3 -0
  195. package/dist/error-summary/index.js +3 -0
  196. package/dist/fab/index.js +2 -0
  197. package/dist/file-upload/index.js +9 -0
  198. package/dist/filter-bar/index.js +8 -0
  199. package/dist/flow-run/index.js +14 -0
  200. package/dist/form/index.js +3 -0
  201. package/dist/gallery/index.js +2 -0
  202. package/dist/header/index.js +5 -0
  203. package/dist/hold-to-confirm/index.js +4 -0
  204. package/dist/index.d.ts +22883 -0
  205. package/dist/index.js +158 -0
  206. package/dist/infinite-list/index.js +2 -0
  207. package/dist/inline-edit/index.js +5 -0
  208. package/dist/input/index.js +5 -0
  209. package/dist/interactions/index.js +2 -0
  210. package/dist/invoice/index.js +10 -0
  211. package/dist/kbd/index.js +1 -0
  212. package/dist/keyboard/index.js +3 -0
  213. package/dist/list-row/index.js +7 -0
  214. package/dist/log-viewer/index.js +2 -0
  215. package/dist/map-view/index.js +3 -0
  216. package/dist/markdown/index.js +6 -0
  217. package/dist/metric/index.js +4 -0
  218. package/dist/money/index.js +3 -0
  219. package/dist/nav-drawer/index.js +2 -0
  220. package/dist/navigation/index.js +2 -0
  221. package/dist/notification-center/index.js +16 -0
  222. package/dist/number-roll/index.js +3 -0
  223. package/dist/one-handed/index.js +5 -0
  224. package/dist/os-surfaces/index.js +3 -0
  225. package/dist/otp/index.js +7 -0
  226. package/dist/page-header/index.js +1 -0
  227. package/dist/payment-method/index.js +12 -0
  228. package/dist/payment-status/index.js +16 -0
  229. package/dist/permission/index.js +2 -0
  230. package/dist/picker/index.js +7 -0
  231. package/dist/progress/index.js +5 -0
  232. package/dist/pull-to-refresh/index.js +4 -0
  233. package/dist/radio-group/index.js +6 -0
  234. package/dist/rating/index.js +2 -0
  235. package/dist/receivables/index.js +20 -0
  236. package/dist/refund/index.js +16 -0
  237. package/dist/save-status/index.js +3 -0
  238. package/dist/scroll-area/index.js +1 -0
  239. package/dist/search-bar/index.js +5 -0
  240. package/dist/segmented-control/index.js +5 -0
  241. package/dist/sheet/index.js +4 -0
  242. package/dist/skeleton/index.js +2 -0
  243. package/dist/slider/index.js +5 -0
  244. package/dist/spinner/index.js +2 -0
  245. package/dist/split-button/index.js +7 -0
  246. package/dist/spotlight/index.js +2 -0
  247. package/dist/stage-timeline/index.js +4 -0
  248. package/dist/status-dot/index.js +2 -0
  249. package/dist/stepper/index.js +6 -0
  250. package/dist/streaming-text/index.js +3 -0
  251. package/dist/survey/index.js +19 -0
  252. package/dist/switch/index.js +5 -0
  253. package/dist/system-state/index.js +4 -0
  254. package/dist/tab-bar/index.js +2 -0
  255. package/dist/tabs/index.js +2 -0
  256. package/dist/textarea/index.js +6 -0
  257. package/dist/thinking/index.js +2 -0
  258. package/dist/timeline/index.js +4 -0
  259. package/dist/toast/index.js +2 -0
  260. package/dist/toolbar/index.js +2 -0
  261. package/dist/tour/index.js +11 -0
  262. package/dist/truncation-notice/index.js +2 -0
  263. package/dist/update-notice/index.js +11 -0
  264. package/dist/video-player/index.js +2 -0
  265. package/dist/viewfinder/index.js +5 -0
  266. package/dist/widget/index.js +4 -0
  267. package/dist/wizard/index.js +6 -0
  268. package/package.json +76 -3
  269. package/README.md +0 -3
@@ -0,0 +1,366 @@
1
+ import { StreamFade } from './chunk-WSW6ZFAQ.js';
2
+ import { CodeBlock } from './chunk-TOXAGRDQ.js';
3
+ import * as React from 'react';
4
+ import { View, Text, Linking } from 'react-native';
5
+ import { createStyleSheet, useStyles } from '@btndprojects/loam-theme-native';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+
8
+ // src/markdown/parse.ts
9
+ function safeHref(raw) {
10
+ const cleaned = raw.replace(/[\u0000-\u001F\u007F-\u009F]/g, "").trim();
11
+ if (cleaned === "") return null;
12
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(cleaned);
13
+ if (!scheme) return cleaned;
14
+ return /^(?:https?|mailto)$/i.test(scheme[1]) ? cleaned : null;
15
+ }
16
+ function parseInline(src) {
17
+ const nodes = [];
18
+ let buf = "";
19
+ let i = 0;
20
+ const flush = () => {
21
+ if (buf !== "") {
22
+ nodes.push({ type: "text", value: buf });
23
+ buf = "";
24
+ }
25
+ };
26
+ while (i < src.length) {
27
+ const c = src[i];
28
+ if (c === "`") {
29
+ const end = src.indexOf("`", i + 1);
30
+ if (end !== -1) {
31
+ flush();
32
+ nodes.push({ type: "code", value: src.slice(i + 1, end) });
33
+ i = end + 1;
34
+ continue;
35
+ }
36
+ }
37
+ if ((c === "*" || c === "_") && src[i + 1] === c) {
38
+ const delim = c + c;
39
+ const end = src.indexOf(delim, i + 2);
40
+ if (end > i + 2) {
41
+ flush();
42
+ nodes.push({ type: "strong", children: parseInline(src.slice(i + 2, end)) });
43
+ i = end + 2;
44
+ continue;
45
+ }
46
+ }
47
+ if (c === "*" || c === "_") {
48
+ const end = src.indexOf(c, i + 1);
49
+ if (end > i + 1) {
50
+ flush();
51
+ nodes.push({ type: "em", children: parseInline(src.slice(i + 1, end)) });
52
+ i = end + 1;
53
+ continue;
54
+ }
55
+ }
56
+ if (c === "[") {
57
+ const close = src.indexOf("]", i + 1);
58
+ if (close !== -1 && src[close + 1] === "(") {
59
+ const paren = src.indexOf(")", close + 2);
60
+ if (paren !== -1) {
61
+ flush();
62
+ nodes.push({
63
+ type: "link",
64
+ href: src.slice(close + 2, paren).trim(),
65
+ children: parseInline(src.slice(i + 1, close))
66
+ });
67
+ i = paren + 1;
68
+ continue;
69
+ }
70
+ }
71
+ }
72
+ buf += c;
73
+ i += 1;
74
+ }
75
+ flush();
76
+ return nodes;
77
+ }
78
+ function linesToInline(lines) {
79
+ const out = [];
80
+ lines.forEach((line, idx) => {
81
+ const hard = /\s{2,}$/.test(line);
82
+ out.push(...parseInline(line.trim()));
83
+ if (idx < lines.length - 1) out.push(hard ? { type: "br" } : { type: "text", value: " " });
84
+ });
85
+ return out;
86
+ }
87
+ var HEADING = /^ {0,3}(#{1,6})\s+(.*?)(?:\s+#+)?\s*$/;
88
+ var FENCE = /^ {0,3}(```|~~~)\s*([\w+-]*)\s*$/;
89
+ var HR = /^ {0,3}(?:-{3,}|\*{3,}|_{3,})\s*$/;
90
+ var UL = /^ {0,3}[-*+]\s+(.*)$/;
91
+ var OL = /^ {0,3}(\d{1,9})[.)]\s+(.*)$/;
92
+ var QUOTE = /^ {0,3}>\s?(.*)$/;
93
+ function parseMarkdown(content) {
94
+ const lines = content.replace(/\r\n?/g, "\n").split("\n");
95
+ const blocks = [];
96
+ let i = 0;
97
+ const isBlank = (s) => s.trim() === "";
98
+ const startsBlock = (s) => HEADING.test(s) || FENCE.test(s) || HR.test(s) || UL.test(s) || OL.test(s) || QUOTE.test(s);
99
+ while (i < lines.length) {
100
+ const line = lines[i];
101
+ if (isBlank(line)) {
102
+ i += 1;
103
+ continue;
104
+ }
105
+ const fence = FENCE.exec(line);
106
+ if (fence) {
107
+ const marker = fence[1];
108
+ const lang = fence[2] ? fence[2] : null;
109
+ const body = [];
110
+ i += 1;
111
+ while (i < lines.length && !new RegExp(`^ {0,3}${marker}\\s*$`).test(lines[i])) {
112
+ body.push(lines[i]);
113
+ i += 1;
114
+ }
115
+ if (i < lines.length) i += 1;
116
+ blocks.push({ type: "code", lang, value: body.join("\n") });
117
+ continue;
118
+ }
119
+ const heading = HEADING.exec(line);
120
+ if (heading) {
121
+ blocks.push({
122
+ type: "heading",
123
+ level: heading[1].length,
124
+ children: parseInline(heading[2].trim())
125
+ });
126
+ i += 1;
127
+ continue;
128
+ }
129
+ if (HR.test(line)) {
130
+ blocks.push({ type: "hr" });
131
+ i += 1;
132
+ continue;
133
+ }
134
+ if (QUOTE.test(line)) {
135
+ const quote = [];
136
+ while (i < lines.length && QUOTE.test(lines[i])) {
137
+ quote.push(QUOTE.exec(lines[i])[1]);
138
+ i += 1;
139
+ }
140
+ blocks.push({ type: "blockquote", children: linesToInline(quote) });
141
+ continue;
142
+ }
143
+ const ol = OL.exec(line);
144
+ const ul = UL.exec(line);
145
+ if (ol || ul) {
146
+ const ordered = Boolean(ol);
147
+ const start = ol ? Number(ol[1]) : 1;
148
+ const items = [];
149
+ while (i < lines.length) {
150
+ const m = ordered ? OL.exec(lines[i]) : UL.exec(lines[i]);
151
+ if (!m) break;
152
+ items.push(parseInline((ordered ? m[2] : m[1]).trim()));
153
+ i += 1;
154
+ }
155
+ blocks.push({ type: "list", ordered, start, items });
156
+ continue;
157
+ }
158
+ const para = [];
159
+ while (i < lines.length && !isBlank(lines[i]) && !startsBlock(lines[i])) {
160
+ para.push(lines[i]);
161
+ i += 1;
162
+ }
163
+ blocks.push({ type: "paragraph", children: linesToInline(para) });
164
+ }
165
+ return blocks;
166
+ }
167
+ var HEADING_ROLE = {
168
+ 1: "largeTitle",
169
+ 2: "title1",
170
+ 3: "title2",
171
+ 4: "title3",
172
+ 5: "headline",
173
+ 6: "subheadline"
174
+ };
175
+ function useInlineRenderer() {
176
+ const { styles } = useStyles(sheet);
177
+ const render = React.useCallback(
178
+ (nodes, keyPrefix) => nodes.map((node, i) => {
179
+ const key = `${keyPrefix}-${i}`;
180
+ switch (node.type) {
181
+ case "text":
182
+ return /* @__PURE__ */ jsx(Text, { children: node.value }, key);
183
+ case "br":
184
+ return /* @__PURE__ */ jsx(Text, { children: "\n" }, key);
185
+ case "strong":
186
+ return /* @__PURE__ */ jsx(Text, { style: styles.strong, children: render(node.children, key) }, key);
187
+ case "em":
188
+ return /* @__PURE__ */ jsx(Text, { style: styles.em, children: render(node.children, key) }, key);
189
+ case "code":
190
+ return /* @__PURE__ */ jsx(Text, { style: styles.inlineCode, children: node.value }, key);
191
+ case "link": {
192
+ const href = safeHref(node.href);
193
+ if (href === null) {
194
+ return /* @__PURE__ */ jsx(Text, { children: render(node.children, key) }, key);
195
+ }
196
+ return /* @__PURE__ */ jsx(
197
+ Text,
198
+ {
199
+ style: styles.link,
200
+ accessibilityRole: "link",
201
+ onPress: () => {
202
+ void Linking.openURL(href);
203
+ },
204
+ children: render(node.children, key)
205
+ },
206
+ key
207
+ );
208
+ }
209
+ }
210
+ }),
211
+ [styles]
212
+ );
213
+ return render;
214
+ }
215
+ function Markdown({
216
+ content,
217
+ streaming = false,
218
+ motion = "none"
219
+ }) {
220
+ const { styles } = useStyles(sheet);
221
+ const renderInline = useInlineRenderer();
222
+ const blocks = React.useMemo(() => parseMarkdown(content), [content]);
223
+ const animate = streaming && motion === "full";
224
+ const prevCount = React.useRef(0);
225
+ const firstRender = React.useRef(true);
226
+ const baseline = firstRender.current ? Number.POSITIVE_INFINITY : prevCount.current;
227
+ React.useEffect(() => {
228
+ prevCount.current = blocks.length;
229
+ firstRender.current = false;
230
+ });
231
+ const renderBlock = (block, index) => {
232
+ switch (block.type) {
233
+ case "heading":
234
+ return /* @__PURE__ */ jsx(
235
+ Text,
236
+ {
237
+ accessibilityRole: "header",
238
+ style: [styles.heading, styles[`h${block.level}`]],
239
+ children: renderInline(block.children, `h${index}`)
240
+ }
241
+ );
242
+ case "paragraph":
243
+ return /* @__PURE__ */ jsx(Text, { style: styles.paragraph, children: renderInline(block.children, `p${index}`) });
244
+ case "hr":
245
+ return /* @__PURE__ */ jsx(View, { style: styles.hr, accessibilityRole: "none" });
246
+ case "code":
247
+ return /* @__PURE__ */ jsx(CodeBlock, { code: block.value, language: block.lang ?? void 0, showLineNumbers: false });
248
+ case "blockquote":
249
+ return /* @__PURE__ */ jsxs(View, { style: styles.blockquote, children: [
250
+ /* @__PURE__ */ jsx(View, { style: styles.blockquoteBar }),
251
+ /* @__PURE__ */ jsx(Text, { style: styles.blockquoteText, children: renderInline(block.children, `q${index}`) })
252
+ ] });
253
+ case "list":
254
+ return /* @__PURE__ */ jsx(View, { style: styles.list, children: block.items.map((item, j) => /* @__PURE__ */ jsxs(View, { style: styles.listItem, children: [
255
+ /* @__PURE__ */ jsx(Text, { style: styles.marker, children: block.ordered ? `${block.start + j}.` : "\u2022" }),
256
+ /* @__PURE__ */ jsx(Text, { style: styles.listItemText, children: renderInline(item, `l${index}-${j}`) })
257
+ ] }, j)) });
258
+ }
259
+ };
260
+ return /* @__PURE__ */ jsx(View, { style: styles.root, children: blocks.map((block, i) => {
261
+ const el = renderBlock(block, i);
262
+ if (animate && i >= baseline) {
263
+ return /* @__PURE__ */ jsx(StreamFade, { children: el }, i);
264
+ }
265
+ return /* @__PURE__ */ jsx(React.Fragment, { children: el }, i);
266
+ }) });
267
+ }
268
+ var sheet = createStyleSheet((theme) => ({
269
+ root: { gap: theme.space.s3 },
270
+ // Headings: the mobile type ramp carries the level; ink stays full.
271
+ heading: {
272
+ fontFamily: theme.font.display,
273
+ fontWeight: theme.font.displayWeight,
274
+ color: theme.color.text
275
+ },
276
+ h1: {
277
+ fontSize: theme.type[HEADING_ROLE[1]].fontSize,
278
+ lineHeight: theme.type[HEADING_ROLE[1]].lineHeight,
279
+ letterSpacing: theme.type[HEADING_ROLE[1]].letterSpacing
280
+ },
281
+ h2: {
282
+ fontSize: theme.type[HEADING_ROLE[2]].fontSize,
283
+ lineHeight: theme.type[HEADING_ROLE[2]].lineHeight,
284
+ letterSpacing: theme.type[HEADING_ROLE[2]].letterSpacing
285
+ },
286
+ h3: {
287
+ fontSize: theme.type[HEADING_ROLE[3]].fontSize,
288
+ lineHeight: theme.type[HEADING_ROLE[3]].lineHeight,
289
+ letterSpacing: theme.type[HEADING_ROLE[3]].letterSpacing
290
+ },
291
+ h4: {
292
+ fontSize: theme.type[HEADING_ROLE[4]].fontSize,
293
+ lineHeight: theme.type[HEADING_ROLE[4]].lineHeight,
294
+ letterSpacing: theme.type[HEADING_ROLE[4]].letterSpacing
295
+ },
296
+ h5: {
297
+ fontSize: theme.type[HEADING_ROLE[5]].fontSize,
298
+ lineHeight: theme.type[HEADING_ROLE[5]].lineHeight,
299
+ letterSpacing: theme.type[HEADING_ROLE[5]].letterSpacing
300
+ },
301
+ h6: {
302
+ fontSize: theme.type[HEADING_ROLE[6]].fontSize,
303
+ lineHeight: theme.type[HEADING_ROLE[6]].lineHeight,
304
+ letterSpacing: theme.type[HEADING_ROLE[6]].letterSpacing
305
+ },
306
+ // Body copy — secondary ink, the AA-safe muted foreground on a surface.
307
+ paragraph: {
308
+ fontFamily: theme.font.sans,
309
+ fontSize: theme.type.body.fontSize,
310
+ lineHeight: theme.type.body.lineHeight,
311
+ letterSpacing: theme.type.body.letterSpacing,
312
+ color: theme.color.text2
313
+ },
314
+ // Inline runs. Nested `Text` inherits the parent size, so these only add the
315
+ // treatment that distinguishes them.
316
+ strong: { fontWeight: theme.fontWeight.bold, color: theme.color.text },
317
+ em: { fontStyle: "italic" },
318
+ inlineCode: {
319
+ fontFamily: theme.font.mono,
320
+ fontSize: theme.type.footnote.fontSize,
321
+ color: theme.color.accentStrong,
322
+ backgroundColor: theme.color.surface2
323
+ },
324
+ // Links use accent-strong (AA against the surface) plus an underline, so the
325
+ // affordance survives greyscale — colour alone is not enough.
326
+ link: { color: theme.color.accentStrong, textDecorationLine: "underline" },
327
+ list: { gap: theme.space.s2 },
328
+ listItem: { flexDirection: "row", alignItems: "flex-start", gap: theme.space.s2 },
329
+ marker: {
330
+ fontFamily: theme.font.sans,
331
+ fontSize: theme.type.body.fontSize,
332
+ lineHeight: theme.type.body.lineHeight,
333
+ color: theme.color.text3,
334
+ minWidth: theme.space.s4
335
+ },
336
+ listItemText: {
337
+ flex: 1,
338
+ fontFamily: theme.font.sans,
339
+ fontSize: theme.type.body.fontSize,
340
+ lineHeight: theme.type.body.lineHeight,
341
+ letterSpacing: theme.type.body.letterSpacing,
342
+ color: theme.color.text2
343
+ },
344
+ // Blockquote — a leading accent bar (order mirrors under RTL for free) beside
345
+ // the quoted text.
346
+ blockquote: { flexDirection: "row", gap: theme.space.s3, alignItems: "stretch" },
347
+ blockquoteBar: {
348
+ width: theme.borderWidth.heavy,
349
+ backgroundColor: theme.color.accent,
350
+ borderRadius: theme.borderWidth.heavy
351
+ },
352
+ blockquoteText: {
353
+ flex: 1,
354
+ fontFamily: theme.font.display,
355
+ fontSize: theme.type.headline.fontSize,
356
+ lineHeight: theme.type.headline.lineHeight,
357
+ color: theme.color.text
358
+ },
359
+ hr: {
360
+ height: theme.borderWidth.base,
361
+ backgroundColor: theme.color.border,
362
+ marginVertical: theme.space.s2
363
+ }
364
+ }));
365
+
366
+ export { Markdown, parseInline, parseMarkdown, safeHref };
@@ -0,0 +1,223 @@
1
+ import { Spinner } from './chunk-O7AE6DAF.js';
2
+ import { haptics } from './chunk-NY2U3PBI.js';
3
+ import { useResolvedMotion } from './chunk-6N33LFQA.js';
4
+ import * as React from 'react';
5
+ import { Animated, Easing, View, Pressable, Platform } from 'react-native';
6
+ import { createStyleSheet, useLoamTheme, useStyles } from '@btndprojects/loam-theme-native';
7
+ import { jsx } from 'react/jsx-runtime';
8
+
9
+ var TRACK = {
10
+ ios: { sm: { width: 40, height: 24 }, md: { width: 52, height: 32 } },
11
+ // loam-allow-raw: ramp keys
12
+ android: { sm: { width: 40, height: 18 }, md: { width: 52, height: 22 } }
13
+ // loam-allow-raw: ramp keys
14
+ };
15
+ var IOS_PAD = 2;
16
+ var ANDROID_OVERHANG = 4;
17
+ var HEAVY_SHADOW_RATIO = 1.2;
18
+ function knobShadow(theme, os) {
19
+ if (os === "ios") return theme.shadow.knob;
20
+ return {
21
+ ...theme.shadow.knob,
22
+ shadowOffset: { width: 0, height: theme.space[2] },
23
+ shadowOpacity: theme.shadow.knob.shadowOpacity * HEAVY_SHADOW_RATIO,
24
+ shadowRadius: theme.space[6],
25
+ elevation: 3
26
+ // loam-allow-raw: Android depth between shadow.knob (2) and shadow.md (4).
27
+ };
28
+ }
29
+ function geometry(theme, os, size) {
30
+ const spec = TRACK[os][size];
31
+ const width = theme.space[spec.width];
32
+ const height = theme.space[spec.height];
33
+ const pad = theme.space[IOS_PAD];
34
+ if (os === "ios") {
35
+ const knob2 = height - 2 * pad;
36
+ return { width, height, pad, knob: knob2, travel: width - 2 * pad - knob2 };
37
+ }
38
+ const knob = height + theme.space[ANDROID_OVERHANG];
39
+ return { width, height, pad: 0, knob, travel: width - knob };
40
+ }
41
+ function useResolvedPlatform(explicit) {
42
+ const theme = useLoamTheme();
43
+ if (explicit) return explicit;
44
+ if (Platform.OS === "ios") return "ios";
45
+ if (Platform.OS === "android") return "android";
46
+ return theme.platform === "iOS" ? "ios" : "android";
47
+ }
48
+ function Switch({
49
+ value,
50
+ defaultValue = false,
51
+ onValueChange,
52
+ size = "md",
53
+ platform,
54
+ disabled = false,
55
+ pending = false,
56
+ motion = "full",
57
+ accessibilityLabel,
58
+ decorative = false
59
+ }) {
60
+ const isControlled = value !== void 0;
61
+ const [internal, setInternal] = React.useState(defaultValue);
62
+ const checked = isControlled ? value : internal;
63
+ const theme = useLoamTheme();
64
+ const os = useResolvedPlatform(platform);
65
+ const shape = `${os}-${size}`;
66
+ const { styles } = useStyles(sheet, { shape, disabled });
67
+ const { travel, width: trackW, height: trackH } = geometry(theme, os, size);
68
+ const slopX = Math.max(0, (theme.tapMin - trackW) / 2);
69
+ const slopY = Math.max(0, (theme.tapMin - trackH) / 2);
70
+ const resolved = useResolvedMotion(motion);
71
+ const tint = React.useRef(new Animated.Value(checked ? 1 : 0)).current;
72
+ const slide = React.useRef(new Animated.Value(checked ? 1 : 0)).current;
73
+ React.useEffect(() => {
74
+ const to = checked ? 1 : 0;
75
+ if (resolved === "none") {
76
+ tint.setValue(to);
77
+ } else {
78
+ Animated.timing(tint, {
79
+ toValue: to,
80
+ duration: theme.duration.base,
81
+ easing: Easing.bezier(...theme.easing.base),
82
+ // Colour interpolation cannot run on the native driver.
83
+ useNativeDriver: false
84
+ }).start();
85
+ }
86
+ if (resolved === "full") {
87
+ Animated.timing(slide, {
88
+ toValue: to,
89
+ duration: theme.duration.base,
90
+ easing: Easing.bezier(...theme.easing.spring),
91
+ useNativeDriver: true
92
+ }).start();
93
+ } else {
94
+ slide.setValue(to);
95
+ }
96
+ }, [checked, resolved, tint, slide, theme.duration.base, theme.easing.base, theme.easing.spring]);
97
+ const trackColor = tint.interpolate({
98
+ inputRange: [0, 1],
99
+ outputRange: [theme.color.surface3, os === "ios" ? theme.color.good : theme.color.accentSoft]
100
+ });
101
+ const knobColor = pending ? theme.color.knob : os === "ios" ? theme.color.knob : tint.interpolate({
102
+ inputRange: [0, 1],
103
+ outputRange: [theme.color.text3, theme.color.accent]
104
+ });
105
+ const translateX = slide.interpolate({
106
+ inputRange: [0, 1],
107
+ // The knob travels toward the end edge; only the sign of an X translation
108
+ // needs mirroring by hand.
109
+ outputRange: [0, theme.rtl ? -travel : travel]
110
+ });
111
+ const toggle = () => {
112
+ const next = !checked;
113
+ if (!isControlled) setInternal(next);
114
+ haptics.impact("medium");
115
+ onValueChange?.(next);
116
+ };
117
+ const visual = /* @__PURE__ */ jsx(Animated.View, { style: [styles.track, { backgroundColor: trackColor }], children: /* @__PURE__ */ jsx(Animated.View, { style: [styles.knobSlot, { transform: [{ translateX }] }], children: /* @__PURE__ */ jsx(
118
+ Animated.View,
119
+ {
120
+ testID: "switch-knob",
121
+ style: [styles.knob, pending && styles.knobBusy, { backgroundColor: knobColor }],
122
+ children: pending ? (
123
+ // Hidden from assistive tech — the switch's own `busy` state carries
124
+ // the meaning, so the nested progressbar is suppressed.
125
+ /* @__PURE__ */ jsx(
126
+ View,
127
+ {
128
+ testID: "switch-spinner",
129
+ style: styles.spinner,
130
+ "aria-hidden": true,
131
+ accessibilityElementsHidden: true,
132
+ importantForAccessibility: "no-hide-descendants",
133
+ children: /* @__PURE__ */ jsx(
134
+ Spinner,
135
+ {
136
+ size: "sm",
137
+ color: theme.color.accent,
138
+ motion,
139
+ accessibilityLabel: "Loading"
140
+ }
141
+ )
142
+ }
143
+ )
144
+ ) : null
145
+ }
146
+ ) }) });
147
+ if (decorative) {
148
+ return /* @__PURE__ */ jsx(View, { accessible: false, style: styles.decorative, children: visual });
149
+ }
150
+ return /* @__PURE__ */ jsx(
151
+ Pressable,
152
+ {
153
+ accessibilityRole: "switch",
154
+ accessibilityLabel,
155
+ accessibilityState: { checked, disabled, busy: pending },
156
+ "aria-checked": checked,
157
+ "aria-busy": pending || void 0,
158
+ disabled,
159
+ onPress: disabled || pending ? void 0 : toggle,
160
+ hitSlop: { top: slopY, bottom: slopY, left: slopX, right: slopX },
161
+ children: visual
162
+ }
163
+ );
164
+ }
165
+ function trackStyle(theme, os, size) {
166
+ const g = geometry(theme, os, size);
167
+ return { width: g.width, height: g.height, padding: g.pad };
168
+ }
169
+ function knobStyle(theme, os, size) {
170
+ const g = geometry(theme, os, size);
171
+ return { width: g.knob, height: g.knob, ...knobShadow(theme, os) };
172
+ }
173
+ var sheet = createStyleSheet((theme) => ({
174
+ // Decorative glyph wrapper: inert to touch so an owning ancestor keeps the press.
175
+ decorative: { pointerEvents: "none" },
176
+ track: {
177
+ justifyContent: "center",
178
+ borderRadius: theme.radius.full,
179
+ variants: {
180
+ shape: {
181
+ "ios-sm": trackStyle(theme, "ios", "sm"),
182
+ "ios-md": trackStyle(theme, "ios", "md"),
183
+ "android-sm": trackStyle(theme, "android", "sm"),
184
+ "android-md": trackStyle(theme, "android", "md")
185
+ },
186
+ disabled: {
187
+ true: { opacity: theme.state.disabledOpacity },
188
+ false: {}
189
+ }
190
+ }
191
+ },
192
+ // The Android knob overhangs its track, so it is centred out of flow.
193
+ knobSlot: {
194
+ justifyContent: "center",
195
+ variants: {
196
+ shape: {
197
+ "ios-sm": {},
198
+ "ios-md": {},
199
+ "android-sm": { position: "absolute", start: 0 },
200
+ "android-md": { position: "absolute", start: 0 }
201
+ },
202
+ disabled: { true: {}, false: {} }
203
+ }
204
+ },
205
+ // Centre the pending spinner inside the knob disc.
206
+ knobBusy: { alignItems: "center", justifyContent: "center" },
207
+ // The spinner is decorative — inert to touch so the knob keeps the press.
208
+ spinner: { pointerEvents: "none" },
209
+ knob: {
210
+ borderRadius: theme.radius.full,
211
+ variants: {
212
+ shape: {
213
+ "ios-sm": knobStyle(theme, "ios", "sm"),
214
+ "ios-md": knobStyle(theme, "ios", "md"),
215
+ "android-sm": knobStyle(theme, "android", "sm"),
216
+ "android-md": knobStyle(theme, "android", "md")
217
+ },
218
+ disabled: { true: {}, false: {} }
219
+ }
220
+ }
221
+ }));
222
+
223
+ export { Switch };
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,37 @@
1
+ // src/progress/node-model.ts
2
+ var NODE_STATE_ICON = {
3
+ working: "loader",
4
+ waiting: "clock",
5
+ done: "check",
6
+ crashed: "alert-triangle",
7
+ conflict: "alert-circle",
8
+ pending: "circle"
9
+ };
10
+ var NODE_STATE_WORD = {
11
+ working: "working",
12
+ waiting: "waiting",
13
+ done: "done",
14
+ crashed: "crashed",
15
+ conflict: "conflict",
16
+ pending: "pending"
17
+ };
18
+ var NODE_STATE_SHAPE = {
19
+ working: "round",
20
+ done: "round",
21
+ pending: "round",
22
+ waiting: "square",
23
+ crashed: "square",
24
+ conflict: "square"
25
+ };
26
+ function isConnectorTraversed(state) {
27
+ return state === "done";
28
+ }
29
+ function resolveStepState(index, current, states) {
30
+ const override = states?.[index];
31
+ if (override) return override;
32
+ if (index < current) return "done";
33
+ if (index === current) return "working";
34
+ return "pending";
35
+ }
36
+
37
+ export { NODE_STATE_ICON, NODE_STATE_SHAPE, NODE_STATE_WORD, isConnectorTraversed, resolveStepState };
@@ -0,0 +1 @@
1
+