@lt-three/love3 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 (378) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -2
  3. package/dist/native/analytics/animation.d.ts +4 -0
  4. package/dist/native/analytics/animation.js +6 -0
  5. package/dist/native/analytics/chart.types.d.ts +25 -0
  6. package/dist/native/analytics/chart.types.js +0 -0
  7. package/dist/native/analytics/line-chart.d.ts +4 -0
  8. package/dist/native/analytics/line-chart.ios.d.ts +4 -0
  9. package/dist/native/analytics/line-chart.ios.js +24 -0
  10. package/dist/native/analytics/line-chart.js +33 -0
  11. package/dist/native/analytics/metric-card.d.ts +10 -0
  12. package/dist/native/analytics/metric-card.js +29 -0
  13. package/dist/native/analytics/multi-line-chart.d.ts +17 -0
  14. package/dist/native/analytics/multi-line-chart.js +215 -0
  15. package/dist/native/analytics/pie-chart.d.ts +15 -0
  16. package/dist/native/analytics/pie-chart.ios.d.ts +4 -0
  17. package/dist/native/analytics/pie-chart.ios.js +24 -0
  18. package/dist/native/analytics/pie-chart.js +92 -0
  19. package/dist/native/analytics/single-number.d.ts +19 -0
  20. package/dist/native/analytics/single-number.js +101 -0
  21. package/dist/native/atom/avatar.d.ts +21 -0
  22. package/dist/native/atom/avatar.js +46 -0
  23. package/dist/native/atom/badge.d.ts +28 -0
  24. package/dist/native/atom/badge.js +51 -0
  25. package/dist/native/atom/button.d.ts +46 -0
  26. package/dist/native/atom/button.js +109 -0
  27. package/dist/native/atom/checkbox.d.ts +21 -0
  28. package/dist/native/atom/checkbox.js +47 -0
  29. package/dist/native/atom/colored-value.d.ts +12 -0
  30. package/dist/native/atom/colored-value.js +24 -0
  31. package/dist/native/atom/image.d.ts +21 -0
  32. package/dist/native/atom/image.js +72 -0
  33. package/dist/native/atom/label.d.ts +18 -0
  34. package/dist/native/atom/label.js +33 -0
  35. package/dist/native/atom/link.d.ts +18 -0
  36. package/dist/native/atom/link.js +25 -0
  37. package/dist/native/atom/readout.d.ts +22 -0
  38. package/dist/native/atom/readout.js +39 -0
  39. package/dist/native/atom/search-input.d.ts +12 -0
  40. package/dist/native/atom/search-input.js +36 -0
  41. package/dist/native/atom/select.d.ts +54 -0
  42. package/dist/native/atom/select.js +200 -0
  43. package/dist/native/atom/separator.d.ts +13 -0
  44. package/dist/native/atom/separator.js +17 -0
  45. package/dist/native/atom/skeleton.d.ts +12 -0
  46. package/dist/native/atom/skeleton.js +39 -0
  47. package/dist/native/atom/slider.d.ts +32 -0
  48. package/dist/native/atom/slider.js +75 -0
  49. package/dist/native/atom/spinner.d.ts +15 -0
  50. package/dist/native/atom/spinner.js +25 -0
  51. package/dist/native/atom/switch.d.ts +18 -0
  52. package/dist/native/atom/switch.js +52 -0
  53. package/dist/native/atom/symbol.d.ts +16 -0
  54. package/dist/native/atom/symbol.js +38 -0
  55. package/dist/native/atom/symbol.types.d.ts +25 -0
  56. package/dist/native/atom/symbol.types.js +49 -0
  57. package/dist/native/atom/text-field.d.ts +49 -0
  58. package/dist/native/atom/text-field.js +56 -0
  59. package/dist/native/atom/text.d.ts +2 -0
  60. package/dist/native/atom/text.js +3 -0
  61. package/dist/native/atom/theme-toggle.d.ts +21 -0
  62. package/dist/native/atom/theme-toggle.js +36 -0
  63. package/dist/native/atom/timezone-select.d.ts +16 -0
  64. package/dist/native/atom/timezone-select.js +28 -0
  65. package/dist/native/atom/typography.d.ts +13 -0
  66. package/dist/native/atom/typography.js +28 -0
  67. package/dist/native/base/button.d.ts +61 -0
  68. package/dist/native/base/button.js +92 -0
  69. package/dist/native/base/form.d.ts +72 -0
  70. package/dist/native/base/form.js +113 -0
  71. package/dist/native/base/glass-card.d.ts +15 -0
  72. package/dist/native/base/glass-card.js +38 -0
  73. package/dist/native/base/input.d.ts +29 -0
  74. package/dist/native/base/input.js +27 -0
  75. package/dist/native/base/sheet.d.ts +71 -0
  76. package/dist/native/base/sheet.js +187 -0
  77. package/dist/native/base/text.d.ts +14 -0
  78. package/dist/native/base/text.js +53 -0
  79. package/dist/native/form/checkbox.d.ts +13 -0
  80. package/dist/native/form/checkbox.js +55 -0
  81. package/dist/native/form/date-picker.d.ts +23 -0
  82. package/dist/native/form/date-picker.js +119 -0
  83. package/dist/native/form/form.d.ts +23 -0
  84. package/dist/native/form/form.js +45 -0
  85. package/dist/native/form/radio-group.d.ts +23 -0
  86. package/dist/native/form/radio-group.js +88 -0
  87. package/dist/native/form/select.d.ts +13 -0
  88. package/dist/native/form/select.js +45 -0
  89. package/dist/native/form/slider.d.ts +14 -0
  90. package/dist/native/form/slider.js +42 -0
  91. package/dist/native/form/switch.d.ts +9 -0
  92. package/dist/native/form/switch.js +59 -0
  93. package/dist/native/form/text-area.d.ts +11 -0
  94. package/dist/native/form/text-area.js +50 -0
  95. package/dist/native/form/text-input.d.ts +18 -0
  96. package/dist/native/form/text-input.js +90 -0
  97. package/dist/native/index.d.ts +1 -0
  98. package/dist/native/index.js +0 -0
  99. package/dist/native/layout/accordion.d.ts +25 -0
  100. package/dist/native/layout/accordion.js +54 -0
  101. package/dist/native/layout/card.d.ts +47 -0
  102. package/dist/native/layout/card.js +57 -0
  103. package/dist/native/layout/description.d.ts +16 -0
  104. package/dist/native/layout/description.js +32 -0
  105. package/dist/native/layout/error.d.ts +21 -0
  106. package/dist/native/layout/error.js +44 -0
  107. package/dist/native/layout/information.d.ts +25 -0
  108. package/dist/native/layout/information.js +35 -0
  109. package/dist/native/layout/locked.d.ts +38 -0
  110. package/dist/native/layout/locked.js +94 -0
  111. package/dist/native/layout/modal.d.ts +25 -0
  112. package/dist/native/layout/modal.js +93 -0
  113. package/dist/native/layout/not-found.d.ts +17 -0
  114. package/dist/native/layout/not-found.js +30 -0
  115. package/dist/native/layout/page-frame.d.ts +23 -0
  116. package/dist/native/layout/page-frame.js +46 -0
  117. package/dist/native/layout/panel.d.ts +18 -0
  118. package/dist/native/layout/panel.js +23 -0
  119. package/dist/native/layout/reorderable-list.d.ts +42 -0
  120. package/dist/native/layout/reorderable-list.js +52 -0
  121. package/dist/native/layout/sheet.d.ts +30 -0
  122. package/dist/native/layout/sheet.js +46 -0
  123. package/dist/native/layout/simple-dialog.d.ts +16 -0
  124. package/dist/native/layout/simple-dialog.js +20 -0
  125. package/dist/native/layout/simple-table.d.ts +50 -0
  126. package/dist/native/layout/simple-table.js +75 -0
  127. package/dist/native/layout/tab-bar.d.ts +33 -0
  128. package/dist/native/layout/tab-bar.js +48 -0
  129. package/dist/native/layout/tabs.d.ts +28 -0
  130. package/dist/native/layout/tabs.js +54 -0
  131. package/dist/native/layout/tuning-panel.d.ts +24 -0
  132. package/dist/native/layout/tuning-panel.js +246 -0
  133. package/dist/native/lib/autocomplete.d.ts +7 -0
  134. package/dist/native/lib/autocomplete.js +34 -0
  135. package/dist/native/lib/breakpoints.d.ts +14 -0
  136. package/dist/native/lib/breakpoints.js +17 -0
  137. package/dist/native/lib/chart-palette.d.ts +8 -0
  138. package/dist/native/lib/chart-palette.js +20 -0
  139. package/dist/native/lib/confirm.d.ts +49 -0
  140. package/dist/native/lib/confirm.js +70 -0
  141. package/dist/native/lib/control.d.ts +24 -0
  142. package/dist/native/lib/control.js +0 -0
  143. package/dist/native/lib/external-store.d.ts +17 -0
  144. package/dist/native/lib/external-store.js +30 -0
  145. package/dist/native/lib/keyboard.d.ts +15 -0
  146. package/dist/native/lib/keyboard.js +24 -0
  147. package/dist/native/lib/labels.d.ts +15 -0
  148. package/dist/native/lib/labels.js +17 -0
  149. package/dist/native/lib/loading.d.ts +10 -0
  150. package/dist/native/lib/loading.js +15 -0
  151. package/dist/native/lib/network.d.ts +12 -0
  152. package/dist/native/lib/network.js +21 -0
  153. package/dist/native/lib/scheme.d.ts +18 -0
  154. package/dist/native/lib/scheme.js +22 -0
  155. package/dist/native/lib/snackbar.d.ts +46 -0
  156. package/dist/native/lib/snackbar.js +60 -0
  157. package/dist/native/lib/theme.d.ts +34 -0
  158. package/dist/native/lib/theme.js +53 -0
  159. package/dist/native/lib/timezone.d.ts +26 -0
  160. package/dist/native/lib/timezone.js +95 -0
  161. package/dist/native/lib/token-color.d.ts +5 -0
  162. package/dist/native/lib/token-color.js +13 -0
  163. package/dist/native/lib/token-color.web.d.ts +4 -0
  164. package/dist/native/lib/token-color.web.js +7 -0
  165. package/dist/native/lib/tuning-context.d.ts +9 -0
  166. package/dist/native/lib/tuning-context.js +7 -0
  167. package/dist/native/lib/tuning.d.ts +24 -0
  168. package/dist/native/lib/tuning.js +42 -0
  169. package/dist/native/lib/typography.d.ts +10 -0
  170. package/dist/native/lib/typography.js +11 -0
  171. package/dist/native/lib/utils.d.ts +11 -0
  172. package/dist/native/lib/utils.js +21 -0
  173. package/dist/native/once/confirm.d.ts +7 -0
  174. package/dist/native/once/confirm.js +60 -0
  175. package/dist/native/once/error-boundary.d.ts +28 -0
  176. package/dist/native/once/error-boundary.js +55 -0
  177. package/dist/native/once/loading-lock.d.ts +8 -0
  178. package/dist/native/once/loading-lock.js +28 -0
  179. package/dist/native/once/offline-banner.d.ts +15 -0
  180. package/dist/native/once/offline-banner.js +35 -0
  181. package/dist/native/once/snackbar.d.ts +17 -0
  182. package/dist/native/once/snackbar.js +106 -0
  183. package/dist/native/styles.css +46 -0
  184. package/dist/shared/analytics.d.ts +71 -0
  185. package/dist/shared/analytics.js +0 -0
  186. package/dist/shared/button.d.ts +7 -0
  187. package/dist/shared/button.js +23 -0
  188. package/dist/shared/form.d.ts +45 -0
  189. package/dist/shared/form.js +46 -0
  190. package/dist/shared/index.d.ts +3 -0
  191. package/dist/shared/index.js +3 -0
  192. package/dist/tokens/contrast-pairs.d.ts +30 -0
  193. package/dist/tokens/contrast-pairs.js +404 -0
  194. package/dist/tokens/index.d.ts +6 -0
  195. package/dist/tokens/index.js +10 -0
  196. package/dist/tokens/styles.gen.css +250 -0
  197. package/dist/tokens/tokens.gen.d.ts +141 -0
  198. package/dist/tokens/tokens.gen.js +206 -0
  199. package/dist/tuning/catalog.d.ts +27 -0
  200. package/dist/tuning/catalog.gen.d.ts +4 -0
  201. package/dist/tuning/catalog.gen.js +397 -0
  202. package/dist/tuning/catalog.js +128 -0
  203. package/dist/tuning/color.d.ts +20 -0
  204. package/dist/tuning/color.js +80 -0
  205. package/dist/tuning/css.d.ts +35 -0
  206. package/dist/tuning/css.js +147 -0
  207. package/dist/tuning/index.d.ts +8 -0
  208. package/dist/tuning/index.js +9 -0
  209. package/dist/tuning/model.d.ts +33 -0
  210. package/dist/tuning/model.js +154 -0
  211. package/dist/tuning/native.d.ts +35 -0
  212. package/dist/tuning/native.js +80 -0
  213. package/dist/tuning/schema.d.ts +69 -0
  214. package/dist/tuning/schema.js +247 -0
  215. package/dist/tuning/types.d.ts +75 -0
  216. package/dist/tuning/types.js +39 -0
  217. package/dist/web/analytics/line-chart.d.ts +20 -0
  218. package/dist/web/analytics/line-chart.js +28 -0
  219. package/dist/web/analytics/metric-card.d.ts +18 -0
  220. package/dist/web/analytics/metric-card.js +40 -0
  221. package/dist/web/analytics/multi-line-chart.d.ts +39 -0
  222. package/dist/web/analytics/multi-line-chart.js +345 -0
  223. package/dist/web/atom/avatar.d.ts +11 -0
  224. package/dist/web/atom/avatar.js +24 -0
  225. package/dist/web/atom/badge.d.ts +2 -0
  226. package/dist/web/atom/badge.js +3 -0
  227. package/dist/web/atom/button.d.ts +23 -0
  228. package/dist/web/atom/button.js +35 -0
  229. package/dist/web/atom/checkbox.d.ts +19 -0
  230. package/dist/web/atom/checkbox.js +33 -0
  231. package/dist/web/atom/colored-value.d.ts +13 -0
  232. package/dist/web/atom/colored-value.js +24 -0
  233. package/dist/web/atom/help.d.ts +10 -0
  234. package/dist/web/atom/help.js +18 -0
  235. package/dist/web/atom/label.d.ts +2 -0
  236. package/dist/web/atom/label.js +3 -0
  237. package/dist/web/atom/segmented-control.d.ts +40 -0
  238. package/dist/web/atom/segmented-control.js +43 -0
  239. package/dist/web/atom/select.d.ts +43 -0
  240. package/dist/web/atom/select.js +93 -0
  241. package/dist/web/atom/separator.d.ts +2 -0
  242. package/dist/web/atom/separator.js +3 -0
  243. package/dist/web/atom/skeleton.d.ts +2 -0
  244. package/dist/web/atom/skeleton.js +3 -0
  245. package/dist/web/atom/slider.d.ts +33 -0
  246. package/dist/web/atom/slider.js +70 -0
  247. package/dist/web/atom/spinner.d.ts +8 -0
  248. package/dist/web/atom/spinner.js +14 -0
  249. package/dist/web/atom/switch.d.ts +11 -0
  250. package/dist/web/atom/switch.js +10 -0
  251. package/dist/web/atom/text-area.d.ts +22 -0
  252. package/dist/web/atom/text-area.js +26 -0
  253. package/dist/web/atom/text-field.d.ts +17 -0
  254. package/dist/web/atom/text-field.js +21 -0
  255. package/dist/web/atom/toggle-chip.d.ts +22 -0
  256. package/dist/web/atom/toggle-chip.js +28 -0
  257. package/dist/web/atom/tooltip.d.ts +23 -0
  258. package/dist/web/atom/tooltip.js +26 -0
  259. package/dist/web/atom/typography.d.ts +6 -0
  260. package/dist/web/atom/typography.js +23 -0
  261. package/dist/web/base/accordion.d.ts +9 -0
  262. package/dist/web/base/accordion.js +44 -0
  263. package/dist/web/base/alert.d.ts +11 -0
  264. package/dist/web/base/alert.js +37 -0
  265. package/dist/web/base/avatar.d.ts +8 -0
  266. package/dist/web/base/avatar.js +29 -0
  267. package/dist/web/base/badge.d.ts +12 -0
  268. package/dist/web/base/badge.js +26 -0
  269. package/dist/web/base/breadcrumb.d.ts +16 -0
  270. package/dist/web/base/breadcrumb.js +72 -0
  271. package/dist/web/base/button.d.ts +12 -0
  272. package/dist/web/base/button.js +47 -0
  273. package/dist/web/base/card.d.ts +19 -0
  274. package/dist/web/base/card.js +74 -0
  275. package/dist/web/base/checkbox.d.ts +6 -0
  276. package/dist/web/base/checkbox.js +21 -0
  277. package/dist/web/base/dialog.d.ts +20 -0
  278. package/dist/web/base/dialog.js +92 -0
  279. package/dist/web/base/dropdown-menu.d.ts +29 -0
  280. package/dist/web/base/dropdown-menu.js +125 -0
  281. package/dist/web/base/field.d.ts +27 -0
  282. package/dist/web/base/field.js +118 -0
  283. package/dist/web/base/form.d.ts +38 -0
  284. package/dist/web/base/form.js +110 -0
  285. package/dist/web/base/input.d.ts +9 -0
  286. package/dist/web/base/input.js +23 -0
  287. package/dist/web/base/label.d.ts +6 -0
  288. package/dist/web/base/label.js +15 -0
  289. package/dist/web/base/pagination.d.ts +34 -0
  290. package/dist/web/base/pagination.js +90 -0
  291. package/dist/web/base/popover.d.ts +11 -0
  292. package/dist/web/base/popover.js +37 -0
  293. package/dist/web/base/radio-group.d.ts +7 -0
  294. package/dist/web/base/radio-group.js +27 -0
  295. package/dist/web/base/scroll-area.d.ts +10 -0
  296. package/dist/web/base/scroll-area.js +41 -0
  297. package/dist/web/base/select.d.ts +17 -0
  298. package/dist/web/base/select.js +96 -0
  299. package/dist/web/base/separator.d.ts +6 -0
  300. package/dist/web/base/separator.js +17 -0
  301. package/dist/web/base/sheet.d.ts +19 -0
  302. package/dist/web/base/sheet.js +88 -0
  303. package/dist/web/base/skeleton.d.ts +5 -0
  304. package/dist/web/base/skeleton.js +14 -0
  305. package/dist/web/base/slider.d.ts +9 -0
  306. package/dist/web/base/slider.js +39 -0
  307. package/dist/web/base/sonner.d.ts +9 -0
  308. package/dist/web/base/sonner.js +25 -0
  309. package/dist/web/base/spinner.d.ts +5 -0
  310. package/dist/web/base/spinner.js +17 -0
  311. package/dist/web/base/switch.d.ts +6 -0
  312. package/dist/web/base/switch.js +19 -0
  313. package/dist/web/base/table.d.ts +14 -0
  314. package/dist/web/base/table.js +68 -0
  315. package/dist/web/base/tabs.d.ts +9 -0
  316. package/dist/web/base/tabs.js +36 -0
  317. package/dist/web/base/textarea.d.ts +9 -0
  318. package/dist/web/base/textarea.js +23 -0
  319. package/dist/web/base/tooltip.d.ts +9 -0
  320. package/dist/web/base/tooltip.js +36 -0
  321. package/dist/web/form/checkbox.d.ts +35 -0
  322. package/dist/web/form/checkbox.js +91 -0
  323. package/dist/web/form/radio-group.d.ts +24 -0
  324. package/dist/web/form/radio-group.js +75 -0
  325. package/dist/web/form/select.d.ts +16 -0
  326. package/dist/web/form/select.js +44 -0
  327. package/dist/web/form/slider.d.ts +19 -0
  328. package/dist/web/form/slider.js +51 -0
  329. package/dist/web/form/switch.d.ts +11 -0
  330. package/dist/web/form/switch.js +50 -0
  331. package/dist/web/form/text-area.d.ts +10 -0
  332. package/dist/web/form/text-area.js +31 -0
  333. package/dist/web/form/text-input.d.ts +10 -0
  334. package/dist/web/form/text-input.js +42 -0
  335. package/dist/web/index.d.ts +1 -0
  336. package/dist/web/index.js +0 -0
  337. package/dist/web/layout/accordion.d.ts +26 -0
  338. package/dist/web/layout/accordion.js +29 -0
  339. package/dist/web/layout/alert-modal.d.ts +41 -0
  340. package/dist/web/layout/alert-modal.js +71 -0
  341. package/dist/web/layout/card.d.ts +17 -0
  342. package/dist/web/layout/card.js +35 -0
  343. package/dist/web/layout/description.d.ts +12 -0
  344. package/dist/web/layout/description.js +20 -0
  345. package/dist/web/layout/information.d.ts +36 -0
  346. package/dist/web/layout/information.js +53 -0
  347. package/dist/web/layout/modal.d.ts +16 -0
  348. package/dist/web/layout/modal.js +37 -0
  349. package/dist/web/layout/page-frame.d.ts +37 -0
  350. package/dist/web/layout/page-frame.js +79 -0
  351. package/dist/web/layout/scroll-area.d.ts +10 -0
  352. package/dist/web/layout/scroll-area.js +13 -0
  353. package/dist/web/layout/sheet.d.ts +32 -0
  354. package/dist/web/layout/sheet.js +68 -0
  355. package/dist/web/layout/simple-dialog.d.ts +11 -0
  356. package/dist/web/layout/simple-dialog.js +24 -0
  357. package/dist/web/layout/simple-table.d.ts +49 -0
  358. package/dist/web/layout/simple-table.js +58 -0
  359. package/dist/web/layout/tabs.d.ts +26 -0
  360. package/dist/web/layout/tabs.js +42 -0
  361. package/dist/web/layout/titled-modal.d.ts +33 -0
  362. package/dist/web/layout/titled-modal.js +59 -0
  363. package/dist/web/lib/css-vars.d.ts +14 -0
  364. package/dist/web/lib/css-vars.js +18 -0
  365. package/dist/web/lib/dialog.d.ts +13 -0
  366. package/dist/web/lib/dialog.js +0 -0
  367. package/dist/web/lib/form.d.ts +2 -0
  368. package/dist/web/lib/form.js +3 -0
  369. package/dist/web/lib/labels.d.ts +27 -0
  370. package/dist/web/lib/labels.js +29 -0
  371. package/dist/web/lib/modal-open-focus.d.ts +17 -0
  372. package/dist/web/lib/modal-open-focus.js +44 -0
  373. package/dist/web/lib/restore-focus.d.ts +12 -0
  374. package/dist/web/lib/restore-focus.js +32 -0
  375. package/dist/web/lib/utils.d.ts +4 -0
  376. package/dist/web/lib/utils.js +10 -0
  377. package/dist/web/styles.css +162 -0
  378. package/package.json +205 -4
