@multiplatform.one/frappe-ui 7.65.2 → 7.67.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 (290) hide show
  1. package/dist/cjs/FormSidebar.cjs +95 -194
  2. package/dist/cjs/FormSidebar.native.js +107 -217
  3. package/dist/cjs/FormSidebar.native.js.map +1 -1
  4. package/dist/cjs/FrappeConnectionIndicator.cjs +5 -24
  5. package/dist/cjs/FrappeConnectionIndicator.native.js +5 -24
  6. package/dist/cjs/FrappeConnectionIndicator.native.js.map +1 -1
  7. package/dist/cjs/FrappeImageView.cjs +46 -65
  8. package/dist/cjs/FrappeImageView.native.js +46 -68
  9. package/dist/cjs/FrappeImageView.native.js.map +1 -1
  10. package/dist/cjs/FrappeListView.cjs +24 -67
  11. package/dist/cjs/FrappeListView.native.js +25 -71
  12. package/dist/cjs/FrappeListView.native.js.map +1 -1
  13. package/dist/cjs/FrappeRecordView.cjs +4 -0
  14. package/dist/cjs/FrappeRecordView.native.js +4 -0
  15. package/dist/cjs/FrappeRecordView.native.js.map +1 -1
  16. package/dist/cjs/FrappeReportBuilder.cjs +21 -18
  17. package/dist/cjs/FrappeReportBuilder.native.js +21 -18
  18. package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
  19. package/dist/cjs/SyncErrorNotice.cjs +8 -36
  20. package/dist/cjs/SyncErrorNotice.native.js +8 -36
  21. package/dist/cjs/SyncErrorNotice.native.js.map +1 -1
  22. package/dist/cjs/desk/DeskFormSidebar.cjs +1 -6
  23. package/dist/cjs/desk/DeskFormSidebar.native.js +1 -6
  24. package/dist/cjs/desk/DeskFormSidebar.native.js.map +1 -1
  25. package/dist/cjs/desk/DeskShell.native.js.map +1 -1
  26. package/dist/cjs/fields/Date/catalog.native.js +0 -1
  27. package/dist/cjs/fields/Date/catalog.native.js.map +1 -1
  28. package/dist/cjs/fields/Date/index.native.js +4 -363
  29. package/dist/cjs/fields/Date/index.native.js.map +1 -1
  30. package/dist/cjs/insights/InsightsFacetTags.cjs +16 -92
  31. package/dist/cjs/insights/InsightsFacetTags.native.js +15 -97
  32. package/dist/cjs/insights/InsightsFacetTags.native.js.map +1 -1
  33. package/dist/cjs/list/FacetBadge.cjs +4 -28
  34. package/dist/cjs/list/FacetBadge.native.js +4 -28
  35. package/dist/cjs/list/FacetBadge.native.js.map +1 -1
  36. package/dist/cjs/list/FacetRail.cjs +37 -128
  37. package/dist/cjs/list/FacetRail.native.js +32 -130
  38. package/dist/cjs/list/FacetRail.native.js.map +1 -1
  39. package/dist/cjs/list/RecordCard.cjs +107 -127
  40. package/dist/cjs/list/RecordCard.native.js +86 -96
  41. package/dist/cjs/list/RecordCard.native.js.map +1 -1
  42. package/dist/cjs/list/ShufflePanel.cjs +57 -36
  43. package/dist/cjs/list/ShufflePanel.native.js +64 -39
  44. package/dist/cjs/list/ShufflePanel.native.js.map +1 -1
  45. package/dist/cjs/record/RecordHero.cjs +7 -85
  46. package/dist/cjs/record/RecordHero.native.js +7 -85
  47. package/dist/cjs/record/RecordHero.native.js.map +1 -1
  48. package/dist/cjs/record/RecordPage.cjs +1 -0
  49. package/dist/cjs/record/RecordPage.native.js +1 -0
  50. package/dist/cjs/record/RecordPage.native.js.map +1 -1
  51. package/dist/cjs/report/ReportViewToolbar.cjs +70 -39
  52. package/dist/cjs/report/ReportViewToolbar.native.js +73 -40
  53. package/dist/cjs/report/ReportViewToolbar.native.js.map +1 -1
  54. package/dist/esm/FormSidebar.mjs +98 -197
  55. package/dist/esm/FormSidebar.mjs.map +1 -1
  56. package/dist/esm/FormSidebar.native.js +110 -220
  57. package/dist/esm/FormSidebar.native.js.map +1 -1
  58. package/dist/esm/FrappeConnectionIndicator.mjs +7 -26
  59. package/dist/esm/FrappeConnectionIndicator.mjs.map +1 -1
  60. package/dist/esm/FrappeConnectionIndicator.native.js +7 -26
  61. package/dist/esm/FrappeConnectionIndicator.native.js.map +1 -1
  62. package/dist/esm/FrappeImageView.mjs +48 -67
  63. package/dist/esm/FrappeImageView.mjs.map +1 -1
  64. package/dist/esm/FrappeImageView.native.js +48 -70
  65. package/dist/esm/FrappeImageView.native.js.map +1 -1
  66. package/dist/esm/FrappeListView.mjs +25 -68
  67. package/dist/esm/FrappeListView.mjs.map +1 -1
  68. package/dist/esm/FrappeListView.native.js +26 -72
  69. package/dist/esm/FrappeListView.native.js.map +1 -1
  70. package/dist/esm/FrappeRecordView.mjs +4 -0
  71. package/dist/esm/FrappeRecordView.mjs.map +1 -1
  72. package/dist/esm/FrappeRecordView.native.js +4 -0
  73. package/dist/esm/FrappeRecordView.native.js.map +1 -1
  74. package/dist/esm/FrappeReportBuilder.mjs +21 -18
  75. package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
  76. package/dist/esm/FrappeReportBuilder.native.js +21 -18
  77. package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
  78. package/dist/esm/SyncErrorNotice.mjs +10 -38
  79. package/dist/esm/SyncErrorNotice.mjs.map +1 -1
  80. package/dist/esm/SyncErrorNotice.native.js +10 -38
  81. package/dist/esm/SyncErrorNotice.native.js.map +1 -1
  82. package/dist/esm/desk/DeskFormSidebar.mjs +1 -6
  83. package/dist/esm/desk/DeskFormSidebar.mjs.map +1 -1
  84. package/dist/esm/desk/DeskFormSidebar.native.js +1 -6
  85. package/dist/esm/desk/DeskFormSidebar.native.js.map +1 -1
  86. package/dist/esm/desk/DeskShell.mjs.map +1 -1
  87. package/dist/esm/desk/DeskShell.native.js.map +1 -1
  88. package/dist/esm/fields/Date/catalog.mjs.map +1 -1
  89. package/dist/esm/fields/Date/catalog.native.js +0 -1
  90. package/dist/esm/fields/Date/catalog.native.js.map +1 -1
  91. package/dist/esm/fields/Date/index.native.js +2 -361
  92. package/dist/esm/fields/Date/index.native.js.map +1 -1
  93. package/dist/esm/insights/InsightsFacetTags.mjs +18 -94
  94. package/dist/esm/insights/InsightsFacetTags.mjs.map +1 -1
  95. package/dist/esm/insights/InsightsFacetTags.native.js +17 -99
  96. package/dist/esm/insights/InsightsFacetTags.native.js.map +1 -1
  97. package/dist/esm/list/FacetBadge.mjs +5 -29
  98. package/dist/esm/list/FacetBadge.mjs.map +1 -1
  99. package/dist/esm/list/FacetBadge.native.js +5 -29
  100. package/dist/esm/list/FacetBadge.native.js.map +1 -1
  101. package/dist/esm/list/FacetRail.mjs +40 -131
  102. package/dist/esm/list/FacetRail.mjs.map +1 -1
  103. package/dist/esm/list/FacetRail.native.js +35 -133
  104. package/dist/esm/list/FacetRail.native.js.map +1 -1
  105. package/dist/esm/list/RecordCard.mjs +107 -127
  106. package/dist/esm/list/RecordCard.mjs.map +1 -1
  107. package/dist/esm/list/RecordCard.native.js +86 -96
  108. package/dist/esm/list/RecordCard.native.js.map +1 -1
  109. package/dist/esm/list/ShufflePanel.mjs +59 -38
  110. package/dist/esm/list/ShufflePanel.mjs.map +1 -1
  111. package/dist/esm/list/ShufflePanel.native.js +66 -41
  112. package/dist/esm/list/ShufflePanel.native.js.map +1 -1
  113. package/dist/esm/record/RecordHero.mjs +8 -86
  114. package/dist/esm/record/RecordHero.mjs.map +1 -1
  115. package/dist/esm/record/RecordHero.native.js +8 -86
  116. package/dist/esm/record/RecordHero.native.js.map +1 -1
  117. package/dist/esm/record/RecordPage.mjs +2 -1
  118. package/dist/esm/record/RecordPage.mjs.map +1 -1
  119. package/dist/esm/record/RecordPage.native.js +2 -1
  120. package/dist/esm/record/RecordPage.native.js.map +1 -1
  121. package/dist/esm/report/ReportViewToolbar.mjs +72 -41
  122. package/dist/esm/report/ReportViewToolbar.mjs.map +1 -1
  123. package/dist/esm/report/ReportViewToolbar.native.js +75 -42
  124. package/dist/esm/report/ReportViewToolbar.native.js.map +1 -1
  125. package/dist/jsx/FormSidebar.mjs +98 -197
  126. package/dist/jsx/FormSidebar.mjs.map +1 -1
  127. package/dist/jsx/FormSidebar.native.js +107 -217
  128. package/dist/jsx/FormSidebar.native.js.map +1 -1
  129. package/dist/jsx/FrappeConnectionIndicator.mjs +7 -26
  130. package/dist/jsx/FrappeConnectionIndicator.mjs.map +1 -1
  131. package/dist/jsx/FrappeConnectionIndicator.native.js +5 -24
  132. package/dist/jsx/FrappeConnectionIndicator.native.js.map +1 -1
  133. package/dist/jsx/FrappeImageView.mjs +48 -67
  134. package/dist/jsx/FrappeImageView.mjs.map +1 -1
  135. package/dist/jsx/FrappeImageView.native.js +46 -68
  136. package/dist/jsx/FrappeImageView.native.js.map +1 -1
  137. package/dist/jsx/FrappeListView.mjs +25 -68
  138. package/dist/jsx/FrappeListView.mjs.map +1 -1
  139. package/dist/jsx/FrappeListView.native.js +25 -71
  140. package/dist/jsx/FrappeListView.native.js.map +1 -1
  141. package/dist/jsx/FrappeRecordView.mjs +4 -0
  142. package/dist/jsx/FrappeRecordView.mjs.map +1 -1
  143. package/dist/jsx/FrappeRecordView.native.js +4 -0
  144. package/dist/jsx/FrappeRecordView.native.js.map +1 -1
  145. package/dist/jsx/FrappeReportBuilder.mjs +21 -18
  146. package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
  147. package/dist/jsx/FrappeReportBuilder.native.js +21 -18
  148. package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
  149. package/dist/jsx/SyncErrorNotice.mjs +10 -38
  150. package/dist/jsx/SyncErrorNotice.mjs.map +1 -1
  151. package/dist/jsx/SyncErrorNotice.native.js +8 -36
  152. package/dist/jsx/SyncErrorNotice.native.js.map +1 -1
  153. package/dist/jsx/desk/DeskFormSidebar.mjs +1 -6
  154. package/dist/jsx/desk/DeskFormSidebar.mjs.map +1 -1
  155. package/dist/jsx/desk/DeskFormSidebar.native.js +1 -6
  156. package/dist/jsx/desk/DeskFormSidebar.native.js.map +1 -1
  157. package/dist/jsx/desk/DeskShell.mjs.map +1 -1
  158. package/dist/jsx/desk/DeskShell.native.js.map +1 -1
  159. package/dist/jsx/fields/Date/catalog.mjs.map +1 -1
  160. package/dist/jsx/fields/Date/catalog.native.js +0 -1
  161. package/dist/jsx/fields/Date/catalog.native.js.map +1 -1
  162. package/dist/jsx/fields/Date/index.native.js +4 -363
  163. package/dist/jsx/fields/Date/index.native.js.map +1 -1
  164. package/dist/jsx/insights/InsightsFacetTags.mjs +18 -94
  165. package/dist/jsx/insights/InsightsFacetTags.mjs.map +1 -1
  166. package/dist/jsx/insights/InsightsFacetTags.native.js +15 -97
  167. package/dist/jsx/insights/InsightsFacetTags.native.js.map +1 -1
  168. package/dist/jsx/list/FacetBadge.mjs +5 -29
  169. package/dist/jsx/list/FacetBadge.mjs.map +1 -1
  170. package/dist/jsx/list/FacetBadge.native.js +4 -28
  171. package/dist/jsx/list/FacetBadge.native.js.map +1 -1
  172. package/dist/jsx/list/FacetRail.mjs +40 -131
  173. package/dist/jsx/list/FacetRail.mjs.map +1 -1
  174. package/dist/jsx/list/FacetRail.native.js +32 -130
  175. package/dist/jsx/list/FacetRail.native.js.map +1 -1
  176. package/dist/jsx/list/RecordCard.mjs +107 -127
  177. package/dist/jsx/list/RecordCard.mjs.map +1 -1
  178. package/dist/jsx/list/RecordCard.native.js +86 -96
  179. package/dist/jsx/list/RecordCard.native.js.map +1 -1
  180. package/dist/jsx/list/ShufflePanel.mjs +59 -38
  181. package/dist/jsx/list/ShufflePanel.mjs.map +1 -1
  182. package/dist/jsx/list/ShufflePanel.native.js +64 -39
  183. package/dist/jsx/list/ShufflePanel.native.js.map +1 -1
  184. package/dist/jsx/record/RecordHero.mjs +8 -86
  185. package/dist/jsx/record/RecordHero.mjs.map +1 -1
  186. package/dist/jsx/record/RecordHero.native.js +7 -85
  187. package/dist/jsx/record/RecordHero.native.js.map +1 -1
  188. package/dist/jsx/record/RecordPage.mjs +2 -1
  189. package/dist/jsx/record/RecordPage.mjs.map +1 -1
  190. package/dist/jsx/record/RecordPage.native.js +1 -0
  191. package/dist/jsx/record/RecordPage.native.js.map +1 -1
  192. package/dist/jsx/report/ReportViewToolbar.mjs +72 -41
  193. package/dist/jsx/report/ReportViewToolbar.mjs.map +1 -1
  194. package/dist/jsx/report/ReportViewToolbar.native.js +73 -40
  195. package/dist/jsx/report/ReportViewToolbar.native.js.map +1 -1
  196. package/package.json +16 -16
  197. package/src/FormSidebar.stories.tsx +1 -1
  198. package/src/FormSidebar.tsx +128 -253
  199. package/src/FrappeConnectionIndicator.tsx +6 -28
  200. package/src/FrappeImageView.stories.tsx +1 -6
  201. package/src/FrappeImageView.tsx +52 -66
  202. package/src/FrappeListView.controls.spec.tsx +3 -2
  203. package/src/FrappeListView.tsx +23 -55
  204. package/src/FrappeRecordView.tsx +16 -3
  205. package/src/FrappeReportBuilder.tsx +21 -19
  206. package/src/SyncErrorNotice.spec.tsx +7 -12
  207. package/src/SyncErrorNotice.stories.tsx +2 -4
  208. package/src/SyncErrorNotice.tsx +13 -41
  209. package/src/desk/DeskFormSidebar.tsx +1 -2
  210. package/src/desk/DeskShell.tsx +1 -0
  211. package/src/fields/Date/catalog.tsx +6 -7
  212. package/src/fields/Date/nativeIsCatalog.spec.tsx +26 -0
  213. package/src/fields/Date/typeParity.spec.tsx +20 -98
  214. package/src/frappeRemainder.designLaw.spec.ts +8 -7
  215. package/src/insights/InsightsFacetTags.tsx +21 -102
  216. package/src/list/FacetBadge.tsx +7 -29
  217. package/src/list/FacetRail.spec.tsx +11 -10
  218. package/src/list/FacetRail.tsx +49 -161
  219. package/src/list/RecordCard.native.tsx +63 -64
  220. package/src/list/RecordCard.spec.tsx +8 -5
  221. package/src/list/RecordCard.tsx +116 -129
  222. package/src/list/ShufflePanel.tsx +65 -38
  223. package/src/record/RecordHero.tsx +11 -51
  224. package/src/record/RecordPage.tsx +6 -1
  225. package/src/report/ReportViewToolbar.spec.tsx +45 -3
  226. package/src/report/ReportViewToolbar.tsx +109 -56
  227. package/types/FormSidebar.d.ts +13 -3
  228. package/types/FormSidebar.d.ts.map +1 -1
  229. package/types/FrappeConnectionIndicator.d.ts +2 -1
  230. package/types/FrappeConnectionIndicator.d.ts.map +1 -1
  231. package/types/FrappeImageView.d.ts.map +1 -1
  232. package/types/FrappeListView.d.ts.map +1 -1
  233. package/types/FrappeRecordView.d.ts.map +1 -1
  234. package/types/FrappeReportBuilder.d.ts.map +1 -1
  235. package/types/SyncErrorNotice.d.ts +4 -6
  236. package/types/SyncErrorNotice.d.ts.map +1 -1
  237. package/types/desk/DeskFormSidebar.d.ts.map +1 -1
  238. package/types/desk/DeskShell.d.ts.map +1 -1
  239. package/types/fields/Date/catalog.d.ts +5 -4
  240. package/types/fields/Date/catalog.d.ts.map +1 -1
  241. package/types/insights/InsightsFacetTags.d.ts +4 -1
  242. package/types/insights/InsightsFacetTags.d.ts.map +1 -1
  243. package/types/list/FacetBadge.d.ts +3 -3
  244. package/types/list/FacetBadge.d.ts.map +1 -1
  245. package/types/list/FacetRail.d.ts +7 -5
  246. package/types/list/FacetRail.d.ts.map +1 -1
  247. package/types/list/RecordCard.d.ts +6 -6
  248. package/types/list/RecordCard.d.ts.map +1 -1
  249. package/types/list/RecordCard.native.d.ts +4 -3
  250. package/types/list/RecordCard.native.d.ts.map +1 -1
  251. package/types/list/ShufflePanel.d.ts +8 -3
  252. package/types/list/ShufflePanel.d.ts.map +1 -1
  253. package/types/record/RecordHero.d.ts +5 -1
  254. package/types/record/RecordHero.d.ts.map +1 -1
  255. package/types/record/RecordPage.d.ts.map +1 -1
  256. package/types/report/ReportViewToolbar.d.ts.map +1 -1
  257. package/dist/cjs/fields/Date/dateTimePickerLoader.cjs +0 -38
  258. package/dist/cjs/fields/Date/dateTimePickerLoader.native.js +0 -42
  259. package/dist/cjs/fields/Date/dateTimePickerLoader.native.js.map +0 -1
  260. package/dist/cjs/fields/Date/sheetKeyboard.cjs +0 -54
  261. package/dist/cjs/fields/Date/sheetKeyboard.native.js +0 -57
  262. package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +0 -1
  263. package/dist/esm/fields/Date/dateTimePickerLoader.mjs +0 -13
  264. package/dist/esm/fields/Date/dateTimePickerLoader.mjs.map +0 -1
  265. package/dist/esm/fields/Date/dateTimePickerLoader.native.js +0 -14
  266. package/dist/esm/fields/Date/dateTimePickerLoader.native.js.map +0 -1
  267. package/dist/esm/fields/Date/sheetKeyboard.mjs +0 -21
  268. package/dist/esm/fields/Date/sheetKeyboard.mjs.map +0 -1
  269. package/dist/esm/fields/Date/sheetKeyboard.native.js +0 -21
  270. package/dist/esm/fields/Date/sheetKeyboard.native.js.map +0 -1
  271. package/dist/jsx/fields/Date/dateTimePickerLoader.mjs +0 -13
  272. package/dist/jsx/fields/Date/dateTimePickerLoader.mjs.map +0 -1
  273. package/dist/jsx/fields/Date/dateTimePickerLoader.native.js +0 -42
  274. package/dist/jsx/fields/Date/dateTimePickerLoader.native.js.map +0 -1
  275. package/dist/jsx/fields/Date/sheetKeyboard.mjs +0 -21
  276. package/dist/jsx/fields/Date/sheetKeyboard.mjs.map +0 -1
  277. package/dist/jsx/fields/Date/sheetKeyboard.native.js +0 -57
  278. package/dist/jsx/fields/Date/sheetKeyboard.native.js.map +0 -1
  279. package/src/fields/Date/dateTimePickerLoader.ts +0 -25
  280. package/src/fields/Date/index.native.tsx +0 -445
  281. package/src/fields/Date/nativeFallback.spec.tsx +0 -21
  282. package/src/fields/Date/nativePresentation.spec.tsx +0 -278
  283. package/src/fields/Date/sheetKeyboard.spec.ts +0 -60
  284. package/src/fields/Date/sheetKeyboard.ts +0 -45
  285. package/types/fields/Date/dateTimePickerLoader.d.ts +0 -11
  286. package/types/fields/Date/dateTimePickerLoader.d.ts.map +0 -1
  287. package/types/fields/Date/index.native.d.ts +0 -14
  288. package/types/fields/Date/index.native.d.ts.map +0 -1
  289. package/types/fields/Date/sheetKeyboard.d.ts +0 -20
  290. package/types/fields/Date/sheetKeyboard.d.ts.map +0 -1
