@lt-three/love3 0.0.0 → 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 (377) hide show
  1. package/README.md +85 -1
  2. package/dist/native/analytics/animation.d.ts +4 -0
  3. package/dist/native/analytics/animation.js +6 -0
  4. package/dist/native/analytics/chart.types.d.ts +25 -0
  5. package/dist/native/analytics/chart.types.js +0 -0
  6. package/dist/native/analytics/line-chart.d.ts +4 -0
  7. package/dist/native/analytics/line-chart.ios.d.ts +4 -0
  8. package/dist/native/analytics/line-chart.ios.js +24 -0
  9. package/dist/native/analytics/line-chart.js +33 -0
  10. package/dist/native/analytics/metric-card.d.ts +10 -0
  11. package/dist/native/analytics/metric-card.js +29 -0
  12. package/dist/native/analytics/multi-line-chart.d.ts +18 -0
  13. package/dist/native/analytics/multi-line-chart.js +216 -0
  14. package/dist/native/analytics/pie-chart.d.ts +15 -0
  15. package/dist/native/analytics/pie-chart.ios.d.ts +4 -0
  16. package/dist/native/analytics/pie-chart.ios.js +24 -0
  17. package/dist/native/analytics/pie-chart.js +92 -0
  18. package/dist/native/analytics/single-number.d.ts +19 -0
  19. package/dist/native/analytics/single-number.js +101 -0
  20. package/dist/native/atom/avatar.d.ts +21 -0
  21. package/dist/native/atom/avatar.js +46 -0
  22. package/dist/native/atom/badge.d.ts +28 -0
  23. package/dist/native/atom/badge.js +51 -0
  24. package/dist/native/atom/button.d.ts +46 -0
  25. package/dist/native/atom/button.js +109 -0
  26. package/dist/native/atom/checkbox.d.ts +21 -0
  27. package/dist/native/atom/checkbox.js +47 -0
  28. package/dist/native/atom/colored-value.d.ts +12 -0
  29. package/dist/native/atom/colored-value.js +24 -0
  30. package/dist/native/atom/image.d.ts +21 -0
  31. package/dist/native/atom/image.js +72 -0
  32. package/dist/native/atom/label.d.ts +18 -0
  33. package/dist/native/atom/label.js +33 -0
  34. package/dist/native/atom/link.d.ts +18 -0
  35. package/dist/native/atom/link.js +25 -0
  36. package/dist/native/atom/readout.d.ts +22 -0
  37. package/dist/native/atom/readout.js +39 -0
  38. package/dist/native/atom/search-input.d.ts +12 -0
  39. package/dist/native/atom/search-input.js +36 -0
  40. package/dist/native/atom/select.d.ts +54 -0
  41. package/dist/native/atom/select.js +200 -0
  42. package/dist/native/atom/separator.d.ts +12 -0
  43. package/dist/native/atom/separator.js +16 -0
  44. package/dist/native/atom/skeleton.d.ts +12 -0
  45. package/dist/native/atom/skeleton.js +39 -0
  46. package/dist/native/atom/slider.d.ts +32 -0
  47. package/dist/native/atom/slider.js +75 -0
  48. package/dist/native/atom/spinner.d.ts +15 -0
  49. package/dist/native/atom/spinner.js +25 -0
  50. package/dist/native/atom/switch.d.ts +18 -0
  51. package/dist/native/atom/switch.js +52 -0
  52. package/dist/native/atom/symbol.d.ts +16 -0
  53. package/dist/native/atom/symbol.js +38 -0
  54. package/dist/native/atom/symbol.types.d.ts +25 -0
  55. package/dist/native/atom/symbol.types.js +49 -0
  56. package/dist/native/atom/text-field.d.ts +49 -0
  57. package/dist/native/atom/text-field.js +56 -0
  58. package/dist/native/atom/text.d.ts +2 -0
  59. package/dist/native/atom/text.js +3 -0
  60. package/dist/native/atom/theme-toggle.d.ts +21 -0
  61. package/dist/native/atom/theme-toggle.js +36 -0
  62. package/dist/native/atom/timezone-select.d.ts +16 -0
  63. package/dist/native/atom/timezone-select.js +28 -0
  64. package/dist/native/atom/typography.d.ts +13 -0
  65. package/dist/native/atom/typography.js +28 -0
  66. package/dist/native/base/button.d.ts +61 -0
  67. package/dist/native/base/button.js +92 -0
  68. package/dist/native/base/form.d.ts +72 -0
  69. package/dist/native/base/form.js +113 -0
  70. package/dist/native/base/glass-card.d.ts +15 -0
  71. package/dist/native/base/glass-card.js +38 -0
  72. package/dist/native/base/input.d.ts +29 -0
  73. package/dist/native/base/input.js +27 -0
  74. package/dist/native/base/sheet.d.ts +71 -0
  75. package/dist/native/base/sheet.js +187 -0
  76. package/dist/native/base/text.d.ts +14 -0
  77. package/dist/native/base/text.js +53 -0
  78. package/dist/native/form/checkbox.d.ts +13 -0
  79. package/dist/native/form/checkbox.js +55 -0
  80. package/dist/native/form/date-picker.d.ts +23 -0
  81. package/dist/native/form/date-picker.js +119 -0
  82. package/dist/native/form/form.d.ts +22 -0
  83. package/dist/native/form/form.js +44 -0
  84. package/dist/native/form/radio-group.d.ts +23 -0
  85. package/dist/native/form/radio-group.js +88 -0
  86. package/dist/native/form/select.d.ts +13 -0
  87. package/dist/native/form/select.js +45 -0
  88. package/dist/native/form/slider.d.ts +14 -0
  89. package/dist/native/form/slider.js +42 -0
  90. package/dist/native/form/switch.d.ts +9 -0
  91. package/dist/native/form/switch.js +59 -0
  92. package/dist/native/form/text-area.d.ts +11 -0
  93. package/dist/native/form/text-area.js +50 -0
  94. package/dist/native/form/text-input.d.ts +18 -0
  95. package/dist/native/form/text-input.js +90 -0
  96. package/dist/native/index.d.ts +1 -0
  97. package/dist/native/index.js +0 -0
  98. package/dist/native/layout/accordion.d.ts +25 -0
  99. package/dist/native/layout/accordion.js +54 -0
  100. package/dist/native/layout/card.d.ts +47 -0
  101. package/dist/native/layout/card.js +57 -0
  102. package/dist/native/layout/description.d.ts +16 -0
  103. package/dist/native/layout/description.js +32 -0
  104. package/dist/native/layout/error.d.ts +21 -0
  105. package/dist/native/layout/error.js +44 -0
  106. package/dist/native/layout/information.d.ts +25 -0
  107. package/dist/native/layout/information.js +35 -0
  108. package/dist/native/layout/locked.d.ts +38 -0
  109. package/dist/native/layout/locked.js +94 -0
  110. package/dist/native/layout/modal.d.ts +25 -0
  111. package/dist/native/layout/modal.js +93 -0
  112. package/dist/native/layout/not-found.d.ts +17 -0
  113. package/dist/native/layout/not-found.js +30 -0
  114. package/dist/native/layout/page-frame.d.ts +23 -0
  115. package/dist/native/layout/page-frame.js +46 -0
  116. package/dist/native/layout/panel.d.ts +18 -0
  117. package/dist/native/layout/panel.js +23 -0
  118. package/dist/native/layout/reorderable-list.d.ts +42 -0
  119. package/dist/native/layout/reorderable-list.js +52 -0
  120. package/dist/native/layout/sheet.d.ts +30 -0
  121. package/dist/native/layout/sheet.js +46 -0
  122. package/dist/native/layout/simple-dialog.d.ts +16 -0
  123. package/dist/native/layout/simple-dialog.js +20 -0
  124. package/dist/native/layout/simple-table.d.ts +50 -0
  125. package/dist/native/layout/simple-table.js +75 -0
  126. package/dist/native/layout/tab-bar.d.ts +33 -0
  127. package/dist/native/layout/tab-bar.js +48 -0
  128. package/dist/native/layout/tabs.d.ts +28 -0
  129. package/dist/native/layout/tabs.js +54 -0
  130. package/dist/native/layout/tuning-panel.d.ts +24 -0
  131. package/dist/native/layout/tuning-panel.js +246 -0
  132. package/dist/native/lib/autocomplete.d.ts +7 -0
  133. package/dist/native/lib/autocomplete.js +34 -0
  134. package/dist/native/lib/breakpoints.d.ts +14 -0
  135. package/dist/native/lib/breakpoints.js +17 -0
  136. package/dist/native/lib/chart-palette.d.ts +8 -0
  137. package/dist/native/lib/chart-palette.js +20 -0
  138. package/dist/native/lib/confirm.d.ts +48 -0
  139. package/dist/native/lib/confirm.js +69 -0
  140. package/dist/native/lib/control.d.ts +24 -0
  141. package/dist/native/lib/control.js +0 -0
  142. package/dist/native/lib/external-store.d.ts +16 -0
  143. package/dist/native/lib/external-store.js +30 -0
  144. package/dist/native/lib/keyboard.d.ts +15 -0
  145. package/dist/native/lib/keyboard.js +24 -0
  146. package/dist/native/lib/labels.d.ts +15 -0
  147. package/dist/native/lib/labels.js +17 -0
  148. package/dist/native/lib/loading.d.ts +10 -0
  149. package/dist/native/lib/loading.js +15 -0
  150. package/dist/native/lib/network.d.ts +11 -0
  151. package/dist/native/lib/network.js +20 -0
  152. package/dist/native/lib/scheme.d.ts +18 -0
  153. package/dist/native/lib/scheme.js +22 -0
  154. package/dist/native/lib/snackbar.d.ts +45 -0
  155. package/dist/native/lib/snackbar.js +59 -0
  156. package/dist/native/lib/theme.d.ts +34 -0
  157. package/dist/native/lib/theme.js +53 -0
  158. package/dist/native/lib/timezone.d.ts +26 -0
  159. package/dist/native/lib/timezone.js +95 -0
  160. package/dist/native/lib/token-color.d.ts +5 -0
  161. package/dist/native/lib/token-color.js +13 -0
  162. package/dist/native/lib/token-color.web.d.ts +4 -0
  163. package/dist/native/lib/token-color.web.js +7 -0
  164. package/dist/native/lib/tuning-context.d.ts +9 -0
  165. package/dist/native/lib/tuning-context.js +7 -0
  166. package/dist/native/lib/tuning.d.ts +24 -0
  167. package/dist/native/lib/tuning.js +42 -0
  168. package/dist/native/lib/typography.d.ts +10 -0
  169. package/dist/native/lib/typography.js +11 -0
  170. package/dist/native/lib/utils.d.ts +11 -0
  171. package/dist/native/lib/utils.js +21 -0
  172. package/dist/native/once/confirm.d.ts +7 -0
  173. package/dist/native/once/confirm.js +60 -0
  174. package/dist/native/once/error-boundary.d.ts +28 -0
  175. package/dist/native/once/error-boundary.js +55 -0
  176. package/dist/native/once/loading-lock.d.ts +8 -0
  177. package/dist/native/once/loading-lock.js +28 -0
  178. package/dist/native/once/offline-banner.d.ts +15 -0
  179. package/dist/native/once/offline-banner.js +35 -0
  180. package/dist/native/once/snackbar.d.ts +17 -0
  181. package/dist/native/once/snackbar.js +106 -0
  182. package/dist/native/styles.css +46 -0
  183. package/dist/shared/analytics.d.ts +71 -0
  184. package/dist/shared/analytics.js +0 -0
  185. package/dist/shared/button.d.ts +7 -0
  186. package/dist/shared/button.js +23 -0
  187. package/dist/shared/form.d.ts +45 -0
  188. package/dist/shared/form.js +46 -0
  189. package/dist/shared/index.d.ts +3 -0
  190. package/dist/shared/index.js +3 -0
  191. package/dist/tokens/contrast-pairs.d.ts +30 -0
  192. package/dist/tokens/contrast-pairs.js +404 -0
  193. package/dist/tokens/index.d.ts +6 -0
  194. package/dist/tokens/index.js +10 -0
  195. package/dist/tokens/styles.gen.css +250 -0
  196. package/dist/tokens/tokens.gen.d.ts +141 -0
  197. package/dist/tokens/tokens.gen.js +206 -0
  198. package/dist/tuning/catalog.d.ts +27 -0
  199. package/dist/tuning/catalog.gen.d.ts +4 -0
  200. package/dist/tuning/catalog.gen.js +397 -0
  201. package/dist/tuning/catalog.js +128 -0
  202. package/dist/tuning/color.d.ts +20 -0
  203. package/dist/tuning/color.js +80 -0
  204. package/dist/tuning/css.d.ts +35 -0
  205. package/dist/tuning/css.js +147 -0
  206. package/dist/tuning/index.d.ts +8 -0
  207. package/dist/tuning/index.js +9 -0
  208. package/dist/tuning/model.d.ts +33 -0
  209. package/dist/tuning/model.js +154 -0
  210. package/dist/tuning/native.d.ts +35 -0
  211. package/dist/tuning/native.js +80 -0
  212. package/dist/tuning/schema.d.ts +69 -0
  213. package/dist/tuning/schema.js +247 -0
  214. package/dist/tuning/types.d.ts +75 -0
  215. package/dist/tuning/types.js +39 -0
  216. package/dist/web/analytics/line-chart.d.ts +20 -0
  217. package/dist/web/analytics/line-chart.js +28 -0
  218. package/dist/web/analytics/metric-card.d.ts +18 -0
  219. package/dist/web/analytics/metric-card.js +40 -0
  220. package/dist/web/analytics/multi-line-chart.d.ts +39 -0
  221. package/dist/web/analytics/multi-line-chart.js +345 -0
  222. package/dist/web/atom/avatar.d.ts +11 -0
  223. package/dist/web/atom/avatar.js +24 -0
  224. package/dist/web/atom/badge.d.ts +2 -0
  225. package/dist/web/atom/badge.js +3 -0
  226. package/dist/web/atom/button.d.ts +23 -0
  227. package/dist/web/atom/button.js +35 -0
  228. package/dist/web/atom/checkbox.d.ts +19 -0
  229. package/dist/web/atom/checkbox.js +33 -0
  230. package/dist/web/atom/colored-value.d.ts +13 -0
  231. package/dist/web/atom/colored-value.js +24 -0
  232. package/dist/web/atom/help.d.ts +10 -0
  233. package/dist/web/atom/help.js +18 -0
  234. package/dist/web/atom/label.d.ts +2 -0
  235. package/dist/web/atom/label.js +3 -0
  236. package/dist/web/atom/segmented-control.d.ts +39 -0
  237. package/dist/web/atom/segmented-control.js +42 -0
  238. package/dist/web/atom/select.d.ts +43 -0
  239. package/dist/web/atom/select.js +93 -0
  240. package/dist/web/atom/separator.d.ts +2 -0
  241. package/dist/web/atom/separator.js +3 -0
  242. package/dist/web/atom/skeleton.d.ts +2 -0
  243. package/dist/web/atom/skeleton.js +3 -0
  244. package/dist/web/atom/slider.d.ts +33 -0
  245. package/dist/web/atom/slider.js +70 -0
  246. package/dist/web/atom/spinner.d.ts +8 -0
  247. package/dist/web/atom/spinner.js +14 -0
  248. package/dist/web/atom/switch.d.ts +11 -0
  249. package/dist/web/atom/switch.js +10 -0
  250. package/dist/web/atom/text-area.d.ts +23 -0
  251. package/dist/web/atom/text-area.js +27 -0
  252. package/dist/web/atom/text-field.d.ts +18 -0
  253. package/dist/web/atom/text-field.js +22 -0
  254. package/dist/web/atom/toggle-chip.d.ts +22 -0
  255. package/dist/web/atom/toggle-chip.js +28 -0
  256. package/dist/web/atom/tooltip.d.ts +23 -0
  257. package/dist/web/atom/tooltip.js +26 -0
  258. package/dist/web/atom/typography.d.ts +6 -0
  259. package/dist/web/atom/typography.js +23 -0
  260. package/dist/web/base/accordion.d.ts +9 -0
  261. package/dist/web/base/accordion.js +44 -0
  262. package/dist/web/base/alert.d.ts +11 -0
  263. package/dist/web/base/alert.js +37 -0
  264. package/dist/web/base/avatar.d.ts +8 -0
  265. package/dist/web/base/avatar.js +29 -0
  266. package/dist/web/base/badge.d.ts +12 -0
  267. package/dist/web/base/badge.js +26 -0
  268. package/dist/web/base/breadcrumb.d.ts +16 -0
  269. package/dist/web/base/breadcrumb.js +72 -0
  270. package/dist/web/base/button.d.ts +12 -0
  271. package/dist/web/base/button.js +47 -0
  272. package/dist/web/base/card.d.ts +19 -0
  273. package/dist/web/base/card.js +74 -0
  274. package/dist/web/base/checkbox.d.ts +6 -0
  275. package/dist/web/base/checkbox.js +21 -0
  276. package/dist/web/base/dialog.d.ts +20 -0
  277. package/dist/web/base/dialog.js +92 -0
  278. package/dist/web/base/dropdown-menu.d.ts +29 -0
  279. package/dist/web/base/dropdown-menu.js +125 -0
  280. package/dist/web/base/field.d.ts +27 -0
  281. package/dist/web/base/field.js +118 -0
  282. package/dist/web/base/form.d.ts +38 -0
  283. package/dist/web/base/form.js +110 -0
  284. package/dist/web/base/input.d.ts +9 -0
  285. package/dist/web/base/input.js +23 -0
  286. package/dist/web/base/label.d.ts +6 -0
  287. package/dist/web/base/label.js +15 -0
  288. package/dist/web/base/pagination.d.ts +34 -0
  289. package/dist/web/base/pagination.js +90 -0
  290. package/dist/web/base/popover.d.ts +11 -0
  291. package/dist/web/base/popover.js +37 -0
  292. package/dist/web/base/radio-group.d.ts +7 -0
  293. package/dist/web/base/radio-group.js +27 -0
  294. package/dist/web/base/scroll-area.d.ts +10 -0
  295. package/dist/web/base/scroll-area.js +41 -0
  296. package/dist/web/base/select.d.ts +17 -0
  297. package/dist/web/base/select.js +96 -0
  298. package/dist/web/base/separator.d.ts +6 -0
  299. package/dist/web/base/separator.js +17 -0
  300. package/dist/web/base/sheet.d.ts +19 -0
  301. package/dist/web/base/sheet.js +88 -0
  302. package/dist/web/base/skeleton.d.ts +5 -0
  303. package/dist/web/base/skeleton.js +14 -0
  304. package/dist/web/base/slider.d.ts +9 -0
  305. package/dist/web/base/slider.js +39 -0
  306. package/dist/web/base/sonner.d.ts +9 -0
  307. package/dist/web/base/sonner.js +25 -0
  308. package/dist/web/base/spinner.d.ts +5 -0
  309. package/dist/web/base/spinner.js +17 -0
  310. package/dist/web/base/switch.d.ts +6 -0
  311. package/dist/web/base/switch.js +19 -0
  312. package/dist/web/base/table.d.ts +14 -0
  313. package/dist/web/base/table.js +68 -0
  314. package/dist/web/base/tabs.d.ts +9 -0
  315. package/dist/web/base/tabs.js +36 -0
  316. package/dist/web/base/textarea.d.ts +9 -0
  317. package/dist/web/base/textarea.js +23 -0
  318. package/dist/web/base/tooltip.d.ts +9 -0
  319. package/dist/web/base/tooltip.js +36 -0
  320. package/dist/web/form/checkbox.d.ts +35 -0
  321. package/dist/web/form/checkbox.js +91 -0
  322. package/dist/web/form/radio-group.d.ts +24 -0
  323. package/dist/web/form/radio-group.js +75 -0
  324. package/dist/web/form/select.d.ts +16 -0
  325. package/dist/web/form/select.js +44 -0
  326. package/dist/web/form/slider.d.ts +19 -0
  327. package/dist/web/form/slider.js +51 -0
  328. package/dist/web/form/switch.d.ts +11 -0
  329. package/dist/web/form/switch.js +50 -0
  330. package/dist/web/form/text-area.d.ts +10 -0
  331. package/dist/web/form/text-area.js +31 -0
  332. package/dist/web/form/text-input.d.ts +10 -0
  333. package/dist/web/form/text-input.js +42 -0
  334. package/dist/web/index.d.ts +1 -0
  335. package/dist/web/index.js +0 -0
  336. package/dist/web/layout/accordion.d.ts +26 -0
  337. package/dist/web/layout/accordion.js +29 -0
  338. package/dist/web/layout/alert-modal.d.ts +41 -0
  339. package/dist/web/layout/alert-modal.js +71 -0
  340. package/dist/web/layout/card.d.ts +17 -0
  341. package/dist/web/layout/card.js +35 -0
  342. package/dist/web/layout/description.d.ts +12 -0
  343. package/dist/web/layout/description.js +20 -0
  344. package/dist/web/layout/information.d.ts +36 -0
  345. package/dist/web/layout/information.js +53 -0
  346. package/dist/web/layout/modal.d.ts +16 -0
  347. package/dist/web/layout/modal.js +37 -0
  348. package/dist/web/layout/page-frame.d.ts +37 -0
  349. package/dist/web/layout/page-frame.js +79 -0
  350. package/dist/web/layout/scroll-area.d.ts +10 -0
  351. package/dist/web/layout/scroll-area.js +13 -0
  352. package/dist/web/layout/sheet.d.ts +32 -0
  353. package/dist/web/layout/sheet.js +68 -0
  354. package/dist/web/layout/simple-dialog.d.ts +11 -0
  355. package/dist/web/layout/simple-dialog.js +24 -0
  356. package/dist/web/layout/simple-table.d.ts +49 -0
  357. package/dist/web/layout/simple-table.js +58 -0
  358. package/dist/web/layout/tabs.d.ts +26 -0
  359. package/dist/web/layout/tabs.js +42 -0
  360. package/dist/web/layout/titled-modal.d.ts +32 -0
  361. package/dist/web/layout/titled-modal.js +58 -0
  362. package/dist/web/lib/css-vars.d.ts +14 -0
  363. package/dist/web/lib/css-vars.js +18 -0
  364. package/dist/web/lib/dialog.d.ts +13 -0
  365. package/dist/web/lib/dialog.js +0 -0
  366. package/dist/web/lib/form.d.ts +2 -0
  367. package/dist/web/lib/form.js +3 -0
  368. package/dist/web/lib/labels.d.ts +27 -0
  369. package/dist/web/lib/labels.js +29 -0
  370. package/dist/web/lib/modal-open-focus.d.ts +17 -0
  371. package/dist/web/lib/modal-open-focus.js +44 -0
  372. package/dist/web/lib/restore-focus.d.ts +12 -0
  373. package/dist/web/lib/restore-focus.js +32 -0
  374. package/dist/web/lib/utils.d.ts +4 -0
  375. package/dist/web/lib/utils.js +10 -0
  376. package/dist/web/styles.css +162 -0
  377. package/package.json +203 -4
