@multiplatform.one/forms 6.4.2 → 6.6.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 (405) hide show
  1. package/dist/cjs/Button/index.cjs +23 -8
  2. package/dist/cjs/Button/index.native.js +23 -8
  3. package/dist/cjs/Button/index.native.js.map +1 -1
  4. package/dist/cjs/FieldDisplay/formatters.cjs +7 -12
  5. package/dist/cjs/FieldDisplay/formatters.native.js +7 -12
  6. package/dist/cjs/FieldDisplay/formatters.native.js.map +1 -1
  7. package/dist/cjs/Skeleton/index.cjs +1 -0
  8. package/dist/cjs/Skeleton/index.native.js +4 -0
  9. package/dist/cjs/Skeleton/index.native.js.map +1 -1
  10. package/dist/cjs/Wheel/index.cjs +1 -1
  11. package/dist/cjs/Wheel/index.native.js +1 -1
  12. package/dist/cjs/Wheel/index.native.js.map +1 -1
  13. package/dist/cjs/fields/Checkbox/Checkbox.cjs +22 -15
  14. package/dist/cjs/fields/Checkbox/Checkbox.native.js +11 -6
  15. package/dist/cjs/fields/Checkbox/Checkbox.native.js.map +1 -1
  16. package/dist/cjs/fields/Checkbox/index.cjs +9 -3
  17. package/dist/cjs/fields/Checkbox/index.native.js +9 -3
  18. package/dist/cjs/fields/Checkbox/index.native.js.map +1 -1
  19. package/dist/cjs/fields/ColorPicker/parts.native.js.map +1 -1
  20. package/dist/cjs/fields/Combobox/index.cjs +9 -4
  21. package/dist/cjs/fields/Combobox/index.native.js +9 -4
  22. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  23. package/dist/cjs/fields/DatePicker/DateRangePicker.cjs +30 -20
  24. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +36 -21
  25. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  26. package/dist/cjs/fields/DatePicker/DatetimePicker.cjs +21 -15
  27. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +26 -16
  28. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  29. package/dist/cjs/fields/DatePicker/MonthPicker.cjs +24 -14
  30. package/dist/cjs/fields/DatePicker/MonthPicker.native.js +36 -15
  31. package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
  32. package/dist/cjs/fields/DatePicker/MultiDatePicker.cjs +27 -18
  33. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +32 -19
  34. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  35. package/dist/cjs/fields/DatePicker/fieldValueSync.cjs +49 -0
  36. package/dist/cjs/fields/DatePicker/fieldValueSync.native.js +56 -0
  37. package/dist/cjs/fields/DatePicker/fieldValueSync.native.js.map +1 -0
  38. package/dist/cjs/fields/DatePicker/index.cjs +20 -14
  39. package/dist/cjs/fields/DatePicker/index.native.js +25 -15
  40. package/dist/cjs/fields/DatePicker/index.native.js.map +1 -1
  41. package/dist/cjs/fields/DatePicker/parts.cjs +2 -3
  42. package/dist/cjs/fields/DatePicker/parts.native.js +2 -3
  43. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  44. package/dist/cjs/fields/Geolocation/GeolocationMap.native.js +2 -2
  45. package/dist/cjs/fields/RadioGroup/index.cjs +4 -6
  46. package/dist/cjs/fields/RadioGroup/index.native.js +7 -6
  47. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  48. package/dist/cjs/fields/Rating/index.cjs +20 -3
  49. package/dist/cjs/fields/Rating/index.native.js +31 -6
  50. package/dist/cjs/fields/Rating/index.native.js.map +1 -1
  51. package/dist/cjs/fields/SearchInput/index.cjs +5 -1
  52. package/dist/cjs/fields/SearchInput/index.native.js +5 -1
  53. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  54. package/dist/cjs/fields/Select/index.cjs +6 -10
  55. package/dist/cjs/fields/Select/index.native.js +12 -10
  56. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  57. package/dist/cjs/fields/Signature/index.cjs +1 -1
  58. package/dist/cjs/fields/Signature/index.native.js +1 -1
  59. package/dist/cjs/fields/Signature/index.native.js.map +1 -1
  60. package/dist/cjs/fields/Slider/index.cjs +16 -4
  61. package/dist/cjs/fields/Slider/index.native.js +24 -4
  62. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  63. package/dist/cjs/fields/TextArea/index.cjs +3 -2
  64. package/dist/cjs/fields/TextArea/index.native.js +5 -2
  65. package/dist/cjs/fields/TextArea/index.native.js.map +1 -1
  66. package/dist/cjs/fields/TimePicker/index.cjs +1 -1
  67. package/dist/cjs/fields/TimePicker/index.native.js +1 -1
  68. package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
  69. package/dist/cjs/fields/ToggleGroup/index.cjs +6 -22
  70. package/dist/cjs/fields/ToggleGroup/index.native.js +11 -28
  71. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  72. package/dist/cjs/shared/TimeColumn.cjs +1 -1
  73. package/dist/cjs/shared/TimeColumn.native.js +1 -1
  74. package/dist/cjs/shared/TimeColumn.native.js.map +1 -1
  75. package/dist/cjs/shared/colorRamps.cjs +5 -1
  76. package/dist/cjs/shared/colorRamps.native.js +5 -1
  77. package/dist/cjs/shared/colorRamps.native.js.map +1 -1
  78. package/dist/cjs/shared/focusManagement.cjs +7 -1
  79. package/dist/cjs/shared/focusManagement.native.js +5 -1
  80. package/dist/cjs/shared/focusManagement.native.js.map +1 -1
  81. package/dist/cjs/shared/t.cjs +5 -0
  82. package/dist/cjs/shared/t.native.js +5 -0
  83. package/dist/cjs/shared/t.native.js.map +1 -1
  84. package/dist/esm/Button/index.mjs +24 -9
  85. package/dist/esm/Button/index.mjs.map +1 -1
  86. package/dist/esm/Button/index.native.js +24 -9
  87. package/dist/esm/Button/index.native.js.map +1 -1
  88. package/dist/esm/FieldDisplay/formatters.mjs +8 -13
  89. package/dist/esm/FieldDisplay/formatters.mjs.map +1 -1
  90. package/dist/esm/FieldDisplay/formatters.native.js +8 -13
  91. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  92. package/dist/esm/FieldDisplay/index.mjs.map +1 -1
  93. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  94. package/dist/esm/Skeleton/index.mjs +2 -1
  95. package/dist/esm/Skeleton/index.mjs.map +1 -1
  96. package/dist/esm/Skeleton/index.native.js +5 -1
  97. package/dist/esm/Skeleton/index.native.js.map +1 -1
  98. package/dist/esm/Wheel/index.mjs +1 -1
  99. package/dist/esm/Wheel/index.mjs.map +1 -1
  100. package/dist/esm/Wheel/index.native.js +1 -1
  101. package/dist/esm/Wheel/index.native.js.map +1 -1
  102. package/dist/esm/fields/Checkbox/Checkbox.mjs +24 -17
  103. package/dist/esm/fields/Checkbox/Checkbox.mjs.map +1 -1
  104. package/dist/esm/fields/Checkbox/Checkbox.native.js +13 -8
  105. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  106. package/dist/esm/fields/Checkbox/index.mjs +11 -5
  107. package/dist/esm/fields/Checkbox/index.mjs.map +1 -1
  108. package/dist/esm/fields/Checkbox/index.native.js +11 -5
  109. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  110. package/dist/esm/fields/ColorPicker/index.mjs.map +1 -1
  111. package/dist/esm/fields/ColorPicker/parts.mjs.map +1 -1
  112. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  113. package/dist/esm/fields/Combobox/index.mjs +9 -4
  114. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  115. package/dist/esm/fields/Combobox/index.native.js +9 -4
  116. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  117. package/dist/esm/fields/DatePicker/DateRangePicker.mjs +31 -21
  118. package/dist/esm/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  119. package/dist/esm/fields/DatePicker/DateRangePicker.native.js +37 -22
  120. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  121. package/dist/esm/fields/DatePicker/DatetimePicker.mjs +21 -15
  122. package/dist/esm/fields/DatePicker/DatetimePicker.mjs.map +1 -1
  123. package/dist/esm/fields/DatePicker/DatetimePicker.native.js +26 -16
  124. package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  125. package/dist/esm/fields/DatePicker/MonthPicker.mjs +25 -15
  126. package/dist/esm/fields/DatePicker/MonthPicker.mjs.map +1 -1
  127. package/dist/esm/fields/DatePicker/MonthPicker.native.js +37 -16
  128. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  129. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs +28 -19
  130. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  131. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js +33 -20
  132. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  133. package/dist/esm/fields/DatePicker/fieldValueSync.mjs +23 -0
  134. package/dist/esm/fields/DatePicker/fieldValueSync.mjs.map +1 -0
  135. package/dist/esm/fields/DatePicker/fieldValueSync.native.js +27 -0
  136. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -0
  137. package/dist/esm/fields/DatePicker/index.mjs +21 -15
  138. package/dist/esm/fields/DatePicker/index.mjs.map +1 -1
  139. package/dist/esm/fields/DatePicker/index.native.js +26 -16
  140. package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
  141. package/dist/esm/fields/DatePicker/parts.mjs +3 -4
  142. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  143. package/dist/esm/fields/DatePicker/parts.native.js +3 -4
  144. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  145. package/dist/esm/fields/DatePicker/utils.mjs.map +1 -1
  146. package/dist/esm/fields/Geolocation/GeolocationMap.native.js +2 -2
  147. package/dist/esm/fields/ImageField/index.mjs.map +1 -1
  148. package/dist/esm/fields/OTPInput/index.mjs.map +1 -1
  149. package/dist/esm/fields/RadioGroup/index.mjs +5 -7
  150. package/dist/esm/fields/RadioGroup/index.mjs.map +1 -1
  151. package/dist/esm/fields/RadioGroup/index.native.js +8 -7
  152. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  153. package/dist/esm/fields/Rating/index.mjs +20 -3
  154. package/dist/esm/fields/Rating/index.mjs.map +1 -1
  155. package/dist/esm/fields/Rating/index.native.js +31 -6
  156. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  157. package/dist/esm/fields/SearchInput/index.mjs +6 -2
  158. package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
  159. package/dist/esm/fields/SearchInput/index.native.js +6 -2
  160. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  161. package/dist/esm/fields/Select/index.mjs +6 -10
  162. package/dist/esm/fields/Select/index.mjs.map +1 -1
  163. package/dist/esm/fields/Select/index.native.js +12 -10
  164. package/dist/esm/fields/Select/index.native.js.map +1 -1
  165. package/dist/esm/fields/Signature/index.mjs +1 -1
  166. package/dist/esm/fields/Signature/index.mjs.map +1 -1
  167. package/dist/esm/fields/Signature/index.native.js +1 -1
  168. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  169. package/dist/esm/fields/Slider/index.mjs +16 -4
  170. package/dist/esm/fields/Slider/index.mjs.map +1 -1
  171. package/dist/esm/fields/Slider/index.native.js +24 -4
  172. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  173. package/dist/esm/fields/TextArea/index.mjs +3 -2
  174. package/dist/esm/fields/TextArea/index.mjs.map +1 -1
  175. package/dist/esm/fields/TextArea/index.native.js +5 -2
  176. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  177. package/dist/esm/fields/TimePicker/index.mjs +1 -1
  178. package/dist/esm/fields/TimePicker/index.mjs.map +1 -1
  179. package/dist/esm/fields/TimePicker/index.native.js +1 -1
  180. package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
  181. package/dist/esm/fields/ToggleGroup/index.mjs +7 -23
  182. package/dist/esm/fields/ToggleGroup/index.mjs.map +1 -1
  183. package/dist/esm/fields/ToggleGroup/index.native.js +12 -29
  184. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  185. package/dist/esm/shared/TimeColumn.mjs +1 -1
  186. package/dist/esm/shared/TimeColumn.mjs.map +1 -1
  187. package/dist/esm/shared/TimeColumn.native.js +1 -1
  188. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  189. package/dist/esm/shared/colorRamps.mjs +5 -2
  190. package/dist/esm/shared/colorRamps.mjs.map +1 -1
  191. package/dist/esm/shared/colorRamps.native.js +5 -2
  192. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  193. package/dist/esm/shared/focusManagement.mjs +7 -1
  194. package/dist/esm/shared/focusManagement.mjs.map +1 -1
  195. package/dist/esm/shared/focusManagement.native.js +5 -1
  196. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  197. package/dist/esm/shared/t.mjs +5 -1
  198. package/dist/esm/shared/t.mjs.map +1 -1
  199. package/dist/esm/shared/t.native.js +5 -1
  200. package/dist/esm/shared/t.native.js.map +1 -1
  201. package/dist/jsx/Button/index.mjs +24 -9
  202. package/dist/jsx/Button/index.mjs.map +1 -1
  203. package/dist/jsx/Button/index.native.js +23 -8
  204. package/dist/jsx/Button/index.native.js.map +1 -1
  205. package/dist/jsx/FieldDisplay/formatters.mjs +8 -13
  206. package/dist/jsx/FieldDisplay/formatters.mjs.map +1 -1
  207. package/dist/jsx/FieldDisplay/formatters.native.js +7 -12
  208. package/dist/jsx/FieldDisplay/formatters.native.js.map +1 -1
  209. package/dist/jsx/FieldDisplay/index.mjs.map +1 -1
  210. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  211. package/dist/jsx/Skeleton/index.mjs +2 -1
  212. package/dist/jsx/Skeleton/index.mjs.map +1 -1
  213. package/dist/jsx/Skeleton/index.native.js +4 -0
  214. package/dist/jsx/Skeleton/index.native.js.map +1 -1
  215. package/dist/jsx/Wheel/index.mjs +1 -1
  216. package/dist/jsx/Wheel/index.mjs.map +1 -1
  217. package/dist/jsx/Wheel/index.native.js +1 -1
  218. package/dist/jsx/Wheel/index.native.js.map +1 -1
  219. package/dist/jsx/fields/Checkbox/Checkbox.mjs +24 -17
  220. package/dist/jsx/fields/Checkbox/Checkbox.mjs.map +1 -1
  221. package/dist/jsx/fields/Checkbox/Checkbox.native.js +11 -6
  222. package/dist/jsx/fields/Checkbox/Checkbox.native.js.map +1 -1
  223. package/dist/jsx/fields/Checkbox/index.mjs +11 -5
  224. package/dist/jsx/fields/Checkbox/index.mjs.map +1 -1
  225. package/dist/jsx/fields/Checkbox/index.native.js +9 -3
  226. package/dist/jsx/fields/Checkbox/index.native.js.map +1 -1
  227. package/dist/jsx/fields/ColorPicker/index.mjs.map +1 -1
  228. package/dist/jsx/fields/ColorPicker/parts.mjs.map +1 -1
  229. package/dist/jsx/fields/ColorPicker/parts.native.js.map +1 -1
  230. package/dist/jsx/fields/Combobox/index.mjs +9 -4
  231. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  232. package/dist/jsx/fields/Combobox/index.native.js +9 -4
  233. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  234. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs +31 -21
  235. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  236. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js +36 -21
  237. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  238. package/dist/jsx/fields/DatePicker/DatetimePicker.mjs +21 -15
  239. package/dist/jsx/fields/DatePicker/DatetimePicker.mjs.map +1 -1
  240. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js +26 -16
  241. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  242. package/dist/jsx/fields/DatePicker/MonthPicker.mjs +25 -15
  243. package/dist/jsx/fields/DatePicker/MonthPicker.mjs.map +1 -1
  244. package/dist/jsx/fields/DatePicker/MonthPicker.native.js +36 -15
  245. package/dist/jsx/fields/DatePicker/MonthPicker.native.js.map +1 -1
  246. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs +28 -19
  247. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  248. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js +32 -19
  249. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  250. package/dist/jsx/fields/DatePicker/fieldValueSync.mjs +23 -0
  251. package/dist/jsx/fields/DatePicker/fieldValueSync.mjs.map +1 -0
  252. package/dist/jsx/fields/DatePicker/fieldValueSync.native.js +56 -0
  253. package/dist/jsx/fields/DatePicker/fieldValueSync.native.js.map +1 -0
  254. package/dist/jsx/fields/DatePicker/index.mjs +21 -15
  255. package/dist/jsx/fields/DatePicker/index.mjs.map +1 -1
  256. package/dist/jsx/fields/DatePicker/index.native.js +25 -15
  257. package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
  258. package/dist/jsx/fields/DatePicker/parts.mjs +3 -4
  259. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  260. package/dist/jsx/fields/DatePicker/parts.native.js +2 -3
  261. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  262. package/dist/jsx/fields/DatePicker/utils.mjs.map +1 -1
  263. package/dist/jsx/fields/Geolocation/GeolocationMap.native.js +2 -2
  264. package/dist/jsx/fields/ImageField/index.mjs.map +1 -1
  265. package/dist/jsx/fields/OTPInput/index.mjs.map +1 -1
  266. package/dist/jsx/fields/RadioGroup/index.mjs +5 -7
  267. package/dist/jsx/fields/RadioGroup/index.mjs.map +1 -1
  268. package/dist/jsx/fields/RadioGroup/index.native.js +7 -6
  269. package/dist/jsx/fields/RadioGroup/index.native.js.map +1 -1
  270. package/dist/jsx/fields/Rating/index.mjs +20 -3
  271. package/dist/jsx/fields/Rating/index.mjs.map +1 -1
  272. package/dist/jsx/fields/Rating/index.native.js +31 -6
  273. package/dist/jsx/fields/Rating/index.native.js.map +1 -1
  274. package/dist/jsx/fields/SearchInput/index.mjs +6 -2
  275. package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
  276. package/dist/jsx/fields/SearchInput/index.native.js +5 -1
  277. package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
  278. package/dist/jsx/fields/Select/index.mjs +6 -10
  279. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  280. package/dist/jsx/fields/Select/index.native.js +12 -10
  281. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  282. package/dist/jsx/fields/Signature/index.mjs +1 -1
  283. package/dist/jsx/fields/Signature/index.mjs.map +1 -1
  284. package/dist/jsx/fields/Signature/index.native.js +1 -1
  285. package/dist/jsx/fields/Signature/index.native.js.map +1 -1
  286. package/dist/jsx/fields/Slider/index.mjs +16 -4
  287. package/dist/jsx/fields/Slider/index.mjs.map +1 -1
  288. package/dist/jsx/fields/Slider/index.native.js +24 -4
  289. package/dist/jsx/fields/Slider/index.native.js.map +1 -1
  290. package/dist/jsx/fields/TextArea/index.mjs +3 -2
  291. package/dist/jsx/fields/TextArea/index.mjs.map +1 -1
  292. package/dist/jsx/fields/TextArea/index.native.js +5 -2
  293. package/dist/jsx/fields/TextArea/index.native.js.map +1 -1
  294. package/dist/jsx/fields/TimePicker/index.mjs +1 -1
  295. package/dist/jsx/fields/TimePicker/index.mjs.map +1 -1
  296. package/dist/jsx/fields/TimePicker/index.native.js +1 -1
  297. package/dist/jsx/fields/TimePicker/index.native.js.map +1 -1
  298. package/dist/jsx/fields/ToggleGroup/index.mjs +7 -23
  299. package/dist/jsx/fields/ToggleGroup/index.mjs.map +1 -1
  300. package/dist/jsx/fields/ToggleGroup/index.native.js +11 -28
  301. package/dist/jsx/fields/ToggleGroup/index.native.js.map +1 -1
  302. package/dist/jsx/shared/TimeColumn.mjs +1 -1
  303. package/dist/jsx/shared/TimeColumn.mjs.map +1 -1
  304. package/dist/jsx/shared/TimeColumn.native.js +1 -1
  305. package/dist/jsx/shared/TimeColumn.native.js.map +1 -1
  306. package/dist/jsx/shared/colorRamps.mjs +5 -2
  307. package/dist/jsx/shared/colorRamps.mjs.map +1 -1
  308. package/dist/jsx/shared/colorRamps.native.js +5 -1
  309. package/dist/jsx/shared/colorRamps.native.js.map +1 -1
  310. package/dist/jsx/shared/focusManagement.mjs +7 -1
  311. package/dist/jsx/shared/focusManagement.mjs.map +1 -1
  312. package/dist/jsx/shared/focusManagement.native.js +5 -1
  313. package/dist/jsx/shared/focusManagement.native.js.map +1 -1
  314. package/dist/jsx/shared/t.mjs +5 -1
  315. package/dist/jsx/shared/t.mjs.map +1 -1
  316. package/dist/jsx/shared/t.native.js +5 -0
  317. package/dist/jsx/shared/t.native.js.map +1 -1
  318. package/package.json +8 -7
  319. package/src/Button/Button.stories.tsx +19 -0
  320. package/src/Button/index.tsx +45 -12
  321. package/src/ControlGroup/ControlGroup.stories.tsx +12 -0
  322. package/src/FieldDisplay/formatters.ts +10 -14
  323. package/src/FieldLayout.stories.tsx +3 -2
  324. package/src/Form/Form.stories.tsx +13 -0
  325. package/src/Skeleton/index.tsx +5 -1
  326. package/src/fields/Checkbox/Checkbox.spec.tsx +50 -1
  327. package/src/fields/Checkbox/Checkbox.tsx +47 -19
  328. package/src/fields/Checkbox/index.tsx +23 -5
  329. package/src/fields/ColorPicker/ColorPicker.stories.tsx +2 -1
  330. package/src/fields/Combobox/index.tsx +8 -3
  331. package/src/fields/DatePicker/DatePicker.spec.tsx +93 -0
  332. package/src/fields/DatePicker/DatePicker.stories.tsx +2 -1
  333. package/src/fields/DatePicker/DateRangePicker.spec.tsx +72 -0
  334. package/src/fields/DatePicker/DateRangePicker.tsx +44 -30
  335. package/src/fields/DatePicker/DatetimePicker.spec.tsx +39 -0
  336. package/src/fields/DatePicker/DatetimePicker.tsx +1 -1
  337. package/src/fields/DatePicker/MonthPicker.spec.tsx +61 -0
  338. package/src/fields/DatePicker/MonthPicker.tsx +47 -21
  339. package/src/fields/DatePicker/MultiDatePicker.spec.tsx +34 -0
  340. package/src/fields/DatePicker/MultiDatePicker.tsx +39 -27
  341. package/src/fields/DatePicker/fieldValueSync.tsx +23 -0
  342. package/src/fields/DatePicker/parts.tsx +6 -1
  343. package/src/fields/FileUpload/FileUpload.stories.tsx +11 -1
  344. package/src/fields/Geolocation/Geolocation.stories.tsx +9 -0
  345. package/src/fields/Geolocation/GeolocationMap.native.tsx +2 -2
  346. package/src/fields/ImageField/ImageField.stories.tsx +2 -1
  347. package/src/fields/Input/Input.stories.tsx +19 -0
  348. package/src/fields/Progress/Progress.stories.tsx +19 -0
  349. package/src/fields/RadioGroup/RadioGroup.spec.tsx +139 -2
  350. package/src/fields/RadioGroup/index.tsx +2 -2
  351. package/src/fields/Rating/Rating.spec.tsx +43 -1
  352. package/src/fields/Rating/index.tsx +43 -4
  353. package/src/fields/SearchInput/SearchInput.spec.tsx +11 -0
  354. package/src/fields/SearchInput/index.tsx +6 -2
  355. package/src/fields/Select/Select.stories.tsx +19 -0
  356. package/src/fields/Select/index.tsx +12 -5
  357. package/src/fields/Signature/index.tsx +1 -1
  358. package/src/fields/Slider/Slider.spec.tsx +89 -4
  359. package/src/fields/Slider/Slider.stories.tsx +19 -0
  360. package/src/fields/Slider/index.tsx +4 -0
  361. package/src/fields/Stepper/Stepper.stories.tsx +12 -0
  362. package/src/fields/Switch/Switch.spec.tsx +50 -2
  363. package/src/fields/TextArea/TextArea.spec.tsx +57 -0
  364. package/src/fields/TextArea/TextArea.stories.tsx +19 -0
  365. package/src/fields/TextArea/index.tsx +10 -2
  366. package/src/fields/TimePicker/index.tsx +1 -1
  367. package/src/fields/ToggleGroup/ToggleGroup.spec.tsx +64 -1
  368. package/src/fields/ToggleGroup/ToggleGroup.stories.tsx +19 -0
  369. package/src/fields/ToggleGroup/index.tsx +31 -29
  370. package/src/shared/FloatingListScrollArrows.stories.tsx +4 -2
  371. package/src/shared/TimeColumn.tsx +1 -1
  372. package/src/shared/focusManagement.ts +12 -1
  373. package/src/shared/t.spec.ts +39 -0
  374. package/src/shared/t.ts +20 -0
  375. package/types/Button/index.d.ts +9 -1
  376. package/types/Button/index.d.ts.map +1 -1
  377. package/types/FieldDisplay/formatters.d.ts +7 -1
  378. package/types/FieldDisplay/formatters.d.ts.map +1 -1
  379. package/types/InputParts/index.d.ts +4 -4
  380. package/types/Skeleton/index.d.ts.map +1 -1
  381. package/types/fields/Checkbox/Checkbox.d.ts.map +1 -1
  382. package/types/fields/Checkbox/index.d.ts +3 -3
  383. package/types/fields/Checkbox/index.d.ts.map +1 -1
  384. package/types/fields/Combobox/index.d.ts.map +1 -1
  385. package/types/fields/DatePicker/DateRangePicker.d.ts.map +1 -1
  386. package/types/fields/DatePicker/DatetimePicker.d.ts.map +1 -1
  387. package/types/fields/DatePicker/MonthPicker.d.ts.map +1 -1
  388. package/types/fields/DatePicker/MultiDatePicker.d.ts.map +1 -1
  389. package/types/fields/DatePicker/fieldValueSync.d.ts +31 -0
  390. package/types/fields/DatePicker/fieldValueSync.d.ts.map +1 -0
  391. package/types/fields/DatePicker/index.d.ts.map +1 -1
  392. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  393. package/types/fields/Input/index.d.ts +2 -2
  394. package/types/fields/RadioGroup/index.d.ts.map +1 -1
  395. package/types/fields/Rating/index.d.ts.map +1 -1
  396. package/types/fields/SearchInput/index.d.ts.map +1 -1
  397. package/types/fields/Select/index.d.ts.map +1 -1
  398. package/types/fields/Slider/index.d.ts.map +1 -1
  399. package/types/fields/TextArea/index.d.ts.map +1 -1
  400. package/types/fields/ToggleGroup/index.d.ts.map +1 -1
  401. package/types/shared/colorRamps.d.ts +14 -0
  402. package/types/shared/colorRamps.d.ts.map +1 -1
  403. package/types/shared/focusManagement.d.ts.map +1 -1
  404. package/types/shared/t.d.ts +16 -0
  405. package/types/shared/t.d.ts.map +1 -1