@@ -0,0 +1,48 @@
1
+ import { useTokenColor } from "../lib/token-color.js";
2
+ import { cn } from "../lib/utils.js";
3
+ import { Text as Text$1 } from "../base/text.js";
4
+ import { Pressable, View } from "react-native";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+
7
+ //#region src/native/layout/tab-bar.tsx
8
+ /**
9
+ * 画面の下に置く、トップレベルの行き先の切り替え(3〜5 件)。`layout/tabs`(本文を切り替える下線タブ)とは別物。
10
+ * 選択中は `text-action-ink`(暗い面でも AA)で、選択状態は色だけにせず太さ(`font-semibold`)でも示す。
11
+ * 1 件の押す範囲は高さ 56px 以上(実機の 44pt 基準を上回る)。**下端の安全領域(ホームインジケータ)はアプリが持つ**
12
+ * (`className` に `pb-*` を渡すか、外側の `SafeAreaView` に置く)。
13
+ */
14
+ function TabBar({ items, value, onValueChange, accessibilityLabel = "メイン", className }) {
15
+ const activeColor = useTokenColor("--action-ink");
16
+ const inactiveColor = useTokenColor("--muted-foreground");
17
+ return /* @__PURE__ */ jsx(View, {
18
+ role: "navigation",
19
+ "aria-label": accessibilityLabel,
20
+ className: cn("border-line bg-card border-t", className),
21
+ children: /* @__PURE__ */ jsx(View, {
22
+ role: "tablist",
23
+ className: "flex-row",
24
+ children: items.map((item) => {
25
+ const active = item.value === value;
26
+ const color = active ? activeColor : inactiveColor;
27
+ return /* @__PURE__ */ jsxs(Pressable, {
28
+ role: "tab",
29
+ "aria-selected": active,
30
+ "aria-label": item.label,
31
+ onPress: () => onValueChange(item.value),
32
+ className: "min-h-14 flex-1 items-center justify-center gap-1 px-2 py-2",
33
+ children: [item.icon ? item.icon({
34
+ active,
35
+ color
36
+ }) : null, /* @__PURE__ */ jsx(Text$1, {
37
+ numberOfLines: 1,
38
+ className: cn("text-xs", active ? "text-action-ink font-semibold" : "text-muted-foreground font-normal"),
39
+ children: item.label
40
+ })]
41
+ }, item.value);
42
+ })
43
+ })
44
+ });
45
+ }
46
+
47
+ //#endregion
48
+ export { TabBar };
@@ -0,0 +1,28 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/native/layout/tabs.d.ts
3
+ export type TabType = {
4
+ [value: string]: {
5
+ name: string;
6
+ render?: () => ReactNode;
7
+ onSelect?: () => void;
8
+ };
9
+ };
10
+ export type TabsProps = {
11
+ tabs: TabType;
12
+ defaultValue?: string;
13
+ /** 制御モード: 外部から選択値を管理する場合に指定する。 */
14
+ value?: string;
15
+ onValueChange?: (value: string) => void;
16
+ /** タブ列と同じ行の右端に置くスロット(ツールバー的に使う)。 */
17
+ trailing?: ReactNode;
18
+ className?: string;
19
+ };
20
+ /**
21
+ * `@lt-three/web` の layout/tabs と同じレコード駆動の API を持つタブ。
22
+ * 見た目は web の base/tabs に揃えたフラッシュレフトの下線タブで、
23
+ * 共有の薄い罫線の上にアクティブの 2px インディゴ下線が乗る。
24
+ *
25
+ * タブ数が増えても折り返さないよう横スクロールする(web の `flex-wrap` の代わり)。
26
+ */
27
+ export declare function Tabs({ tabs, defaultValue, value, onValueChange, trailing, className }: TabsProps): import("react").JSX.Element;
28
+ //#endregion
@@ -0,0 +1,54 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { Text as Text$1 } from "../base/text.js";
3
+ import { useState } from "react";
4
+ import { Pressable, ScrollView, View } from "react-native";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+
7
+ //#region src/native/layout/tabs.tsx
8
+ /**
9
+ * `@lt-three/web` の layout/tabs と同じレコード駆動の API を持つタブ。
10
+ * 見た目は web の base/tabs に揃えたフラッシュレフトの下線タブで、
11
+ * 共有の薄い罫線の上にアクティブの 2px インディゴ下線が乗る。
12
+ *
13
+ * タブ数が増えても折り返さないよう横スクロールする(web の `flex-wrap` の代わり)。
14
+ */
15
+ function Tabs({ tabs, defaultValue, value, onValueChange, trailing, className }) {
16
+ const keys = Object.keys(tabs);
17
+ const [internalValue, setInternalValue] = useState(defaultValue ?? keys[0] ?? "");
18
+ const active = value ?? internalValue;
19
+ const select = (next) => {
20
+ tabs[next]?.onSelect?.();
21
+ onValueChange?.(next);
22
+ if (value === void 0) setInternalValue(next);
23
+ };
24
+ const hasContent = Object.values(tabs).some((tab) => tab.render);
25
+ return /* @__PURE__ */ jsxs(View, {
26
+ className: cn(hasContent && "gap-4", className),
27
+ children: [/* @__PURE__ */ jsxs(View, {
28
+ role: "tablist",
29
+ className: "flex-row items-center border-b border-line",
30
+ children: [/* @__PURE__ */ jsx(ScrollView, {
31
+ horizontal: true,
32
+ showsHorizontalScrollIndicator: false,
33
+ contentContainerStyle: { gap: 24 },
34
+ children: keys.map((key) => {
35
+ const on = key === active;
36
+ return /* @__PURE__ */ jsxs(Pressable, {
37
+ role: "tab",
38
+ "aria-selected": on,
39
+ onPress: () => select(key),
40
+ className: "-mb-px pb-2.5",
41
+ hitSlop: 12,
42
+ children: [/* @__PURE__ */ jsx(Text$1, {
43
+ className: cn("text-sm", on ? "text-foreground font-medium" : "text-muted-foreground font-normal"),
44
+ children: tabs[key]?.name
45
+ }), on ? /* @__PURE__ */ jsx(View, { className: "absolute inset-x-0 bottom-0 h-0.5 bg-action" }) : null]
46
+ }, key);
47
+ })
48
+ }), trailing]
49
+ }), hasContent ? tabs[active]?.render?.() : null]
50
+ });
51
+ }
52
+
53
+ //#endregion
54
+ export { Tabs };
@@ -0,0 +1,24 @@
1
+ import { Tuning, TuningCatalog } from "../../tuning/types.js";
2
+ //#region src/native/layout/tuning-panel.d.ts
3
+ export type TuningPanelProps = {
4
+ /** 調整の内容(既定との差分)。保存先はアプリが持つ。 */
5
+ tuning: Tuning;
6
+ onChange: (next: Tuning) => void;
7
+ /** 調整の対象。既定は love3 の生成物。 */
8
+ catalog?: TuningCatalog;
9
+ /** 書き出したとき(コピー・共有などはアプリが決める)。JSON の文字列が渡る。 */
10
+ onExport?: (json: string) => void;
11
+ };
12
+ /**
13
+ * native の調整の画面(最小限)。トークンを動かし、`love3-tuning` の JSON で書き出し・読み込みする。web の `/tuning` と同じ形式。
14
+ *
15
+ * - 色: 今のテーマ(ライト・ダーク)の値を 16 進で編集する。読めない値は赤い枠のままで、適用しない
16
+ * - 角丸: 役割ごとに px(実機ではビルド時に固定されるので効かない。JSON には残る)
17
+ * - JSON: 「書き出す」で今の調整を欄に出し(`onExport` にも渡す)、「読み込む」で欄の JSON を検証して適用する。
18
+ * 1 つでも不正なら全体を断り、理由を出す(部分適用しない)
19
+ * - 実機で効かない項目は、`nativeLimits` の説明を出す
20
+ *
21
+ * 作り込みはしない(love3 の native 部品だけで組んだ検証用)。
22
+ */
23
+ export declare function TuningPanel({ tuning, onChange, catalog, onExport }: TuningPanelProps): import("react").JSX.Element;
24
+ //#endregion
@@ -0,0 +1,246 @@
1
+ import { catalog } from "../../tuning/catalog.gen.js";
2
+ import { parseTokenColor } from "../../tuning/color.js";
3
+ import { RADIUS_MAX, RADIUS_ROLES, emptyTuning } from "../../tuning/types.js";
4
+ import { colorValue, countChanges, normalize, withColor, withRadius } from "../../tuning/model.js";
5
+ import { nativeLimits } from "../../tuning/native.js";
6
+ import { parseTuning, toJson } from "../../tuning/schema.js";
7
+ import { useActiveScheme } from "../lib/theme.js";
8
+ import { Text as Text$1 } from "../base/text.js";
9
+ import { Panel } from "./panel.js";
10
+ import { Button } from "../atom/button.js";
11
+ import { Label } from "../atom/label.js";
12
+ import { TextField } from "../atom/text-field.js";
13
+ import { useId, useMemo, useState } from "react";
14
+ import { View } from "react-native";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+
17
+ //#region src/native/layout/tuning-panel.tsx
18
+ /** 色の編集に出すトークンの区分(ランプ・主操作・状態・チャート。ブランド色は共通なので別)。 */
19
+ const EDITABLE_GROUPS = /* @__PURE__ */ new Set([
20
+ "ramp",
21
+ "action",
22
+ "state",
23
+ "chart"
24
+ ]);
25
+ /**
26
+ * native の調整の画面(最小限)。トークンを動かし、`love3-tuning` の JSON で書き出し・読み込みする。web の `/tuning` と同じ形式。
27
+ *
28
+ * - 色: 今のテーマ(ライト・ダーク)の値を 16 進で編集する。読めない値は赤い枠のままで、適用しない
29
+ * - 角丸: 役割ごとに px(実機ではビルド時に固定されるので効かない。JSON には残る)
30
+ * - JSON: 「書き出す」で今の調整を欄に出し(`onExport` にも渡す)、「読み込む」で欄の JSON を検証して適用する。
31
+ * 1 つでも不正なら全体を断り、理由を出す(部分適用しない)
32
+ * - 実機で効かない項目は、`nativeLimits` の説明を出す
33
+ *
34
+ * 作り込みはしない(love3 の native 部品だけで組んだ検証用)。
35
+ */
36
+ function TuningPanel({ tuning, onChange, catalog: catalog$1 = catalog, onExport }) {
37
+ const scheme = useActiveScheme();
38
+ const normalized = useMemo(() => normalize(tuning, catalog$1), [tuning, catalog$1]);
39
+ const limits = useMemo(() => nativeLimits(tuning, catalog$1), [tuning, catalog$1]);
40
+ const [json, setJson] = useState("");
41
+ const [reasons, setReasons] = useState([]);
42
+ const [epoch, setEpoch] = useState(0);
43
+ const importJson = () => {
44
+ const result = parseTuning(json, catalog$1);
45
+ if (result.ok) {
46
+ setReasons([]);
47
+ setEpoch((value) => value + 1);
48
+ onChange(result.tuning);
49
+ } else setReasons(result.reasons);
50
+ };
51
+ const exportJson = () => {
52
+ const text = toJson(tuning, catalog$1);
53
+ setJson(text);
54
+ setReasons([]);
55
+ onExport?.(text);
56
+ };
57
+ return /* @__PURE__ */ jsxs(Panel, {
58
+ className: "gap-4 p-4",
59
+ children: [
60
+ /* @__PURE__ */ jsxs(View, {
61
+ className: "gap-1",
62
+ children: [/* @__PURE__ */ jsxs(Text$1, {
63
+ role: "heading",
64
+ "aria-level": "2",
65
+ className: "text-base font-semibold",
66
+ children: [
67
+ "調整(",
68
+ scheme === "dark" ? "ダーク" : "ライト",
69
+ ")"
70
+ ]
71
+ }), /* @__PURE__ */ jsxs(Text$1, {
72
+ className: "text-muted-foreground text-sm",
73
+ children: [
74
+ "変えた項目は ",
75
+ countChanges(tuning, catalog$1),
76
+ " 件。書き出した JSON は web の調整ページでも読めます。"
77
+ ]
78
+ })]
79
+ }),
80
+ /* @__PURE__ */ jsxs(View, {
81
+ className: "gap-2",
82
+ children: [/* @__PURE__ */ jsx(Label, { children: "色" }), catalog$1.colors.filter((color) => EDITABLE_GROUPS.has(color.group)).map((color) => /* @__PURE__ */ jsx(ColorRow, {
83
+ name: color.name,
84
+ value: colorValue(normalized, catalog$1, scheme, color.name),
85
+ alpha: color.alpha,
86
+ onCommit: (value) => onChange(withColor(tuning, catalog$1, scheme, color.name, value))
87
+ }, `${color.name}-${epoch}`))]
88
+ }),
89
+ /* @__PURE__ */ jsxs(View, {
90
+ className: "gap-2",
91
+ children: [/* @__PURE__ */ jsx(Label, { children: "角丸(px)" }), RADIUS_ROLES.map((role) => /* @__PURE__ */ jsx(RadiusRow, {
92
+ role,
93
+ value: normalized.radius[role] ?? catalog$1.radius[role],
94
+ onCommit: (px) => onChange(withRadius(tuning, role, px))
95
+ }, `${role}-${epoch}`))]
96
+ }),
97
+ limits.length > 0 ? /* @__PURE__ */ jsx(View, {
98
+ className: "gap-1",
99
+ accessibilityRole: "summary",
100
+ children: limits.map((note) => /* @__PURE__ */ jsx(Text$1, {
101
+ className: "text-muted-foreground text-xs",
102
+ children: note
103
+ }, note))
104
+ }) : null,
105
+ /* @__PURE__ */ jsxs(View, {
106
+ className: "gap-2",
107
+ children: [
108
+ /* @__PURE__ */ jsx(Label, { children: "JSON(love3-tuning)" }),
109
+ /* @__PURE__ */ jsx(TextField, {
110
+ value: json,
111
+ onChangeText: setJson,
112
+ multiline: true,
113
+ numberOfLines: 6,
114
+ autoCapitalize: "none",
115
+ autoCorrect: false,
116
+ accessibilityLabel: "調整の JSON",
117
+ placeholder: "{ \"format\": \"love3-tuning\", \"version\": 1 }",
118
+ invalid: reasons.length > 0
119
+ }),
120
+ reasons.map((reason) => /* @__PURE__ */ jsx(Text$1, {
121
+ role: "alert",
122
+ className: "text-destructive text-xs",
123
+ children: reason
124
+ }, reason)),
125
+ /* @__PURE__ */ jsxs(View, {
126
+ className: "flex-row flex-wrap gap-2",
127
+ children: [
128
+ /* @__PURE__ */ jsx(Button, {
129
+ size: "sm",
130
+ variant: "outline",
131
+ onPress: exportJson,
132
+ children: "書き出す"
133
+ }),
134
+ /* @__PURE__ */ jsx(Button, {
135
+ size: "sm",
136
+ onPress: importJson,
137
+ children: "読み込む"
138
+ }),
139
+ /* @__PURE__ */ jsx(Button, {
140
+ size: "sm",
141
+ variant: "ghost",
142
+ onPress: () => {
143
+ setEpoch((value) => value + 1);
144
+ onChange(emptyTuning());
145
+ },
146
+ children: "すべて既定に戻す"
147
+ })
148
+ ]
149
+ })
150
+ ]
151
+ })
152
+ ]
153
+ });
154
+ }
155
+ /** 入力が読めないときの理由。行の下に `role="alert"` で出し、入力欄から `aria-describedby` で結ぶ。 */
156
+ function Reason({ id, text }) {
157
+ return /* @__PURE__ */ jsx(Text$1, {
158
+ id,
159
+ role: "alert",
160
+ className: "text-destructive text-xs",
161
+ children: text
162
+ });
163
+ }
164
+ /**
165
+ * 色 1 件。**入力中の文字(draft)を自分で持ち、フォーカスが外れるまで欄に出し続ける**(`#abc` は有効な 3 桁の形だが、
166
+ * 6 桁の途中でもある。反映した値で欄を置き換えると、6 桁を打ち切れない)。読める値になったら、打つたびに反映する
167
+ * (反映した値は正規の形 `#aabbcc` になるが、欄には打った文字のまま)。外れたら、反映した値(正規の形)を欄に出す。
168
+ * 読めない値は理由を出し、反映しない。
169
+ */
170
+ function ColorRow({ name, value, alpha, onCommit }) {
171
+ const reasonId = useId();
172
+ const [draft, setDraft] = useState(null);
173
+ const parsed = draft === null ? null : parseTokenColor(draft, { alpha });
174
+ const reason = parsed !== null && !parsed.ok ? parsed.reason : void 0;
175
+ return /* @__PURE__ */ jsxs(View, {
176
+ className: "gap-1",
177
+ children: [/* @__PURE__ */ jsxs(View, {
178
+ className: "flex-row items-center gap-2",
179
+ children: [/* @__PURE__ */ jsxs(Text$1, {
180
+ className: "w-32 font-mono text-xs",
181
+ children: ["--", name]
182
+ }), /* @__PURE__ */ jsx(View, {
183
+ className: "flex-1",
184
+ children: /* @__PURE__ */ jsx(TextField, {
185
+ value: draft ?? value,
186
+ onChangeText: (text) => {
187
+ setDraft(text);
188
+ const next = parseTokenColor(text, { alpha });
189
+ if (next.ok) onCommit(next.value);
190
+ },
191
+ onBlur: () => setDraft(null),
192
+ accessibilityLabel: `--${name}`,
193
+ autoCapitalize: "none",
194
+ autoCorrect: false,
195
+ invalid: reason !== void 0,
196
+ "aria-describedby": reason === void 0 ? void 0 : reasonId
197
+ })
198
+ })]
199
+ }), reason === void 0 ? null : /* @__PURE__ */ jsx(Reason, {
200
+ id: reasonId,
201
+ text: reason
202
+ })]
203
+ });
204
+ }
205
+ /** 角丸の入力の問題(読めて、範囲内なら undefined)。 */
206
+ function radiusProblem(text) {
207
+ const number = Number(text);
208
+ if (text.trim() === "" || !Number.isFinite(number)) return `角丸は数で入力してください(0〜${64})`;
209
+ if (number < 0 || number > 64) return `角丸は 0〜${64} の数で入力してください(実際: ${text})`;
210
+ }
211
+ /** 角丸 1 件。色と同じく、入力中の文字(`6.` など)は外れるまで欄に出し続ける。 */
212
+ function RadiusRow({ role, value, onCommit }) {
213
+ const reasonId = useId();
214
+ const [draft, setDraft] = useState(null);
215
+ const reason = draft === null ? void 0 : radiusProblem(draft);
216
+ return /* @__PURE__ */ jsxs(View, {
217
+ className: "gap-1",
218
+ children: [/* @__PURE__ */ jsxs(View, {
219
+ className: "flex-row items-center gap-2",
220
+ children: [/* @__PURE__ */ jsxs(Text$1, {
221
+ className: "w-32 font-mono text-xs",
222
+ children: ["radius-", role]
223
+ }), /* @__PURE__ */ jsx(View, {
224
+ className: "flex-1",
225
+ children: /* @__PURE__ */ jsx(TextField, {
226
+ value: draft ?? String(value),
227
+ onChangeText: (text) => {
228
+ setDraft(text);
229
+ if (radiusProblem(text) === void 0) onCommit(Number(text));
230
+ },
231
+ onBlur: () => setDraft(null),
232
+ type: "number",
233
+ accessibilityLabel: `radius-${role}`,
234
+ invalid: reason !== void 0,
235
+ "aria-describedby": reason === void 0 ? void 0 : reasonId
236
+ })
237
+ })]
238
+ }), reason === void 0 ? null : /* @__PURE__ */ jsx(Reason, {
239
+ id: reasonId,
240
+ text: reason
241
+ })]
242
+ });
243
+ }
244
+
245
+ //#endregion
246
+ export { TuningPanel };
@@ -0,0 +1,7 @@
1
+ import { TextInputProps } from "react-native";
2
+ //#region src/native/lib/autocomplete.d.ts
3
+ export type AutoComplete = NonNullable<TextInputProps["autoComplete"]>;
4
+ export type TextContentType = NonNullable<TextInputProps["textContentType"]>;
5
+ /** iOS の `textContentType`。対応する語が無ければ `undefined`(iOS の既定に任せる)。 */
6
+ export declare function textContentTypeOf(autoComplete: AutoComplete | undefined): TextContentType | undefined;
7
+ //#endregion
@@ -0,0 +1,34 @@
1
+ //#region src/native/lib/autocomplete.ts
2
+ const CONTENT_TYPE = {
3
+ email: "emailAddress",
4
+ username: "username",
5
+ "username-new": "username",
6
+ "current-password": "password",
7
+ password: "password",
8
+ "new-password": "newPassword",
9
+ "password-new": "newPassword",
10
+ "one-time-code": "oneTimeCode",
11
+ "sms-otp": "oneTimeCode",
12
+ "email-otp": "oneTimeCode",
13
+ tel: "telephoneNumber",
14
+ name: "name",
15
+ "given-name": "givenName",
16
+ "name-given": "givenName",
17
+ "family-name": "familyName",
18
+ "name-family": "familyName",
19
+ "postal-code": "postalCode",
20
+ "street-address": "fullStreetAddress",
21
+ "address-line1": "streetAddressLine1",
22
+ "address-line2": "streetAddressLine2",
23
+ organization: "organizationName",
24
+ url: "URL",
25
+ "cc-number": "creditCardNumber",
26
+ off: "none"
27
+ };
28
+ /** iOS の `textContentType`。対応する語が無ければ `undefined`(iOS の既定に任せる)。 */
29
+ function textContentTypeOf(autoComplete) {
30
+ return autoComplete === void 0 ? void 0 : CONTENT_TYPE[autoComplete];
31
+ }
32
+
33
+ //#endregion
34
+ export { textContentTypeOf };
@@ -0,0 +1,14 @@
1
+ //#region src/native/lib/breakpoints.d.ts
2
+ /** web(Tailwind)と同じブレークポイント(px)。 */
3
+ export declare const BREAKPOINT: {
4
+ readonly sm: 640;
5
+ readonly md: 768;
6
+ readonly lg: 1024;
7
+ };
8
+ export type Breakpoint = keyof typeof BREAKPOINT;
9
+ /**
10
+ * `hideBelow` の列を、この画面の幅で出すか。ブレークポイントちょうどの幅は**出す**(Tailwind の `sm:` は 640px 以上)。
11
+ * 指定が無ければ常に出す。
12
+ */
13
+ export declare function isShownAtWidth(hideBelow: Breakpoint | undefined, width: number): boolean;
14
+ //#endregion
@@ -0,0 +1,17 @@
1
+ //#region src/native/lib/breakpoints.ts
2
+ /** web(Tailwind)と同じブレークポイント(px)。 */
3
+ const BREAKPOINT = {
4
+ sm: 640,
5
+ md: 768,
6
+ lg: 1024
7
+ };
8
+ /**
9
+ * `hideBelow` の列を、この画面の幅で出すか。ブレークポイントちょうどの幅は**出す**(Tailwind の `sm:` は 640px 以上)。
10
+ * 指定が無ければ常に出す。
11
+ */
12
+ function isShownAtWidth(hideBelow, width) {
13
+ return hideBelow === void 0 || width >= BREAKPOINT[hideBelow];
14
+ }
15
+
16
+ //#endregion
17
+ export { BREAKPOINT, isShownAtWidth };
@@ -0,0 +1,8 @@
1
+ //#region src/native/lib/chart-palette.d.ts
2
+ /**
3
+ * チャートの既定配色。web の `--chart-1` 〜 `--chart-5`(色で系列を分ける 5 色。ダークでも読める別の値を持つ)と同じ順序で返す。
4
+ *
5
+ * `--chart-*` は、ライト・ダークで別の値を持つ生の色のトークンなので、そのまま実値を引ける。`.dark` にも追従する。
6
+ */
7
+ export declare function useChartPalette(): string[];
8
+ //#endregion
@@ -0,0 +1,20 @@
1
+ import { useTokenColor } from "./token-color.js";
2
+
3
+ //#region src/native/lib/chart-palette.ts
4
+ /**
5
+ * チャートの既定配色。web の `--chart-1` 〜 `--chart-5`(色で系列を分ける 5 色。ダークでも読める別の値を持つ)と同じ順序で返す。
6
+ *
7
+ * `--chart-*` は、ライト・ダークで別の値を持つ生の色のトークンなので、そのまま実値を引ける。`.dark` にも追従する。
8
+ */
9
+ function useChartPalette() {
10
+ return [
11
+ useTokenColor("--chart-1"),
12
+ useTokenColor("--chart-2"),
13
+ useTokenColor("--chart-3"),
14
+ useTokenColor("--chart-4"),
15
+ useTokenColor("--chart-5")
16
+ ].filter((color) => typeof color === "string");
17
+ }
18
+
19
+ //#endregion
20
+ export { useChartPalette };
@@ -0,0 +1,49 @@
1
+ import { ButtonProps } from "../atom/button.js";
2
+ import { ExternalStore } from "./external-store.js";
3
+ //#region src/native/lib/confirm.d.ts
4
+ export type ConfirmDialogButton = {
5
+ text: string;
6
+ onClick: () => void;
7
+ variant?: ButtonProps["variant"];
8
+ };
9
+ export type ConfirmDialogValue = {
10
+ isOpen: boolean;
11
+ title?: string;
12
+ description?: string;
13
+ buttons?: ConfirmDialogButton[];
14
+ /** 外側を押したとき。未指定なら閉じない。`close` を呼ぶと閉じる。 */
15
+ onOutsideClick?: (close: () => void) => void;
16
+ /**
17
+ * ボタンを押さずに閉じられたとき(Escape・Android の戻る操作など)に描画側が呼ぶ。
18
+ * `confirm()` はこれで false を解決し、待っている呼び出し側が固まらないようにする。
19
+ */
20
+ onDismiss?: () => void;
21
+ };
22
+ /** `ConfirmDialog` が読む状態。命令的な API(`confirm()`)がここへ書く。 */
23
+ export declare const confirmDialogStore: ExternalStore<ConfirmDialogValue>;
24
+ /** 開いている確認ダイアログを閉じる(内容は残す。閉じるアニメーションの間、文字が消えないように)。 */
25
+ export declare function closeConfirmDialog(): void;
26
+ /**
27
+ * `ConfirmDialog` がマウントされている間だけ呼ぶ(`once/confirm` が effect で呼ぶ)。戻り値は解除。
28
+ * **最後の 1 つが外れたとき、開いたままの確認は false で解決して閉じる**(開いたまま unmount すると、待っている呼び出し側が
29
+ * 固まり、次にマウントしたときに古い確認が出てしまう)。
30
+ */
31
+ export declare function registerConfirmDialog(): () => void;
32
+ export type ConfirmOptions = {
33
+ description?: string;
34
+ /** 「はい」側のボタンの文言(既定「はい」)。 */
35
+ yes?: string;
36
+ /** 「いいえ」側のボタンの文言(既定「いいえ」)。 */
37
+ no?: string;
38
+ /** 取り消せない操作の確認では `destructive` を渡し、見た目でも危険だと分かるようにする。 */
39
+ yesVariant?: ButtonProps["variant"];
40
+ };
41
+ /**
42
+ * 確認ダイアログを開き、押されたボタンで解決する(はい = true、いいえ・外側・戻る操作 = false)。
43
+ * アプリのルートに `once/confirm` の `ConfirmDialog` を 1 つ置いておく(**置いていないと、開かず、解決もしない**。開発時は警告を出す。
44
+ * 後から置くと、その時点で開く)。
45
+ * 移植元の `@lt-three/core` の `confirm(i18n, message, options)` から、i18n の引数を外した
46
+ * (love3 は i18n に依存しない。文言は `yes` / `no` で渡し、既定は日本語)。
47
+ */
48
+ export declare function confirm(message: string, options?: ConfirmOptions): Promise<boolean>;
49
+ //#endregion
@@ -0,0 +1,70 @@
1
+ import { NO_LABEL, YES_LABEL } from "./labels.js";
2
+ import { createExternalStore } from "./external-store.js";
3
+
4
+ //#region src/native/lib/confirm.ts
5
+ /** `ConfirmDialog` が読む状態。命令的な API(`confirm()`)がここへ書く。 */
6
+ const confirmDialogStore = createExternalStore({ isOpen: false });
7
+ /** 開いている確認ダイアログを閉じる(内容は残す。閉じるアニメーションの間、文字が消えないように)。 */
8
+ function closeConfirmDialog() {
9
+ confirmDialogStore.update((prev) => ({
10
+ ...prev,
11
+ isOpen: false
12
+ }));
13
+ }
14
+ let mountedDialogs = 0;
15
+ /**
16
+ * `ConfirmDialog` がマウントされている間だけ呼ぶ(`once/confirm` が effect で呼ぶ)。戻り値は解除。
17
+ * **最後の 1 つが外れたとき、開いたままの確認は false で解決して閉じる**(開いたまま unmount すると、待っている呼び出し側が
18
+ * 固まり、次にマウントしたときに古い確認が出てしまう)。
19
+ */
20
+ function registerConfirmDialog() {
21
+ mountedDialogs += 1;
22
+ return () => {
23
+ mountedDialogs -= 1;
24
+ if (mountedDialogs > 0 || !confirmDialogStore.get().isOpen) return;
25
+ confirmDialogStore.get().onDismiss?.();
26
+ closeConfirmDialog();
27
+ };
28
+ }
29
+ let pendingResolve = null;
30
+ /**
31
+ * 確認ダイアログを開き、押されたボタンで解決する(はい = true、いいえ・外側・戻る操作 = false)。
32
+ * アプリのルートに `once/confirm` の `ConfirmDialog` を 1 つ置いておく(**置いていないと、開かず、解決もしない**。開発時は警告を出す。
33
+ * 後から置くと、その時点で開く)。
34
+ * 移植元の `@lt-three/core` の `confirm(i18n, message, options)` から、i18n の引数を外した
35
+ * (love3 は i18n に依存しない。文言は `yes` / `no` で渡し、既定は日本語)。
36
+ */
37
+ function confirm(message, options) {
38
+ const { description, yes, no, yesVariant } = options ?? {};
39
+ if (__DEV__ && mountedDialogs === 0) console.warn("confirm(): ConfirmDialog がマウントされていない。アプリのルートに <ConfirmDialog /> を 1 つ置くまで、この確認は開かず、解決もしない。");
40
+ return new Promise((resolvePromise) => {
41
+ pendingResolve?.(false);
42
+ const resolve = (value) => {
43
+ if (pendingResolve === resolve) pendingResolve = null;
44
+ resolvePromise(value);
45
+ };
46
+ pendingResolve = resolve;
47
+ confirmDialogStore.set({
48
+ isOpen: true,
49
+ title: message,
50
+ description,
51
+ buttons: [{
52
+ text: no ?? "いいえ",
53
+ onClick: () => resolve(false),
54
+ variant: "outline"
55
+ }, {
56
+ text: yes ?? "はい",
57
+ onClick: () => resolve(true),
58
+ variant: yesVariant
59
+ }],
60
+ onOutsideClick: (close) => {
61
+ resolve(false);
62
+ close();
63
+ },
64
+ onDismiss: () => resolve(false)
65
+ });
66
+ });
67
+ }
68
+
69
+ //#endregion
70
+ export { closeConfirmDialog, confirm, confirmDialogStore, registerConfirmDialog };
@@ -0,0 +1,24 @@
1
+ //#region src/native/lib/control.d.ts
2
+ /**
3
+ * 入力の部品(`atom/text-field` `checkbox` `switch` `slider`)が、フォームの外装(`base/form` の `FormControl`)から受け取る
4
+ * アクセシビリティの props。web の `FormControl`(Radix の Slot が直下の入力に `id` / `aria-*` を渡す)に対応する。
5
+ *
6
+ * - `id` / `aria-labelledby` / `aria-describedby` / `aria-invalid`: react-native-web は DOM に出す(ラベルや説明との紐付けが効く)。
7
+ * 実機の React Native は `aria-labelledby` を Android だけ、`aria-describedby` は読まないので、
8
+ * 実機の読み上げには `accessibilityLabel` と `accessibilityHint` を渡す(フォームの部品が文字列のときに渡す)
9
+ * - `accessibilityHint`: 補足(`description`)。実機の VoiceOver / TalkBack が名前のあとに読む
10
+ */
11
+ export type ControlA11yProps = {
12
+ id?: string;
13
+ "aria-labelledby"?: string;
14
+ "aria-describedby"?: string;
15
+ "aria-invalid"?: boolean;
16
+ accessibilityHint?: string;
17
+ };
18
+ /**
19
+ * 名前を自分で持つ入力(`atom/checkbox`=右のラベル、`atom/slider`=自分の `label`)が受ける props。
20
+ * `aria-labelledby` は**型に含めない**(受け口が無いのに受けて黙って捨てない)。フォームの外装のラベルを名前にしたい入力
21
+ * (`text-field`・`switch`)だけが `ControlA11yProps` の全部を受ける。
22
+ */
23
+ export type NamedControlA11yProps = Omit<ControlA11yProps, "aria-labelledby">;
24
+ //#endregion
File without changes