@@ -1,13 +1,8 @@
1
- import { ScrollView, Text, XStack, isWeb } from "@multiplatform.one/components";
1
+ import { Chip, ScrollView, XStack, isWeb, type ChipSize } from "@multiplatform.one/components";
2
2
  import {
3
3
  ensureKeyboardModalityTracking,
4
- keyboardFocusRingProps,
5
- pressTargetHitSlop,
6
4
  sizeKeyBelow,
7
- sizeRecipeForToken,
8
- transitionProps,
9
5
  useResolvedKnobs,
10
- wasKeyboardFocus,
11
6
  } from "@multiplatform.one/theme";
12
7
  import { useRef, useState } from "react";
13
8
 
@@ -30,147 +25,25 @@ export interface FacetRailProps {
30
25
  testID?: string;
31
26
  }
32
27
 
33
- interface RailChipProps {
34
- option: FacetRailOption;
35
- selected: boolean;
36
- tabStop: boolean;
37
- onPress: () => void;
38
- onFocusChip: () => void;
39
- onBlurChip: () => void;
40
- onMove: (direction: -1 | 1 | "home" | "end") => void;
41
- testID?: string;
42
- register: (node: { focus?: () => void } | null) => void;
43
- }
44
-
45
- // Chips paint one full step under the toolbar controls; hitSlop restores the
46
- // 44px press target (DG-LAY-04, ViewSwitcher precedent).
47
- const pipSize = "$1";
48
-
49
- /**
50
- * One chip. Neutral until active; the active chip fills from its tint ramp
51
- * (DF-04 pairing: tint fill, step-12 text), so selected is fill, never a
52
- * sibling border (LC-71). An unselected tinted chip carries a hue pip.
53
- */
54
- function RailChip({
55
- option,
56
- selected,
57
- tabStop,
58
- onPress,
59
- onFocusChip,
60
- onBlurChip,
61
- onMove,
62
- testID,
63
- register,
64
- }: RailChipProps) {
65
- const { knobProps } = useResolvedKnobs();
66
- const chipToken = sizeKeyBelow(knobProps.sizeToken);
67
- const chip = sizeRecipeForToken(chipToken, { family: "chip" });
68
- const count = sizeRecipeForToken(sizeKeyBelow(chipToken), { family: "chip" });
69
- const [kbFocus, setKbFocus] = useState(false);
70
- if (isWeb) ensureKeyboardModalityTracking();
71
- const hue = option.tint;
72
- const fill = selected ? (hue ? `$${hue}5` : "$color5") : hue ? `$${hue}3` : "$color3";
73
- const hoverFill = selected ? fill : hue ? `$${hue}4` : "$color4";
74
- const textColor = selected ? (hue ? `$${hue}12` : "$color12") : hue ? `$${hue}11` : "$color11";
75
- const keys: Record<string, -1 | 1 | "home" | "end"> = {
76
- ArrowRight: 1,
77
- ArrowLeft: -1,
78
- Home: "home",
79
- End: "end",
80
- };
81
-
82
- return (
83
- <XStack
84
- ref={register}
85
- {...knobProps.borderRadius}
86
- backgroundColor={fill as never}
87
- borderWidth={0}
88
- paddingHorizontal={chip.paddingHorizontal}
89
- height={chip.height}
90
- hitSlop={pressTargetHitSlop(chip.height)}
91
- alignItems="center"
92
- gap={chip.gap}
93
- cursor="pointer"
94
- role="radio"
95
- aria-checked={selected}
96
- {...(isWeb ? { tabIndex: tabStop ? 0 : -1 } : undefined)}
97
- {...transitionProps(knobProps.motion.control)}
98
- hoverStyle={{ backgroundColor: hoverFill as never }}
99
- pressStyle={{ backgroundColor: fill as never }}
100
- outlineWidth={0}
101
- focusStyle={{ outlineWidth: 0, backgroundColor: fill as never }}
102
- focusVisibleStyle={{ outlineWidth: 0 }}
103
- {...(isWeb
104
- ? {
105
- onFocus: () => {
106
- onFocusChip();
107
- if (wasKeyboardFocus()) setKbFocus(true);
108
- },
109
- onBlur: () => {
110
- onBlurChip();
111
- setKbFocus(false);
112
- },
113
- onKeyDown: (event: { key?: string; preventDefault?: () => void }) => {
114
- const direction = event.key ? keys[event.key] : undefined;
115
- if (direction !== undefined) {
116
- event.preventDefault?.();
117
- onMove(direction);
118
- return;
119
- }
120
- if (event.key === "Enter" || event.key === " ") {
121
- event.preventDefault?.();
122
- onPress();
123
- }
124
- },
125
- }
126
- : undefined)}
127
- {...(kbFocus ? keyboardFocusRingProps : undefined)}
128
- onPress={onPress}
129
- testID={testID}
130
- >
131
- {hue ? (
132
- <XStack
133
- width={pipSize}
134
- height={pipSize}
135
- borderRadius={1000}
136
- backgroundColor={`$${hue}9` as never}
137
- flexShrink={0}
138
- />
139
- ) : null}
140
- <Text
141
- {...knobProps.label}
142
- fontSize={chip.fontSize}
143
- fontWeight={selected ? "700" : "500"}
144
- color={textColor as never}
145
- textTransform="capitalize"
146
- userSelect="none"
147
- >
148
- {option.label}
149
- </Text>
150
- {typeof option.count === "number" ? (
151
- <Text
152
- {...knobProps.label}
153
- fontSize={count.fontSize}
154
- fontWeight="700"
155
- color={textColor as never}
156
- opacity={0.7}
157
- userSelect="none"
158
- >
159
- {option.count}
160
- </Text>
161
- ) : null}
162
- </XStack>
163
- );
164
- }
28
+ const moves: Record<string, -1 | 1 | "home" | "end"> = {
29
+ ArrowRight: 1,
30
+ ArrowLeft: -1,
31
+ Home: "home",
32
+ End: "end",
33
+ };
165
34
 