package/README.md CHANGED
@@ -1,3 +1,87 @@
1
1
  # @lt-three/love3
2
2
 
3
- Placeholder. Real releases are published from CI.
3
+ The shared design system of <3 (Less Than Three): layered backgrounds, hairline borders, soft shadows, and an indigo primary action.
4
+ It looks the same on web (React + Tailwind CSS v4) and React Native (NativeWind v5). The actual token values (color, radius, shadow, typeface) can also be read as a TS object.
5
+
6
+ Licensed under MIT.
7
+
8
+ ## Installation
9
+
10
+ ```sh
11
+ npm install @lt-three/love3
12
+ ```
13
+
14
+ - **web**: install `react` and `react-dom` (`>=19.3.0 <20`) and `tailwindcss` (v4). The dependencies used by the web components (Radix, `@tanstack/charts`, and so on) are in this package's `dependencies`, so you do not need to install them separately.
15
+ - **React Native**: install `react`, `react-native`, `nativewind` (v5), `react-native-css`, and `tailwindcss`, plus the native dependencies pulled in by the components you use (`expo`, `expo-router`, `react-native-reanimated`, `react-native-svg`, and so on).
16
+ Native-only dependencies are **optional `peerDependencies`**. You do not need to install the dependencies of components you do not use (see the `peerDependencies` in `package.json` and the imports of each component to find out which component needs which).
17
+
18
+ The published files are in `dist/` (ESM `.js` and `.d.ts`). They keep the same structure as the source, one file per component. The dependencies of components you do not use are not pulled in.
19
+
20
+ ## Usage
21
+
22
+ | import | contents |
23
+ | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
24
+ | `@lt-three/love3/styles.css` | Tailwind v4 `@theme` with light and dark. Shared by web and NativeWind |
25
+ | `@lt-three/love3/tokens` | The actual token values as a TS object (`tokens.light` / `tokens.dark`), `cssVar`, and types. For RN charts and Reanimated, where CSS is not available. Does not import `node:` built-ins |
26
+ | `@lt-three/love3/tokens/contrast` | The foreground / background pairs checked for contrast (`CONTRAST_PAIRS`) and the known exceptions with reasons (`KNOWN_CONTRAST_EXCEPTIONS`). Data only |
27
+ | `@lt-three/love3/tuning` | The format, validation, and application of "tuning", which overrides tokens at runtime (imports only `zod`) |
28
+ | `@lt-three/love3/web` / `@lt-three/love3/native` / `@lt-three/love3/shared` | The entry point of each layer (`index.ts`) |
29
+ | `@lt-three/love3/web/atom/button.tsx`, **with the extension** | Web components. `web/*.ts` (hooks and utilities) and `web/*.tsx` |
30
+ | `@lt-three/love3/web/styles.css` | Imported by a web app at its CSS entry. Tailwind, fonts, tokens, and base styles |
31
+ | `@lt-three/love3/native/atom/button.tsx`, **with the extension** | Native components |
32
+ | `@lt-three/love3/native/styles.css` | **The CSS entry for real devices (Metro / NativeWind v5)**. Tailwind, `nativewind/theme`, tokens, detection of component classes, and an override that maps `dark:` to `prefers-color-scheme` |
33
+ | `@lt-three/love3/shared/…` (`.ts` / `.tsx`) | Props types and variant definitions shared by web and native |
34
+
35
+ **Wildcard exports use keys with the file extension** (`./web/*.tsx` / `./web/*.ts`). `exports` does not search for extensions, so consumers import with the extension too
36
+ (enable `allowImportingTsExtensions` in TypeScript). Without the extension (`.../atom/button`) the specifier does not resolve. Specifiers point to the `.js` files and the `.d.ts` type declarations in `dist/`.
37
+
38
+ ### web
39
+
40
+ Import it once at your CSS entry.
41
+
42
+ ```css
43
+ @import "@lt-three/love3/web/styles.css";
44
+ ```
45
+
46
+ ```tsx
47
+ import { Button } from "@lt-three/love3/web/atom/button.tsx";
48
+ ```
49
+
50
+ The Tailwind classes used by the components are picked up from `dist/` by `@source` in this CSS. Your own app source is left to Tailwind's automatic detection, based on the bundler's project root.
51
+ Switch to dark with `<html class="dark">`.
52
+
53
+ ### React Native
54
+
55
+ Import it once in your app's `global.css` (NativeWind v5 / react-native-css compiles it as Tailwind v4).
56
+
57
+ ```css
58
+ @import "@lt-three/love3/native/styles.css";
59
+ ```
60
+
61
+ On native, `dark:` is resolved by **the OS color scheme** (`prefers-color-scheme`), not by a class. With `.dark` as an ancestor selector, react-native-css treats that view as a container,
62
+ and a descendant ScrollView can no longer receive pans. Switch the in-app theme with `Appearance.setColorScheme()`.
63
+
64
+ The components that use SwiftUI Charts on iOS (`line-chart.ios.tsx` / `pie-chart.ios.tsx`) are imported explicitly, with the extension, by the iOS app.
65
+
66
+ ### Tokens
67
+
68
+ ```ts
69
+ import { cssVar, tokens } from "@lt-three/love3/tokens";
70
+
71
+ tokens.light["ink-900"]; // the actual value ("#1b1c20")
72
+ cssVar("ink-900"); // "var(--ink-900)"
73
+ ```
74
+
75
+ The variable names are shadcn-compatible names (`--background`, `--primary`, and so on) plus raw tokens such as `--ink-*`, `--line*`, and `--lt-three`.
76
+
77
+ ## Note: `.theme-light` does not lighten semantic classes
78
+
79
+ `.theme-light` (a scope that forces light) redefines **only the raw tokens** (`--ink-*` / `--line*` / `--frame` / `--paper` / `--raised` / `--overlay` / `--wash` / `--scrim` / `--shadow-color` / `--action-ink` / `--state-*` / `--chart-*`).
80
+ Semantic variables such as `--background` / `--foreground` / `--primary` are declared on `:root` as `var(--paper)` and the like, and **are resolved on the element that declares them, then inherited by descendants**.
81
+ So even if you put `.theme-light` under `<html class="dark">`, classes such as `bg-background` / `text-foreground` / `bg-primary` **stay dark** in its descendants
82
+ (classes of raw tokens such as `bg-paper` / `text-ink-900` do become light).
83
+ love3 components do not use `.theme-light`. On a page that must always be light, use raw-token classes inside `.theme-light`, or also redeclare the semantic variables in `.theme-light`.
84
+
85
+ ## License
86
+
87
+ [MIT](./LICENSE)
@@ -0,0 +1,4 @@
1
+ //#region src/native/analytics/animation.d.ts
2
+ /** Chart animation duration (ms). Kept identical to the web analytics animation. */
3
+ export declare const animationDuration = 250;
4
+ //#endregion
@@ -0,0 +1,6 @@
1
+ //#region src/native/analytics/animation.ts
2
+ /** Chart animation duration (ms). Kept identical to the web analytics animation. */
3
+ const animationDuration = 250;
4
+
5
+ //#endregion
6
+ export { animationDuration };
@@ -0,0 +1,25 @@
1
+ import { ChartCommonProps as ChartCommonProps$1, LineChartSharedProps, LinePoint, LineSeries, MultiLineChartSharedProps } from "../../shared/analytics.js";
2
+ import { ViewStyle } from "react-native";
3
+ //#region src/native/analytics/chart.types.d.ts
4
+ export type PieSlice = {
5
+ label: string;
6
+ value: number;
7
+ color?: string;
8
+ };
9
+ type ChartCommonProps = ChartCommonProps$1 & {
10
+ style?: ViewStyle;
11
+ /**
12
+ * Text shown on platforms without native chart support.
13
+ * This is a shared package, so it only provides a default; consumers pass their own translation.
14
+ */
15
+ fallbackText?: string;
16
+ };
17
+ export type LineChartProps = ChartCommonProps & LineChartSharedProps;
18
+ export type PieChartProps = ChartCommonProps & {
19
+ data: PieSlice[];
20
+ /** Renders a donut with a hollow center. */
21
+ donut?: boolean;
22
+ };
23
+ export type MultiLineChartProps = ChartCommonProps & MultiLineChartSharedProps;
24
+ //#endregion
25
+ export type { LinePoint, LineSeries };
File without changes
@@ -0,0 +1,4 @@
1
+ import { LineChartProps } from "./chart.types.js";
2
+ //#region src/native/analytics/line-chart.d.ts
3
+ export declare function LineChart(props: LineChartProps): import("react").JSX.Element;
4
+ //#endregion
@@ -0,0 +1,4 @@
1
+ import { LineChartProps } from "./chart.types.js";
2
+ //#region src/native/analytics/line-chart.ios.d.ts
3
+ export declare function LineChart({ data, color, height, style }: LineChartProps): import("react").JSX.Element;
4
+ //#endregion
@@ -0,0 +1,24 @@
1
+ import { useChartPalette } from "../lib/chart-palette.js";
2
+ import { Chart, Host } from "@expo/ui/swift-ui";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region src/native/analytics/line-chart.ios.tsx
6
+ function LineChart({ data, color, height = 220, style }) {
7
+ const palette = useChartPalette();
8
+ return /* @__PURE__ */ jsx(Host, {
9
+ style: [{ height }, style],
10
+ children: /* @__PURE__ */ jsx(Chart, {
11
+ data: data.map((point) => ({
12
+ x: point.x,
13
+ y: point.y
14
+ })),
15
+ type: "line",
16
+ showGrid: true,
17
+ animate: true,
18
+ lineStyle: { color: color ?? palette[0] }
19
+ })
20
+ });
21
+ }
22
+
23
+ //#endregion
24
+ export { LineChart };
@@ -0,0 +1,33 @@
1
+ import { Text as Text$1 } from "../base/text.js";
2
+ import { Suspense, lazy } from "react";
3
+ import { Platform, View } from "react-native";
4
+ import { jsx } from "react/jsx-runtime";
5
+
6
+ //#region src/native/analytics/line-chart.tsx
7
+ const SwiftUILineChart = lazy(() => import("./line-chart.ios.js").then((module) => ({ default: module.LineChart })));
8
+ const DEFAULT_FALLBACK_TEXT = "チャートは現在 iOS でのみ表示できます";
9
+ const DEFAULT_HEIGHT = 220;
10
+ function LineChart(props) {
11
+ const height = props.height ?? DEFAULT_HEIGHT;
12
+ if (Platform.OS !== "ios") return /* @__PURE__ */ jsx(LineChartFallback, {
13
+ height,
14
+ text: props.fallbackText
15
+ });
16
+ return /* @__PURE__ */ jsx(Suspense, {
17
+ fallback: /* @__PURE__ */ jsx(View, { style: { height } }),
18
+ children: /* @__PURE__ */ jsx(SwiftUILineChart, { ...props })
19
+ });
20
+ }
21
+ function LineChartFallback({ height, text }) {
22
+ return /* @__PURE__ */ jsx(View, {
23
+ style: { height },
24
+ className: "items-center justify-center",
25
+ children: /* @__PURE__ */ jsx(Text$1, {
26
+ className: "text-muted-foreground text-sm",
27
+ children: text ?? DEFAULT_FALLBACK_TEXT
28
+ })
29
+ });
30
+ }
31
+
32
+ //#endregion
33
+ export { LineChart };
@@ -0,0 +1,10 @@
1
+ import { MetricCardSharedProps } from "../../shared/analytics.js";
2
+ //#region src/native/analytics/metric-card.d.ts
3
+ export type MetricCardProps = MetricCardSharedProps;
4
+ /**
5
+ * A single metric on a surface. Mirrors the web analytics metric-card.
6
+ * The content (label + large monospaced number + secondary text) lives in `atom/readout`;
7
+ * as on the web, this component only wraps it in the card chrome.
8
+ */
9
+ export declare function MetricCard({ label, value, subValue, trend, className }: MetricCardProps): import("react").JSX.Element;
10
+ //#endregion
@@ -0,0 +1,29 @@
1
+ import { useTokenColor } from "../lib/token-color.js";
2
+ import { cn } from "../lib/utils.js";
3
+ import { Readout } from "../atom/readout.js";
4
+ import { Panel } from "../layout/panel.js";
5
+ import { jsx } from "react/jsx-runtime";
6
+
7
+ //#region src/native/analytics/metric-card.tsx
8
+ /**
9
+ * A single metric on a surface. Mirrors the web analytics metric-card.
10
+ * The content (label + large monospaced number + secondary text) lives in `atom/readout`;
11
+ * as on the web, this component only wraps it in the card chrome.
12
+ */
13
+ function MetricCard({ label, value, subValue, trend, className }) {
14
+ const up = useTokenColor("--state-success");
15
+ const down = useTokenColor("--state-error");
16
+ const valueColor = trend === void 0 || trend === 0 ? void 0 : trend > 0 ? up : down;
17
+ return /* @__PURE__ */ jsx(Panel, {
18
+ className: cn("p-4", className),
19
+ children: /* @__PURE__ */ jsx(Readout, {
20
+ label,
21
+ value,
22
+ sub: subValue,
23
+ valueColor
24
+ })
25
+ });
26
+ }
27
+
28
+ //#endregion
29
+ export { MetricCard };
@@ -0,0 +1,18 @@
1
+ import { MultiLineChartProps } from "./chart.types.js";
2
+ //#region src/native/analytics/multi-line-chart.d.ts
3
+ /**
4
+ * Multi-series line chart. The web counterpart is `analytics/multi-line-chart` (`@tanstack/charts`)
5
+ * (the props are shared via `shared/analytics.ts`).
6
+ *
7
+ * **The `@expo/ui` Chart can only draw a single series** (its type definitions also state that
8
+ * line/area are single-series), so use this component when two or more series share an axis.
9
+ * Splitting series with the same unit and axis (such as balance and equity) across two cards
10
+ * makes the relationship hard to read without comparing them vertically.
11
+ *
12
+ * Drawing uses react-native-svg. Unlike SwiftUI Charts it draws no outer frame, only the tick lines
13
+ * (a consumer wrapping it in a `Panel` would otherwise get a double border).
14
+ *
15
+ * Tapping reads out each series' value at that position, since tick marks alone only convey the rough shape.
16
+ */
17
+ export declare function MultiLineChart({ series, height, formatValue, emptyText, style, accessibilityLabel }: MultiLineChartProps): import("react").JSX.Element;
18
+ //#endregion
@@ -0,0 +1,216 @@
1
+ import { useTokenColor } from "../lib/token-color.js";
2
+ import { Text as Text$2 } from "../base/text.js";
3
+ import { tabularNums } from "../lib/typography.js";
4
+ import { useState } from "react";
5
+ import { Pressable, View } from "react-native";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import Svg, { Circle, Line, Path, Text as Text$1 } from "react-native-svg";
8
+
9
+ //#region src/native/analytics/multi-line-chart.tsx
10
+ /**
11
+ * Multi-series line chart. The web counterpart is `analytics/multi-line-chart` (`@tanstack/charts`)
12
+ * (the props are shared via `shared/analytics.ts`).
13
+ *
14
+ * **The `@expo/ui` Chart can only draw a single series** (its type definitions also state that
15
+ * line/area are single-series), so use this component when two or more series share an axis.
16
+ * Splitting series with the same unit and axis (such as balance and equity) across two cards
17
+ * makes the relationship hard to read without comparing them vertically.
18
+ *
19
+ * Drawing uses react-native-svg. Unlike SwiftUI Charts it draws no outer frame, only the tick lines
20
+ * (a consumer wrapping it in a `Panel` would otherwise get a double border).
21
+ *
22
+ * Tapping reads out each series' value at that position, since tick marks alone only convey the rough shape.
23
+ */
24
+ function MultiLineChart({ series, height = 220, formatValue = (value) => String(Math.round(value)), emptyText = "データがありません", style, accessibilityLabel }) {
25
+ const line = useTokenColor("--line");
26
+ const mutedInk = useTokenColor("--ink-500");
27
+ const [width, setWidth] = useState(0);
28
+ const [pickedX, setPickedX] = useState(null);
29
+ const withData = series.filter((entry) => entry.points.length > 0);
30
+ const values = withData.flatMap((entry) => entry.points.map((point) => point.y));
31
+ if (withData.length === 0) return /* @__PURE__ */ jsx(View, {
32
+ style: [{ height }, style],
33
+ className: "items-center justify-center",
34
+ children: /* @__PURE__ */ jsx(Text$2, {
35
+ className: "text-muted-foreground text-sm",
36
+ children: emptyText
37
+ })
38
+ });
39
+ const padding = {
40
+ top: 8,
41
+ right: 8,
42
+ bottom: 8,
43
+ left: 72
44
+ };
45
+ const plotWidth = Math.max(width - padding.left - padding.right, 0);
46
+ const plotHeight = height - padding.top - padding.bottom;
47
+ const min = Math.min(...values);
48
+ const max = Math.max(...values);
49
+ const span = max - min || Math.max(Math.abs(max), 1);
50
+ const low = max === min ? min - span / 2 : min;
51
+ const high = max === min ? max + span / 2 : max;
52
+ const toY = (value) => padding.top + (1 - (value - low) / (high - low)) * plotHeight;
53
+ const times = withData.flatMap((entry) => entry.points.map((point) => point.t));
54
+ const timed = times.every((time) => time !== void 0) && times.length > 0;
55
+ const tMin = timed ? Math.min(...times) : 0;
56
+ const tSpan = (timed ? Math.max(...times) : 0) - tMin;
57
+ const toX = (index, count, time) => {
58
+ if (timed && time !== void 0) return padding.left + (tSpan === 0 ? plotWidth / 2 : (time - tMin) / tSpan * plotWidth);
59
+ return padding.left + (count === 1 ? plotWidth / 2 : index / (count - 1) * plotWidth);
60
+ };
61
+ const ticks = [
62
+ high,
63
+ (high + low) / 2,
64
+ low
65
+ ];
66
+ const picked = pickedX === null ? [] : withData.map((entry) => ({
67
+ entry,
68
+ hit: nearestPoint(entry, pickedX, toX)
69
+ })).filter((row) => row.hit !== null);
70
+ const marker = picked[0];
71
+ return /* @__PURE__ */ jsxs(View, {
72
+ style,
73
+ ...accessibilityLabel === void 0 ? {} : {
74
+ accessible: true,
75
+ accessibilityRole: "image",
76
+ accessibilityLabel
77
+ },
78
+ children: [
79
+ /* @__PURE__ */ jsx(Pressable, {
80
+ focusable: false,
81
+ tabIndex: -1,
82
+ onLayout: (event) => setWidth(event.nativeEvent.layout.width),
83
+ onPress: (event) => {
84
+ const x = pressX(event);
85
+ if (x === null) return;
86
+ setPickedX(x < padding.left || x > padding.left + plotWidth ? null : x);
87
+ },
88
+ children: /* @__PURE__ */ jsxs(Svg, {
89
+ width,
90
+ height,
91
+ children: [
92
+ ticks.map((tick) => /* @__PURE__ */ jsx(Line, {
93
+ x1: padding.left,
94
+ x2: padding.left + plotWidth,
95
+ y1: toY(tick),
96
+ y2: toY(tick),
97
+ stroke: line,
98
+ strokeWidth: 1
99
+ }, `grid-${tick}`)),
100
+ ticks.map((tick) => /* @__PURE__ */ jsx(Text$1, {
101
+ x: padding.left - 8,
102
+ y: toY(tick) + 4,
103
+ fontSize: 10,
104
+ fill: mutedInk,
105
+ textAnchor: "end",
106
+ children: formatValue(tick)
107
+ }, `label-${tick}`)),
108
+ withData.map((entry) => /* @__PURE__ */ jsx(Path, {
109
+ d: pathOf(entry, toX, toY),
110
+ stroke: entry.color,
111
+ strokeWidth: entry.dashed === true ? 1 : 1.5,
112
+ strokeDasharray: entry.dashed === true ? "4 3" : void 0,
113
+ fill: "none"
114
+ }, entry.key)),
115
+ marker !== void 0 && /* @__PURE__ */ jsx(Line, {
116
+ x1: marker.hit.x,
117
+ x2: marker.hit.x,
118
+ y1: padding.top,
119
+ y2: padding.top + plotHeight,
120
+ stroke: mutedInk,
121
+ strokeWidth: 1,
122
+ strokeDasharray: "2 2"
123
+ }),
124
+ picked.map((row) => /* @__PURE__ */ jsx(Circle, {
125
+ cx: row.hit.x,
126
+ cy: toY(row.hit.value.y),
127
+ r: 3,
128
+ fill: row.entry.color
129
+ }, `dot-${row.entry.key}`))
130
+ ]
131
+ })
132
+ }),
133
+ marker !== void 0 && /* @__PURE__ */ jsxs(View, {
134
+ className: "border-line bg-popover rounded-control mt-2 gap-1 border p-2.5 shadow-md",
135
+ children: [/* @__PURE__ */ jsx(Text$2, {
136
+ style: tabularNums,
137
+ className: "text-muted-foreground font-mono text-[11px]",
138
+ children: String(marker.hit.value.x)
139
+ }), picked.map((row) => /* @__PURE__ */ jsxs(View, {
140
+ className: "flex-row items-center justify-between gap-3",
141
+ children: [/* @__PURE__ */ jsxs(View, {
142
+ className: "flex-row items-center gap-1.5",
143
+ children: [/* @__PURE__ */ jsx(View, { style: {
144
+ width: 10,
145
+ height: 2,
146
+ backgroundColor: row.entry.color
147
+ } }), /* @__PURE__ */ jsx(Text$2, {
148
+ className: "text-muted-foreground text-[11px]",
149
+ children: row.entry.label
150
+ })]
151
+ }), /* @__PURE__ */ jsx(Text$2, {
152
+ style: tabularNums,
153
+ className: "text-foreground font-mono text-[13px] font-semibold",
154
+ children: formatValue(row.hit.value.y)
155
+ })]
156
+ }, `read-${row.entry.key}`))]
157
+ }),
158
+ /* @__PURE__ */ jsx(View, {
159
+ className: "flex-row flex-wrap gap-x-4 gap-y-1 px-1 pt-2",
160
+ children: series.map((entry) => /* @__PURE__ */ jsxs(View, {
161
+ className: "flex-row items-center gap-1.5",
162
+ children: [/* @__PURE__ */ jsx(View, { style: {
163
+ width: 10,
164
+ height: 2,
165
+ backgroundColor: entry.color,
166
+ opacity: entry.points.length > 0 ? 1 : .4
167
+ } }), /* @__PURE__ */ jsx(Text$2, {
168
+ className: "text-muted-foreground text-[11px]",
169
+ children: entry.label
170
+ })]
171
+ }, `legend-${entry.key}`))
172
+ })
173
+ ]
174
+ });
175
+ }
176
+ /**
177
+ * The pressed position (x from the left edge of the pressed element). On a device this is `locationX`.
178
+ * react-native-web's `onPress` passes a DOM click (no `locationX`), so in that case it is computed from the difference to the element's left edge.
179
+ * Returns null for a click without a position (keyboard, etc.).
180
+ */
181
+ function pressX(event) {
182
+ const { locationX } = event.nativeEvent;
183
+ if (typeof locationX === "number" && Number.isFinite(locationX)) return locationX;
184
+ const dom = event.nativeEvent;
185
+ if (dom.detail === 0) return null;
186
+ const target = event.currentTarget;
187
+ return dom.clientX - target.getBoundingClientRect().left;
188
+ }
189
+ /** Turns a series into a single SVG path. */
190
+ function pathOf(entry, toX, toY) {
191
+ const count = entry.points.length;
192
+ return entry.points.map((point, index) => `${index === 0 ? "M" : "L"}${toX(index, count, point.t)},${toY(point.y)}`).join(" ");
193
+ }
194
+ /** Returns the point nearest to the pressed x, together with its drawn position. */
195
+ function nearestPoint(entry, pickedX, toX) {
196
+ const count = entry.points.length;
197
+ let best;
198
+ let bestX = 0;
199
+ let bestDistance = Number.POSITIVE_INFINITY;
200
+ for (let index = 0; index < count; index++) {
201
+ const x = toX(index, count, entry.points[index]?.t);
202
+ const distance = Math.abs(x - pickedX);
203
+ if (distance < bestDistance) {
204
+ bestDistance = distance;
205
+ bestX = x;
206
+ best = entry.points[index];
207
+ }
208
+ }
209
+ return best === void 0 ? null : {
210
+ x: bestX,
211
+ value: best
212
+ };
213
+ }
214
+
215
+ //#endregion
216
+ export { MultiLineChart };
@@ -0,0 +1,15 @@
1
+ import { PieChartProps } from "./chart.types.js";
2
+ //#region src/native/analytics/pie-chart.d.ts
3
+ /**
4
+ * Pie chart (react-native-svg). The default implementation for Android and web. The iOS SwiftUI Charts version (`pie-chart.ios.tsx`)
5
+ * needs `@expo/ui`, so iOS is drawn with this implementation too unless the app imports that file explicitly.
6
+ *
7
+ * Drawing uses the same react-native-svg as `multi-line-chart`. It is **not** an "iOS only"
8
+ * placeholder because a screen's main content can be produced by this component alone,
9
+ * and on Android that content would be replaced entirely by a text message.
10
+ *
11
+ * **No legend here.** Consumers are expected to list the colored breakdown below the circle,
12
+ * so a legend here would show the same thing twice and eat into the circle's height.
13
+ */
14
+ export declare function PieChart({ data, donut, height, style, accessibilityLabel }: PieChartProps): import("react").JSX.Element;
15
+ //#endregion
@@ -0,0 +1,4 @@
1
+ import { PieChartProps } from "./chart.types.js";
2
+ //#region src/native/analytics/pie-chart.ios.d.ts
3
+ export declare function PieChart({ data, donut, height, style }: PieChartProps): import("react").JSX.Element;
4
+ //#endregion
@@ -0,0 +1,24 @@
1
+ import { useChartPalette } from "../lib/chart-palette.js";
2
+ import { Chart, Host } from "@expo/ui/swift-ui";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region src/native/analytics/pie-chart.ios.tsx
6
+ function PieChart({ data, donut, height = 220, style }) {
7
+ const palette = useChartPalette();
8
+ return /* @__PURE__ */ jsx(Host, {
9
+ style: [{ height }, style],
10
+ children: /* @__PURE__ */ jsx(Chart, {
11
+ data: data.map((slice, index) => ({
12
+ x: slice.label,
13
+ y: slice.value,
14
+ color: slice.color ?? palette[index % palette.length]
15
+ })),
16
+ type: "pie",
17
+ animate: true,
18
+ pieStyle: donut ? { innerRadius: .6 } : void 0
19
+ })
20
+ });
21
+ }
22
+
23
+ //#endregion
24
+ export { PieChart };
@@ -0,0 +1,92 @@
1
+ import { useTokenColor } from "../lib/token-color.js";
2
+ import { useChartPalette } from "../lib/chart-palette.js";
3
+ import { Text as Text$2 } from "../base/text.js";
4
+ import { View } from "react-native";
5
+ import { jsx } from "react/jsx-runtime";
6
+ import Svg, { Circle, Path } from "react-native-svg";
7
+
8
+ //#region src/native/analytics/pie-chart.tsx
9
+ /**
10
+ * Pie chart (react-native-svg). The default implementation for Android and web. The iOS SwiftUI Charts version (`pie-chart.ios.tsx`)
11
+ * needs `@expo/ui`, so iOS is drawn with this implementation too unless the app imports that file explicitly.
12
+ *
13
+ * Drawing uses the same react-native-svg as `multi-line-chart`. It is **not** an "iOS only"
14
+ * placeholder because a screen's main content can be produced by this component alone,
15
+ * and on Android that content would be replaced entirely by a text message.
16
+ *
17
+ * **No legend here.** Consumers are expected to list the colored breakdown below the circle,
18
+ * so a legend here would show the same thing twice and eat into the circle's height.
19
+ */
20
+ function PieChart({ data, donut, height = 220, style, accessibilityLabel }) {
21
+ const palette = useChartPalette();
22
+ const fallbackColor = useTokenColor("--chart-1");
23
+ const total = data.reduce((sum, slice) => sum + Math.max(slice.value, 0), 0);
24
+ const colorOf = (slice, index) => slice.color ?? palette[index % palette.length] ?? fallbackColor;
25
+ const size = height;
26
+ const radius = size / 2;
27
+ const inner = donut ? radius * .6 : 0;
28
+ return /* @__PURE__ */ jsx(View, {
29
+ style,
30
+ ...accessibilityLabel === void 0 ? {} : {
31
+ accessible: true,
32
+ accessibilityRole: "image",
33
+ accessibilityLabel
34
+ },
35
+ children: /* @__PURE__ */ jsx(View, {
36
+ style: { height: size },
37
+ className: "items-center justify-center",
38
+ children: total > 0 ? /* @__PURE__ */ jsx(Svg, {
39
+ width: size,
40
+ height: size,
41
+ viewBox: `0 0 ${size} ${size}`,
42
+ children: data.length === 1 && data[0] ? /* @__PURE__ */ jsx(Circle, {
43
+ cx: radius,
44
+ cy: radius,
45
+ r: (radius + inner) / 2,
46
+ stroke: colorOf(data[0], 0),
47
+ strokeWidth: radius - inner,
48
+ fill: "none"
49
+ }) : slicePaths(data, total, radius, inner).map(({ slice, d }, index) => /* @__PURE__ */ jsx(Path, {
50
+ d,
51
+ fill: colorOf(slice, index)
52
+ }, slice.label))
53
+ }) : /* @__PURE__ */ jsx(Text$2, {
54
+ className: "text-muted-foreground text-sm",
55
+ children: "–"
56
+ })
57
+ })
58
+ });
59
+ }
60
+ /** Turns each slice into an SVG path. Slices run clockwise from 12 o'clock (the same direction as SwiftUI Charts). */
61
+ function slicePaths(data, total, radius, inner) {
62
+ let angle = -Math.PI / 2;
63
+ return data.map((slice) => {
64
+ const sweep = Math.max(slice.value, 0) / total * Math.PI * 2;
65
+ const end = angle + sweep;
66
+ const large = sweep > Math.PI ? 1 : 0;
67
+ const outerStart = point(radius, radius, radius, angle);
68
+ const outerEnd = point(radius, radius, radius, end);
69
+ const innerEnd = point(radius, radius, inner, end);
70
+ const innerStart = point(radius, radius, inner, angle);
71
+ angle = end;
72
+ return {
73
+ slice,
74
+ d: [
75
+ `M ${outerStart.x} ${outerStart.y}`,
76
+ `A ${radius} ${radius} 0 ${large} 1 ${outerEnd.x} ${outerEnd.y}`,
77
+ `L ${innerEnd.x} ${innerEnd.y}`,
78
+ inner > 0 ? `A ${inner} ${inner} 0 ${large} 0 ${innerStart.x} ${innerStart.y}` : "",
79
+ "Z"
80
+ ].filter(Boolean).join(" ")
81
+ };
82
+ });
83
+ }
84
+ function point(cx, cy, r, angle) {
85
+ return {
86
+ x: cx + r * Math.cos(angle),
87
+ y: cy + r * Math.sin(angle)
88
+ };
89
+ }
90
+
91
+ //#endregion
92
+ export { PieChart };
@@ -0,0 +1,19 @@
1
+ //#region src/native/analytics/single-number.d.ts
2
+ export type SingleNumberProps = {
3
+ title: string;
4
+ subTitle?: string;
5
+ value: number | null;
6
+ unit?: string;
7
+ /** Value to compare against. When given, the difference and the percentage change are shown alongside. */
8
+ compareValue?: number;
9
+ compareTitle?: string;
10
+ /** Flips the colors for metrics where an increase is bad (cost, etc.). */
11
+ reverseColor?: boolean;
12
+ className?: string;
13
+ };
14
+ /**
15
+ * A metric showing a large number on a raised surface (surface corner radius, 1px hairline border).
16
+ * Mirrors the web analytics single-number. Increase/decrease uses the state colors (the surface does not invert, so the same theme values work).
17
+ */
18
+ export declare function SingleNumber({ title, subTitle, value, unit, compareValue, compareTitle, reverseColor, className }: SingleNumberProps): import("react").JSX.Element;
19
+ //#endregion