@@ -36,10 +36,10 @@ function MapFallback({ lat, lng, minHeight }: { lat: number; lng: number; minHei
36
36
  backgroundColor="$backgroundHover"
37
37
  gap="$1"
38
38
  >
39
- <Text color="$colorSubtle" fontSize="$2">
39
+ <Text color="$color11" fontSize="$2">
40
40
  {t("Map preview unavailable — requires expo-maps")}
41
41
  </Text>
42
- <Text color="$colorSubtle" fontSize="$1">
42
+ <Text color="$color11" fontSize="$1">
43
43
  {`${lat.toFixed(4)}, ${lng.toFixed(4)}`}
44
44
  </Text>
45
45
  </YStack>
@@ -135,7 +135,8 @@ export const ReadOnly: Story = {
135
135
  export const WithError: Story = {
136
136
  args: {
137
137
  label: "Required Image",
138
- error: "Please upload an image",
138
+ // DG-COPY-02: error copy states the rule broken — never "please"/"invalid"/"error".
139
+ error: "An image is required",
139
140
  required: true,
140
141
  imageWidth: 64,
141
142
  imageHeight: 64,
@@ -115,7 +115,26 @@ export const SkeletonState: Story = {
115
115
  args: { label: "Full name", skeleton: true },
116
116
  };
117
117
 
118
+ /**
119
+ * FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY): the right column renders the
120
+ * RAW tamagui Input beside the house Input strictly so the difference stays
121
+ * visible. Raw primitives here are by design and labeled — knob/contrast probes
122
+ * skip this story via `parameters.foreignContrastSpecimen`.
123
+ */
118
124
  export const Comparison: StoryObj = {
125
+ name: "Foreign contrast specimen (raw tamagui)",
126
+ parameters: {
127
+ // Machine-readable exemption for knob/contrast probes and the LC-56 linter arm.
128
+ foreignContrastSpecimen: true,
129
+ docs: {
130
+ description: {
131
+ story:
132
+ "FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY). The right column is the raw " +
133
+ "tamagui Input, rendered for contrast only: it ignores house knobs and field " +
134
+ "recipes by design. Probes asserting house rendering must skip this story.",
135
+ },
136
+ },
137
+ },
119
138
  render: () => {
120
139
  const ComparisonExample = () => {
121
140
  const [customVal, setCustomVal] = useState("");
@@ -169,7 +169,26 @@ export const Interactive: Story = {
169
169
  },
170
170
  };
171
171
 
172
+ /**
173
+ * FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY): the right column renders the
174
+ * RAW tamagui Progress beside the house Progress strictly so the difference
175
+ * stays visible. Raw primitives here are by design and labeled — knob/contrast
176
+ * probes skip this story via `parameters.foreignContrastSpecimen`.
177
+ */
172
178
  export const Comparison: Story = {
179
+ name: "Foreign contrast specimen (raw tamagui)",
180
+ parameters: {
181
+ // Machine-readable exemption for knob/contrast probes and the LC-56 linter arm.
182
+ foreignContrastSpecimen: true,
183
+ docs: {
184
+ description: {
185
+ story:
186
+ "FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY). The right column is the raw " +
187
+ "tamagui Progress, rendered for contrast only: it ignores house knobs and " +
188
+ "recipes by design. Probes asserting house rendering must skip this story.",
189
+ },
190
+ },
191
+ },
173
192
  render: () => (
174
193
  <XStack gap="$6" alignItems="flex-start" padding="$4">
175
194
  <YStack gap="$3" width={300}>
@@ -1,8 +1,16 @@
1
1
  import { useForm } from "@tanstack/react-form";
2
- import { act, fireEvent, waitFor } from "@testing-library/react";
3
- import { YStack } from "tamagui";
2
+ import { act, fireEvent, render, waitFor } from "@testing-library/react";
3
+ import { TamaguiProvider, YStack, createTamagui } from "tamagui";
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
5
  import { renderWithProviders } from "@multiplatform.one/test-utils";
6
+ import {
7
+ createThemesBuilder,
8
+ defaultAccentTheme,
9
+ defaultBaseTheme,
10
+ defaultBuilderOptions,
11
+ } from "@multiplatform.one/theme";
12
+ import { configWithoutAnimations } from "@tamagui/config";
13
+ import { animationsCSS } from "@tamagui/config/v5-css";
6
14
  import { Button } from "../../Button";
7
15
  import { Form } from "../../Form";
8
16
  import { RadioGroup } from "./index";
@@ -13,6 +21,21 @@ const mockOptions = [
13
21
  { label: "Option 3", value: "option3" },
14
22
  ];
15
23
 
24
+ // House builder themes for LC-05 mark assertions — created at MODULE scope:
25
+ // tamagui registers a config's theme variables globally at createTamagui
26
+ // time, and a config created after the first render (inside a test body)
27
+ // never resolves its tokens (Progress.spec pattern).
28
+ const houseThemes = createThemesBuilder(
29
+ defaultBaseTheme,
30
+ defaultAccentTheme,
31
+ defaultBuilderOptions,
32
+ ).themes() as Record<string, Record<string, string>>;
33
+ const houseConfig = createTamagui({
34
+ ...configWithoutAnimations,
35
+ animations: animationsCSS,
36
+ themes: houseThemes as any,
37
+ });
38
+
16
39
  let consoleErrorSpy: ReturnType<typeof vi.spyOn> | null = null;
17
40
  beforeEach(() => {
18
41
  consoleErrorSpy = vi.spyOn(console, "error").mockImplementation((...args: unknown[]) => {
@@ -266,6 +289,95 @@ describe("RadioGroup Components", () => {
266
289
  });
267
290
  });
268
291
 
292
+ describe("late-arriving value display (create-mode seeding)", () => {
293
+ // The non-card variant fed the current value into tamagui as mount-only
294
+ // `defaultValue`, so a value applied AFTER first paint (create-mode
295
+ // engine seeding lands once meta loads) never displayed. The group must
296
+ // render controlled — and adopting a programmatic value must not emit
297
+ // onChange (LC-14: a seeded value is not a user edit).
298
+ const getRadioByValue = (container: ParentNode, value: string) =>
299
+ [...container.querySelectorAll("[role='radio']")].find((radio) =>
300
+ radio.id.endsWith(`-${value}`),
301
+ );
302
+
303
+ it("standalone controlled: a value arriving after mount renders checked, without onChange", async () => {
304
+ const onChange = vi.fn();
305
+ const onValueChange = vi.fn();
306
+ const result = renderWithProviders(
307
+ <RadioGroup
308
+ label="Status"
309
+ value=""
310
+ options={mockOptions}
311
+ onChange={onChange}
312
+ onValueChange={onValueChange}
313
+ />,
314
+ );
315
+ for (const radio of result.container.querySelectorAll("[role='radio']")) {
316
+ expect(radio.getAttribute("aria-checked")).not.toBe("true");
317
+ }
318
+
319
+ // Late seed: the upstream doc value arrives after first paint.
320
+ result.rerender(
321
+ <RadioGroup
322
+ label="Status"
323
+ value="option2"
324
+ options={mockOptions}
325
+ onChange={onChange}
326
+ onValueChange={onValueChange}
327
+ />,
328
+ );
329
+ await waitFor(() => {
330
+ expect(getRadioByValue(result.container, "option2")?.getAttribute("aria-checked")).toBe(
331
+ "true",
332
+ );
333
+ });
334
+ expect(onChange).not.toHaveBeenCalled();
335
+ expect(onValueChange).not.toHaveBeenCalled();
336
+ });
337
+
338
+ it("form-integrated: a field value set after mount renders checked, without onChange", async () => {
339
+ const onChange = vi.fn();
340
+ let formApi: { setFieldValue: (name: "option", value: string) => void } | undefined;
341
+ const TestComponent = () => {
342
+ const form = useForm({ defaultValues: { option: "" } });
343
+ formApi = form as unknown as typeof formApi;
344
+ return (
345
+ <Form form={form}>
346
+ <RadioGroup label="Status" name="option" options={mockOptions} onChange={onChange} />
347
+ </Form>
348
+ );
349
+ };
350
+ const result = renderWithProviders(<TestComponent />);
351
+
352
+ await act(async () => {
353
+ formApi?.setFieldValue("option", "option3");
354
+ });
355
+ await waitFor(() => {
356
+ expect(getRadioByValue(result.container, "option3")?.getAttribute("aria-checked")).toBe(
357
+ "true",
358
+ );
359
+ });
360
+ expect(onChange).not.toHaveBeenCalled();
361
+ });
362
+
363
+ it("still emits exactly once for a real click after a late seed", async () => {
364
+ const onChange = vi.fn();
365
+ const result = renderWithProviders(
366
+ <RadioGroup label="Status" value="" options={mockOptions} onChange={onChange} />,
367
+ );
368
+ result.rerender(
369
+ <RadioGroup label="Status" value="option1" options={mockOptions} onChange={onChange} />,
370
+ );
371
+ const radio = getRadioByValue(result.container, "option2");
372
+ expect(radio).toBeTruthy();
373
+ await act(async () => {
374
+ if (radio) fireEvent.click(radio);
375
+ });
376
+ expect(onChange).toHaveBeenCalledTimes(1);
377
+ expect(onChange).toHaveBeenCalledWith("option2");
378
+ });
379
+ });
380
+
269
381
  describe("card mode (LC-22 SELECTION-CARD)", () => {
270
382
  const cardOptions = [
271
383
  { label: "Card A", value: "a", description: "Description for A" },
@@ -326,5 +438,30 @@ describe("RadioGroup Components", () => {
326
438
  expect(new Set(ids).size).toBe(2);
327
439
  });
328
440
  });
441
+
442
+ describe("selected mark (LC-05 ONE-EMPHASIS / D-01)", () => {
443
+ it("paints the checked radio's indicator dot with the accent mark, never ink", () => {
444
+ const { container } = render(
445
+ <TamaguiProvider config={houseConfig} defaultTheme="light" disableInjectCSS>
446
+ <RadioGroup label="Choose" value="option2" options={mockOptions} />
447
+ </TamaguiProvider>,
448
+ );
449
+ const checked = container.querySelector('[role="radio"][aria-checked="true"]');
450
+ expect(checked).toBeTruthy();
451
+ // The indicator dot is the selection mark: it fills with the shared
452
+ // accent mark token ($accentBackground), not the ink/label tier.
453
+ const marked = Array.from(checked!.querySelectorAll("*")).filter((el) =>
454
+ (el as HTMLElement).className?.toString().includes("_bg-accentBackg"),
455
+ );
456
+ expect(marked.length).toBeGreaterThan(0);
457
+ // Unchecked radios render no accent mark.
458
+ const unchecked = container.querySelector('[role="radio"][aria-checked="false"]');
459
+ expect(unchecked).toBeTruthy();
460
+ const uncheckedMarked = Array.from(unchecked!.querySelectorAll("*")).filter((el) =>
461
+ (el as HTMLElement).className?.toString().includes("_bg-accentBackg"),
462
+ );
463
+ expect(uncheckedMarked.length).toBe(0);
464
+ });
465
+ });
329
466
  });
330
467
  });
@@ -280,7 +280,7 @@ export function RadioGroup({
280
280
  borderWidth={radioRingWidth(knobProps.borderRadius.borderWidth)}
281
281
  borderRadius={itemRadius}
282
282
  outlined={knobProps.outlined}
283
- {...(knobProps.transition ? { animation: knobProps.transition } : undefined)}
283
+ {...(knobProps.transition ? { transition: knobProps.transition } : undefined)}
284
284
  >
285
285
  <RadioIndicatorFrame
286
286
  borderRadius={indicatorRadius}
@@ -288,7 +288,7 @@ export function RadioGroup({
288
288
  // accent — `textAccentColor` is the LABEL ink tier ($color/$color11)
289
289
  // and made the checked radio read as ink, not as chosen (D-01).
290
290
  backgroundColor={formSelectedColors.mark}
291
- {...(knobProps.transition ? { animation: knobProps.transition } : undefined)}
291
+ {...(knobProps.transition ? { transition: knobProps.transition } : undefined)}
292
292
  />
293
293
  </RadioGlyph>
294
294
  );
@@ -1,6 +1,15 @@
1
1
  import { describe, expect, it, vi } from "vitest";
2
- import { fireEvent } from "@testing-library/react";
2
+ import { fireEvent, render } from "@testing-library/react";
3
3
  import { renderWithProviders } from "@multiplatform.one/test-utils";
4
+ import {
5
+ createThemesBuilder,
6
+ defaultAccentTheme,
7
+ defaultBaseTheme,
8
+ defaultBuilderOptions,
9
+ } from "@multiplatform.one/theme";
10
+ import { configWithoutAnimations } from "@tamagui/config";
11
+ import { animationsCSS } from "@tamagui/config/v5-css";
12
+ import { TamaguiProvider, createTamagui } from "tamagui";
4
13
  import { Form } from "../../Form";
5
14
  import { Rating } from "./index";
6
15
 
@@ -8,6 +17,21 @@ const MockStarIcon = ({ size, weight, color }: { size: number; weight: string; c
8
17
  <span data-testid="star" data-size={size} data-weight={weight} data-color={color} />
9
18
  );
10
19
 
20
+ // House builder themes for the LC-05 mark assertion — created at MODULE
21
+ // scope: tamagui registers a config's theme variables globally at
22
+ // createTamagui time, and a config created after the first render (inside a
23
+ // test body) never resolves its tokens (Progress.spec pattern).
24
+ const houseThemes = createThemesBuilder(
25
+ defaultBaseTheme,
26
+ defaultAccentTheme,
27
+ defaultBuilderOptions,
28
+ ).themes() as Record<string, Record<string, string>>;
29
+ const houseConfig = createTamagui({
30
+ ...configWithoutAnimations,
31
+ animations: animationsCSS,
32
+ themes: houseThemes as any,
33
+ });
34
+
11
35
  describe("Rating", () => {
12
36
  describe("without form context", () => {
13
37
  it("renders with label", () => {
@@ -97,6 +121,24 @@ describe("Rating", () => {
97
121
  expect(star.getAttribute("aria-disabled")).toBe("true");
98
122
  }
99
123
  });
124
+
125
+ // LC-05 ONE-EMPHASIS / D-01: the FILLED star is the selection mark, so it
126
+ // resolves the shared accent mark token; the empty star stays neutral
127
+ // chrome. Stock test themes carry no $accentBackground, so mount the
128
+ // house builder themes for real resolution.
129
+ it("fills selected stars with the accent mark and empty stars with neutral chrome", () => {
130
+ const { container } = render(
131
+ <TamaguiProvider config={houseConfig} defaultTheme="light" disableInjectCSS>
132
+ <Rating label="Rate" value={0.6} starIcon={MockStarIcon} />
133
+ </TamaguiProvider>,
134
+ );
135
+ const filled = container.querySelector("[data-rating-star='filled'] [data-testid='star']");
136
+ const empty = container.querySelector("[data-rating-star='empty'] [data-testid='star']");
137
+ expect(filled).toBeTruthy();
138
+ expect(empty).toBeTruthy();
139
+ expect(filled!.getAttribute("data-color")).toContain("accentBackground");
140
+ expect(empty!.getAttribute("data-color")).not.toContain("accentBackground");
141
+ });
100
142
  });
101
143
 
102
144
  describe("with form context", () => {
@@ -49,7 +49,10 @@ function PointyStar({
49
49
  <Svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
50
50
  <Path
51
51
  d={d}
52
- fill={weight === "fill" ? color : "none"}
52
+ // `transparent` rather than `none`: an empty->filled star has to
53
+ // interpolate its fill (LC-25), and `none` is not a colour so it can
54
+ // only jump. Paints identically.
55
+ fill={weight === "fill" ? color : "transparent"}
53
56
  stroke={color}
54
57
  strokeWidth={1.5}
55
58
  strokeLinejoin="miter"
@@ -80,6 +83,32 @@ function getTransitionStyle(transition: TransitionProp | undefined, live: boolea
80
83
  };
81
84
  }
82
85
 
86
+ // LC-25, star ink: the visible change is the SVG `fill`/`stroke` of the glyph
87
+ // CHILD, and `transition` does not inherit — a declaration on the wrapper can
88
+ // never reach it, while the swappable `starIcon` contract ({ size, weight,
89
+ // color }) has no style passthrough to declare it on. A one-shot descendant
90
+ // stylesheet (Spinner/Wheel pattern) arms the tween on whatever glyph the
91
+ // contract renders, so the contract itself stays untouched.
92
+ const INK_STYLE_ID = "mp1-rating-ink";
93
+ const inkClassName = (token: string) => `mp1-rating-ink-${token}`;
94
+ function ensureRatingInkStyles() {
95
+ if (!isWeb || typeof document === "undefined") return;
96
+ if (document.getElementById(INK_STYLE_ID)) return;
97
+ const style = document.createElement("style");
98
+ style.id = INK_STYLE_ID;
99
+ // Shape elements only, never the <svg> root: a Phosphor-shaped glyph paints
100
+ // the root's `fill` and the shape INHERITS it, so arming both would leave
101
+ // the shape chasing an already-animating value and stretch the tween well
102
+ // past the token.
103
+ style.textContent = Object.entries(cssTimings)
104
+ .map(
105
+ ([token, timing]) =>
106
+ `.${inkClassName(token)} svg * { transition: fill ${timing}, stroke ${timing}; }`,
107
+ )
108
+ .join("\n");
109
+ document.head.appendChild(style);
110
+ }
111
+
83
112
  const StarWrapper = styled(View, {
84
113
  variants: {
85
114
  filled: {
@@ -124,10 +153,19 @@ function StarRow({
124
153
  const [scrubFilled, setScrubFilled] = useState<number | null>(null);
125
154
  const scrubbing = scrubFilled != null;
126
155
  const displayFilled = scrubFilled ?? filledStars;
127
- // LC-25: discrete star jumps tween via knob transition (default "quick").
128
- // During pointer scrub, omit transition so fill tracks the pointer 1:1.
129
- const motionTransition = (knobProps.transition as TransitionProp | undefined) || "quick";
156
+ // LC-25: discrete star jumps tween via knob transition. During pointer
157
+ // scrub, omit transition so fill tracks the pointer 1:1. `transition` is
158
+ // undefined exactly at animation="none" (which prefers-reduced-motion maps
159
+ // onto), and Axiom 3 says that position is NO motion — not a default one.
160
+ const motionTransition = knobProps.transition as TransitionProp | undefined;
130
161
  const live = scrubbing;
162
+ ensureRatingInkStyles();
163
+ const inkToken =
164
+ isWeb && !live && motionTransition
165
+ ? (motionTransition as string) in cssTimings
166
+ ? (motionTransition as string)
167
+ : "quick"
168
+ : undefined;
131
169
 
132
170
  // DG-A11Y keyboard operability: one roving tab stop (ToggleGroup pattern —
133
171
  // a group of N buttons is one Tab entry, arrows move within). The stop
@@ -227,6 +265,7 @@ function StarRow({
227
265
  data-rating-star={isFilled ? "filled" : "empty"}
228
266
  data-rating-index={starNumber}
229
267
  {...(!isWeb && !live ? { transition: motionTransition } : {})}
268
+ {...(inkToken ? { className: inkClassName(inkToken) } : undefined)}
230
269
  style={getTransitionStyle(live ? undefined : motionTransition, live)}
231
270
  >
232
271
  <StarIcon
@@ -21,6 +21,17 @@ describe("SearchInput", () => {
21
21
  expect(result.container.querySelector("svg")).toBeTruthy();
22
22
  });
23
23
 
24
+ it("bidi-isolates the default placeholder (LC-58) and passes explicit ones through", () => {
25
+ // Default: FSI…PDI framing so the trailing "..." cannot reorder to
26
+ // "…Search" under RTL; the visible run stays byte-identical inside.
27
+ const result = renderWithProviders(<SearchInput />);
28
+ const input = result.container.querySelector("input");
29
+ expect(input?.getAttribute("placeholder")).toBe("\u2068Search...\u2069");
30
+ // Explicit placeholders are the consumer's interpolation site — the
31
+ // component must not double-wrap or mutate them (asserted above too).
32
+ expect(input?.getAttribute("placeholder")?.slice(1, -1)).toBe("Search...");
33
+ });
34
+
24
35
  it("fires onChange per keystroke and onSearch after debounce", () => {
25
36
  const onChange = vi.fn();
26
37
  const onSearch = vi.fn();
@@ -12,7 +12,7 @@ import type { ReactNode } from "react";
12
12
  import { useCallback, useEffect, useRef, useState } from "react";
13
13
  import type { SizeTokens } from "tamagui";
14
14
  import { View } from "tamagui";
15
- import { t } from "../../shared/t";
15
+ import { bidiIsolate, t } from "../../shared/t";
16
16
  import { Input } from "../Input";
17
17
  import type { InputProps } from "../Input";
18
18
 
@@ -60,7 +60,11 @@ export function SearchInput({
60
60
  onSearch,
61
61
  onClear,
62
62
  debounceMs = 300,
63
- placeholder = t("Search..."),
63
+ // Bidi-isolated at the interpolation site (LC-58): under RTL the trailing
64
+ // weak "..." otherwise reorders to the start ("…Search"). First-strong
65
+ // isolation keeps a translated RTL placeholder rendering RTL. Consumer
66
+ // placeholders are the consumer's interpolation site — passed through.
67
+ placeholder = bidiIsolate(t("Search...")),
64
68
  clearable = true,
65
69
  disabled,
66
70
  size,
@@ -303,7 +303,26 @@ export const DynamicOptions: StoryObj<typeof Select> = {
303
303
  },
304
304
  };
305
305
 
306
+ /**
307
+ * FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY): the right column renders the
308
+ * RAW tamagui Select beside the house Select strictly so the difference stays
309
+ * visible. Raw primitives here are by design and labeled — knob/contrast probes
310
+ * skip this story via `parameters.foreignContrastSpecimen`.
311
+ */
306
312
  export const Comparison: StoryObj<typeof Select> = {
313
+ name: "Foreign contrast specimen (raw tamagui)",
314
+ parameters: {
315
+ // Machine-readable exemption for knob/contrast probes and the LC-56 linter arm.
316
+ foreignContrastSpecimen: true,
317
+ docs: {
318
+ description: {
319
+ story:
320
+ "FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY). The right column is the raw " +
321
+ "tamagui Select, rendered for contrast only: it ignores house knobs and control " +
322
+ "recipes by design. Probes asserting house rendering must skip this story.",
323
+ },
324
+ },
325
+ },
307
326
  render: () => {
308
327
  const ComparisonExample = () => {
309
328
  const [customValue, setCustomValue] = useState<string>();
@@ -311,7 +311,7 @@ const SelectItem = memo(function SelectItem({
311
311
  : formInputColors.background.focus,
312
312
  },
313
313
  })}
314
- {...(ctx.knobProps.transition ? { animation: ctx.knobProps.transition } : undefined)}
314
+ {...(ctx.knobProps.transition ? { transition: ctx.knobProps.transition } : undefined)}
315
315
  >
316
316
  <Text
317
317
  fontFamily={ctx.knobProps.body.fontFamily}
@@ -839,9 +839,14 @@ function FloatingSelectCore({
839
839
  cursor="pointer"
840
840
  disabled={disabled}
841
841
  size={knobProps.sizeToken}
842
+ // LC-54 PRESS-FLOOR: the size knob may shrink chrome (compact → $3
843
+ // = 36px) but the trigger's press target never drops below 44 —
844
+ // same minHeight floor the house Button holds. Without it a compact
845
+ // Select sat 36px beside 44px Inputs/Buttons in one control row.
846
+ minHeight={44}
842
847
  {...(inTableCell
843
- ? // Chromeless in cells, but keep a ≥44px pressable target (SP-FIXED).
844
- { minHeight: 44 }
848
+ ? // Chromeless in cells (the floor above still applies).
849
+ {}
845
850
  : {
846
851
  borderRadius: knobProps.borderRadius.borderRadius,
847
852
  borderWidth: knobProps.borderRadius.borderWidth,
@@ -1257,9 +1262,11 @@ function NativeSelectCore({
1257
1262
  <InputParts.Box
1258
1263
  disabled={disabled}
1259
1264
  size={knobProps.sizeToken}
1265
+ // LC-54 PRESS-FLOOR: ≥44px trigger target at every size (matches
1266
+ // the web trigger branch above).
1267
+ minHeight={44}
1260
1268
  {...(inTableCell
1261
- ? // Chromeless in cells, but keep a ≥44px pressable target (SP-FIXED).
1262
- { minHeight: 44 }
1269
+ ? {}
1263
1270
  : {
1264
1271
  borderRadius: knobProps.borderRadius.borderRadius,
1265
1272
  borderWidth: knobProps.borderRadius.borderWidth,
@@ -454,7 +454,7 @@ function SignatureCanvasImpl({
454
454
  opacity={disabled ? 0.6 : 1}
455
455
  aspectRatio={aspectRatio}
456
456
  minHeight={minHeightPx}
457
- {...(knobProps.transition ? { animation: knobProps.transition } : undefined)}
457
+ {...(knobProps.transition ? { transition: knobProps.transition } : undefined)}
458
458
  aria-required={required || undefined}
459
459
  aria-invalid={hasError || undefined}
460
460
  >
@@ -1,3 +1,4 @@
1
+ import { useState } from "react";
1
2
  import { useForm } from "@tanstack/react-form";
2
3
  import { act, fireEvent, renderHook, waitFor } from "@testing-library/react";
3
4
  import { getSize } from "@tamagui/get-token";
@@ -205,6 +206,76 @@ describe("Slider", () => {
205
206
  });
206
207
  });
207
208
 
209
+ describe("late-arriving value display (create-mode seeding)", () => {
210
+ // The upstream value was fed into tamagui as mount-only `defaultValue`,
211
+ // so a value applied AFTER first paint (create-mode engine seeding,
212
+ // form.setFieldValue, live server merge) never moved the thumb. The
213
+ // slider must run controlled when an upstream value drives it — and
214
+ // adopting a programmatic value must not emit onChange (LC-14: a seeded
215
+ // value is not a user edit).
216
+ const getThumb = (container: ParentNode) =>
217
+ container.querySelector('[role="slider"]') as HTMLElement | null;
218
+
219
+ it("standalone controlled: a value arriving after mount renders, without onChange", async () => {
220
+ const onChange = vi.fn();
221
+ const onValueChange = vi.fn();
222
+ const result = renderWithProviders(
223
+ <Slider label="Progress" value={[25]} onChange={onChange} onValueChange={onValueChange} />,
224
+ );
225
+ expect(getThumb(result.container)?.getAttribute("aria-valuenow")).toBe("25");
226
+
227
+ // Late seed: the upstream doc value arrives after first paint.
228
+ result.rerender(
229
+ <Slider label="Progress" value={[75]} onChange={onChange} onValueChange={onValueChange} />,
230
+ );
231
+ await waitFor(() => {
232
+ expect(getThumb(result.container)?.getAttribute("aria-valuenow")).toBe("75");
233
+ });
234
+ expect(onChange).not.toHaveBeenCalled();
235
+ expect(onValueChange).not.toHaveBeenCalled();
236
+ });
237
+
238
+ it("form-integrated: a field value set after mount renders, without onChange", async () => {
239
+ const onChange = vi.fn();
240
+ let formApi: { setFieldValue: (name: "volume", value: number[]) => void } | undefined;
241
+ const TestComponent = () => {
242
+ const form = useForm({ defaultValues: { volume: [10] } });
243
+ formApi = form as unknown as typeof formApi;
244
+ return (
245
+ <Form form={form}>
246
+ <Slider label="Volume" name="volume" onChange={onChange} />
247
+ </Form>
248
+ );
249
+ };
250
+ const result = renderWithProviders(<TestComponent />);
251
+ expect(getThumb(result.container)?.getAttribute("aria-valuenow")).toBe("10");
252
+
253
+ await act(async () => {
254
+ formApi?.setFieldValue("volume", [60]);
255
+ });
256
+ await waitFor(() => {
257
+ expect(getThumb(result.container)?.getAttribute("aria-valuenow")).toBe("60");
258
+ });
259
+ expect(onChange).not.toHaveBeenCalled();
260
+ });
261
+
262
+ it("uncontrolled standalone (defaultValue only) still moves on keyboard input", async () => {
263
+ const onChange = vi.fn();
264
+ const result = renderWithProviders(
265
+ <Slider label="Free" defaultValue={[40]} onChange={onChange} />,
266
+ );
267
+ const thumb = getThumb(result.container);
268
+ expect(thumb?.getAttribute("aria-valuenow")).toBe("40");
269
+ await act(async () => {
270
+ if (thumb) fireEvent.keyDown(thumb, { key: "ArrowRight" });
271
+ });
272
+ await waitFor(() => {
273
+ expect(getThumb(result.container)?.getAttribute("aria-valuenow")).toBe("41");
274
+ });
275
+ expect(onChange).toHaveBeenCalledWith([41]);
276
+ });
277
+ });
278
+
208
279
  describe("field integration", () => {
209
280
  it("should render error text when provided", () => {
210
281
  const result = renderWithProviders(
@@ -688,10 +759,24 @@ describe("Slider", () => {
688
759
  });
689
760
 
690
761
  it("track click arms the left/transform tween then disarms after the jump window", async () => {
691
- const result = renderWithProviders(
692
- // min > 0 so the degenerate unmeasured-layout pointer value stays truthy
693
- <Slider label="Jump" name="jump" value={[60]} min={10} max={110} />,
694
- );
762
+ // Controlled slider with the standard feedback loop (value + onChange
763
+ // echoing back) a bare static `value` is a frozen controlled input
764
+ // now that the upstream value really drives tamagui.
765
+ const JumpExample = () => {
766
+ const [values, setValues] = useState([60]);
767
+ return (
768
+ // min > 0 so the degenerate unmeasured-layout pointer value stays truthy
769
+ <Slider
770
+ label="Jump"
771
+ name="jump"
772
+ value={values}
773
+ onChange={setValues}
774
+ min={10}
775
+ max={110}
776
+ />
777
+ );
778
+ };
779
+ const result = renderWithProviders(<JumpExample />);
695
780
  const thumb = result.container.querySelector('[role="slider"]') as HTMLElement;
696
781
  const track = getTrack(result.container, thumb);
697
782
  expect(track).toBeDefined();
@@ -199,7 +199,26 @@ export const Interactive: Story = {
199
199
  },
200
200
  };
201
201
 
202
+ /**
203
+ * FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY): the right column renders the
204
+ * RAW tamagui Slider beside the house Slider strictly so the difference stays
205
+ * visible. Raw primitives here are by design and labeled — knob/contrast probes
206
+ * skip this story via `parameters.foreignContrastSpecimen`.
207
+ */
202
208
  export const Comparison: Story = {
209
+ name: "Foreign contrast specimen (raw tamagui)",
210
+ parameters: {
211
+ // Machine-readable exemption for knob/contrast probes and the LC-56 linter arm.
212
+ foreignContrastSpecimen: true,
213
+ docs: {
214
+ description: {
215
+ story:
216
+ "FOREIGN CONTRAST SPECIMEN (LC-56 STORY-HONESTY). The right column is the raw " +
217
+ "tamagui Slider, rendered for contrast only: it ignores house knobs and control " +
218
+ "recipes by design. Probes asserting house rendering must skip this story.",
219
+ },
220
+ },
221
+ },
203
222
  render: () => {
204
223
  const ComparisonExample = () => {
205
224
  const [customVal, setCustomVal] = useState([50]);