166
35
  /**
167
- * A single-select facet as a horizontally scrolling chip rail. One tap
168
- * narrows, a second tap on the active chip clears. One tab stop (LC-49):
169
- * arrows, Home and End move and select like a radiogroup, and the focused
170
- * chip paints the only ring (LC-71). Scrolls on narrow viewports instead of
171
- * wrapping into a wall of chips.
36
+ * A single-select facet as a horizontally scrolling rail of MPO `Chip`s, one
37
+ * step under the toolbar controls (LC-175). One tap narrows, a second tap on
38
+ * the active chip clears. One tab stop (LC-49): arrows, Home and End move and
39
+ * select like a radiogroup, and the focused chip paints the only ring
40
+ * (LC-71). Scrolls on narrow viewports instead of wrapping into a wall of
41
+ * chips. A tinted value paints from its ramp; the active chip takes the
42
+ * theme's selected look (LC-131).
172
43
  */
173
44
  export function FacetRail({ label, value, options, onChange, testID }: FacetRailProps) {
45
+ const { knobProps } = useResolvedKnobs();
46
+ const chipSize = sizeKeyBelow(knobProps.sizeToken) as ChipSize;
174
47
  const itemRefs = useRef<Record<string, { focus?: () => void } | null>>({});
175
48
  const [focusValue, setFocusValue] = useState<string | null>(null);
176
49
  if (isWeb) ensureKeyboardModalityTracking();
@@ -215,24 +88,39 @@ export function FacetRail({ label, value, options, onChange, testID }: FacetRail
215
88
  paddingVertical="$1"
216
89
  testID={testID}
217
90
  >
218
- {options.map((option) => (
219
- <RailChip
220
- key={option.value || "__all"}
221
- option={option}
222
- selected={option.value === value}
223
- tabStop={option.value === anchor}
224
- onPress={() =>
225
- onChange(option.value === value && option.value !== "" ? "" : option.value)
226
- }
227
- onFocusChip={() => setFocusValue(option.value)}
228
- onBlurChip={() => setFocusValue((prev) => (prev === option.value ? null : prev))}
229
- onMove={(direction) => moveFrom(option.value, direction)}
230
- testID={testID ? `${testID}-${option.value || "all"}` : undefined}
231
- register={(node) => {
232
- itemRefs.current[option.value] = node;
233
- }}
234
- />
235
- ))}
91
+ {options.map((option) => {
92
+ const selected = option.value === value;
93
+ return (
94
+ <Chip
95
+ key={option.value || "__all"}
96
+ ref={(node: unknown) => {
97
+ itemRefs.current[option.value] = node as { focus?: () => void } | null;
98
+ }}
99
+ role="radio"
100
+ selected={selected}
101
+ tabIndex={option.value === anchor ? 0 : -1}
102
+ size={chipSize}
103
+ color={option.tint}
104
+ swatch={option.tint && !selected ? (`$${option.tint}9` as never) : undefined}
105
+ count={option.count}
106
+ aria-label={
107
+ typeof option.count === "number" ? `${option.label} ${option.count}` : option.label
108
+ }
109
+ onPress={() => onChange(selected && option.value !== "" ? "" : option.value)}
110
+ onFocus={() => setFocusValue(option.value)}
111
+ onBlur={() => setFocusValue((prev) => (prev === option.value ? null : prev))}
112
+ onKeyDown={(event) => {
113
+ const direction = moves[event.key];
114
+ if (direction === undefined) return;
115
+ event.preventDefault();
116
+ moveFrom(option.value, direction);
117
+ }}
118
+ testID={testID ? `${testID}-${option.value || "all"}` : undefined}
119
+ >
120
+ {option.label}
121
+ </Chip>
122
+ );
123
+ })}
236
124
  </XStack>
237
125
  </ScrollView>
238
126
  );
@@ -3,6 +3,7 @@ import { Button } from "@multiplatform.one/forms";
3
3
  import { transitionProps, useResolvedKnobs } from "@multiplatform.one/theme";
4
4
  import { HeartIcon } from "@phosphor-icons/react";
5
5
  import { useTranslation } from "react-i18next";
6
+ import { useTheme } from "tamagui";
6
7
  import { FacetBadge } from "./FacetBadge";
7
8
  import { ImageWell } from "./ImageWell";
8
9
  import type { RecordCardProps } from "./RecordCard";
@@ -10,9 +11,10 @@ import type { RecordCardProps } from "./RecordCard";
10
11
  export type { RecordCardBadge, RecordCardProps } from "./RecordCard";
11
12
 
12
13
  /**
13
- * Native twin of RecordCard. On React Native an Anchor is a Text node whose
14
- * press the Card (a View with its own responder) claims, so the card's
15
- * press sits on the Card itself and the heart stops it from bubbling there.
14
+ * Native twin of RecordCard, the same MPO media `Card`. On React Native an
15
+ * Anchor is a Text node whose press the Card (a View with its own responder)
16
+ * claims, so the card's press sits on the Card itself and the heart stops it
17
+ * from bubbling there.
16
18
  */
17
19
  export function RecordCard({
18
20
  title,
@@ -28,6 +30,7 @@ export function RecordCard({
28
30
  }: RecordCardProps) {
29
31
  const { t } = useTranslation();
30
32
  const { knobProps, elevation: elevationState } = useResolvedKnobs({ component: "Card" });
33
+ const theme = useTheme();
31
34
 
32
35
  const handleToggleFavorite = (event?: { stopPropagation?: () => void }) => {
33
36
  event?.stopPropagation?.();
@@ -37,28 +40,7 @@ export function RecordCard({
37
40
  return (
38
41
  <Card
39
42
  testID={testID}
40
- {...knobProps.cardSurface}
41
- // Full-bleed media: the card has no inset of its own and its radius
42
- // clips the image well; the body below carries the inset.
43
- padding={0}
44
- gap={0}
45
- overflow="hidden"
46
- data-record-card-bleed=""
47
- elevation={knobProps.elevation}
48
- {...transitionProps(knobProps.motion.control, [
49
- "boxShadow",
50
- "shadowColor",
51
- "shadowOffset",
52
- "shadowOpacity",
53
- "shadowRadius",
54
- "elevation",
55
- ])}
56
- pressStyle={{ scale: 0.98, ...elevationState.pressKnobProps }}
57
- role="button"
58
- aria-label={title}
59
- onPress={() => onPress?.()}
60
- >
61
- <YStack gap={0}>
43
+ media={
62
44
  <YStack position="relative">
63
45
  <ImageWell
64
46
  sources={images}
@@ -80,7 +62,13 @@ export function RecordCard({
80
62
  pressStyle={{ backgroundColor: "$background", scale: 0.92 }}
81
63
  onPress={handleToggleFavorite}
82
64
  col={(favorite.active ? "$red9" : "$color11") as never}
83
- icon={<HeartIcon size={20} weight={favorite.active ? "fill" : "regular"} />}
65
+ icon={
66
+ <HeartIcon
67
+ size={20}
68
+ weight={favorite.active ? "fill" : "regular"}
69
+ color={(favorite.active ? theme.red9 : theme.color11)?.val as string}
70
+ />
71
+ }
84
72
  aria-label={
85
73
  favorite.active
86
74
  ? t("Remove {{name}} from favorites", { name: title })
@@ -92,44 +80,55 @@ export function RecordCard({
92
80
  </XStack>
93
81
  ) : null}
94
82
  </YStack>
95
- <YStack {...knobProps.panelPadding} gap="$1.5">
96
- <XStack gap="$2" alignItems="baseline">
97
- <Text
98
- {...knobProps.heading}
99
- fontWeight="700"
100
- fontSize="$4"
101
- numberOfLines={1}
102
- color="$color12"
103
- flexShrink={1}
104
- >
105
- {title}
106
- </Text>
107
- {code ? (
108
- <Text
109
- fontSize="$2"
110
- fontWeight="700"
111
- color="$color10"
112
- flexShrink={0}
113
- {...({ "data-record-card-code": "" } as Record<string, unknown>)}
114
- >
115
- {code}
116
- </Text>
117
- ) : null}
118
- </XStack>
119
- {subtitle ? (
120
- <Text {...knobProps.body} fontSize="$2" color="$color10" numberOfLines={1}>
121
- {subtitle}
122
- </Text>
123
- ) : null}
124
- {badges.length > 0 ? (
125
- <XStack gap="$1.5" flexWrap="wrap">
126
- {badges.map((badge) => (
127
- <FacetBadge key={badge.value} label={badge.label} tint={badge.tint} size="$3" />
128
- ))}
129
- </XStack>
130
- ) : null}
131
- </YStack>
132
- </YStack>
83
+ }
84
+ {...transitionProps(knobProps.motion.control, [
85
+ "boxShadow",
86
+ "shadowColor",
87
+ "shadowOffset",
88
+ "shadowOpacity",
89
+ "shadowRadius",
90
+ "elevation",
91
+ ])}
92
+ pressStyle={{ scale: 0.98, ...elevationState.pressKnobProps }}
93
+ role="button"
94
+ aria-label={title}
95
+ onPress={() => onPress?.()}
96
+ >
97
+ <XStack gap="$2" alignItems="baseline">
98
+ <Text
99
+ {...knobProps.heading}
100
+ fontWeight="700"
101
+ fontSize="$4"
102
+ numberOfLines={1}
103
+ color="$color12"
104
+ flexShrink={1}
105
+ >
106
+ {title}
107
+ </Text>
108
+ {code ? (
109
+ <Text
110
+ fontSize="$2"
111
+ fontWeight="700"
112
+ color="$color10"
113
+ flexShrink={0}
114
+ {...({ "data-record-card-code": "" } as Record<string, unknown>)}
115
+ >
116
+ {code}
117
+ </Text>
118
+ ) : null}
119
+ </XStack>
120
+ {subtitle ? (
121
+ <Text {...knobProps.body} fontSize="$2" color="$color10" numberOfLines={1}>
122
+ {subtitle}
123
+ </Text>
124
+ ) : null}
125
+ {badges.length > 0 ? (
126
+ <XStack gap="$1.5" flexWrap="wrap">
127
+ {badges.map((badge) => (
128
+ <FacetBadge key={badge.value} label={badge.label} tint={badge.tint} size="$3" />
129
+ ))}
130
+ </XStack>
131
+ ) : null}
133
132
  </Card>
134
133
  );
135
134
  }
@@ -1,6 +1,7 @@
1
- // A record card is full-bleed media over a padded body: the image well runs
2
- // to the card's edges (the card clips it to its radius) and the name, the
3
- // code and the facet pills sit in the body under it, not stickered on the art.
1
+ // A record card is the MPO media Card (LC-175): the image well runs to the
2
+ // card's edges (the card clips it to its radius) and the name, the code and
3
+ // the facet chips sit in the card's inset body under it, not stickered on the
4
+ // art.
4
5
  import { renderWithProviders } from "@multiplatform.one/test-utils";
5
6
  import { cleanup, screen } from "@testing-library/react";
6
7
  import { afterEach, describe, expect, it } from "vitest";
@@ -24,10 +25,12 @@ function renderCard() {
24
25
  }
25
26
 
26
27
  describe("RecordCard full-bleed media", () => {
27
- it("drops the card's inset and clips its media to the radius", () => {
28
+ it("is an MPO media Card: no inset on the frame, media clipped to the radius", () => {
28
29
  renderCard();
29
30
  const card = screen.getByTestId("card");
30
- expect(card.hasAttribute("data-record-card-bleed")).toBe(true);
31
+ expect(card.hasAttribute("data-card-media")).toBe(true);
32
+ expect(card.querySelector("[data-card-media-slot] [data-record-card-media]")).not.toBeNull();
33
+ expect(card.querySelector("[data-card-body]")?.textContent).toContain("Pikachu");
31
34
  expect(card.className).toMatch(/_ox-hidden/);
32
35
  expect(card.className).toMatch(/_oy-hidden/);
33
36
  expect(card.className).toMatch(/_pt-0px/);