@oxy.so/bloom 4.16.1 → 4.18.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 (267) hide show
  1. package/docs/adoption-matrix.mdx +15 -15
  2. package/docs/app-shell.mdx +3 -2
  3. package/docs/breadcrumb.mdx +11 -0
  4. package/docs/button-group.mdx +2 -1
  5. package/docs/button.mdx +24 -0
  6. package/docs/cart-panel.mdx +4 -2
  7. package/docs/checkout-summary.mdx +4 -0
  8. package/docs/chip.mdx +14 -1
  9. package/docs/dialog.mdx +5 -4
  10. package/docs/icons.mdx +53 -0
  11. package/docs/loading.mdx +11 -0
  12. package/docs/page-header.mdx +7 -0
  13. package/docs/price-breakdown.mdx +17 -0
  14. package/docs/rating.mdx +22 -0
  15. package/docs/stepper.mdx +25 -0
  16. package/docs/tabs.mdx +6 -0
  17. package/lib/commonjs/app-shell/AppShellEngine.js +9 -5
  18. package/lib/commonjs/app-shell/AppShellEngine.js.map +1 -1
  19. package/lib/commonjs/breadcrumb/Breadcrumb.js +36 -6
  20. package/lib/commonjs/breadcrumb/Breadcrumb.js.map +1 -1
  21. package/lib/commonjs/button/Button.js +7 -4
  22. package/lib/commonjs/button/Button.js.map +1 -1
  23. package/lib/commonjs/button/Button.web.js +21 -2
  24. package/lib/commonjs/button/Button.web.js.map +1 -1
  25. package/lib/commonjs/button-group/ButtonGroup.js +7 -4
  26. package/lib/commonjs/button-group/ButtonGroup.js.map +1 -1
  27. package/lib/commonjs/cart-panel/CartLine.js +32 -10
  28. package/lib/commonjs/cart-panel/CartLine.js.map +1 -1
  29. package/lib/commonjs/cart-panel/CartPanel.js +3 -0
  30. package/lib/commonjs/cart-panel/CartPanel.js.map +1 -1
  31. package/lib/commonjs/cart-panel/shared.js +2 -0
  32. package/lib/commonjs/cart-panel/shared.js.map +1 -1
  33. package/lib/commonjs/checkout-summary/CheckoutConfirm.js +11 -1
  34. package/lib/commonjs/checkout-summary/CheckoutConfirm.js.map +1 -1
  35. package/lib/commonjs/chip/Chip.js +3 -1
  36. package/lib/commonjs/chip/Chip.js.map +1 -1
  37. package/lib/commonjs/dialog/Dialog.js +15 -6
  38. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  39. package/lib/commonjs/dialog/Dialog.web.js +11 -5
  40. package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
  41. package/lib/commonjs/dialog/placement.js +18 -1
  42. package/lib/commonjs/dialog/placement.js.map +1 -1
  43. package/lib/commonjs/icons/index.js +8 -0
  44. package/lib/commonjs/icons/index.js.map +1 -1
  45. package/lib/commonjs/icons/render-icon.js +63 -0
  46. package/lib/commonjs/icons/render-icon.js.map +1 -0
  47. package/lib/commonjs/loading/Loading.js +7 -3
  48. package/lib/commonjs/loading/Loading.js.map +1 -1
  49. package/lib/commonjs/loading/Loading.web.js +7 -3
  50. package/lib/commonjs/loading/Loading.web.js.map +1 -1
  51. package/lib/commonjs/loading/LoadingBase.js +49 -2
  52. package/lib/commonjs/loading/LoadingBase.js.map +1 -1
  53. package/lib/commonjs/page-header/PageHeader.js +6 -1
  54. package/lib/commonjs/page-header/PageHeader.js.map +1 -1
  55. package/lib/commonjs/price-breakdown/PriceSummary.js +11 -1
  56. package/lib/commonjs/price-breakdown/PriceSummary.js.map +1 -1
  57. package/lib/commonjs/price-breakdown/PriceSummaryLine.js +13 -1
  58. package/lib/commonjs/price-breakdown/PriceSummaryLine.js.map +1 -1
  59. package/lib/commonjs/rating/Rating.js +90 -4
  60. package/lib/commonjs/rating/Rating.js.map +1 -1
  61. package/lib/commonjs/stepper/Stepper.js +18 -5
  62. package/lib/commonjs/stepper/Stepper.js.map +1 -1
  63. package/lib/commonjs/tabs/Tabs.js +8 -1
  64. package/lib/commonjs/tabs/Tabs.js.map +1 -1
  65. package/lib/module/app-shell/AppShellEngine.js +9 -5
  66. package/lib/module/app-shell/AppShellEngine.js.map +1 -1
  67. package/lib/module/breadcrumb/Breadcrumb.js +36 -6
  68. package/lib/module/breadcrumb/Breadcrumb.js.map +1 -1
  69. package/lib/module/button/Button.js +7 -4
  70. package/lib/module/button/Button.js.map +1 -1
  71. package/lib/module/button/Button.web.js +21 -2
  72. package/lib/module/button/Button.web.js.map +1 -1
  73. package/lib/module/button-group/ButtonGroup.js +7 -4
  74. package/lib/module/button-group/ButtonGroup.js.map +1 -1
  75. package/lib/module/cart-panel/CartLine.js +32 -10
  76. package/lib/module/cart-panel/CartLine.js.map +1 -1
  77. package/lib/module/cart-panel/CartPanel.js +3 -0
  78. package/lib/module/cart-panel/CartPanel.js.map +1 -1
  79. package/lib/module/cart-panel/shared.js +2 -0
  80. package/lib/module/cart-panel/shared.js.map +1 -1
  81. package/lib/module/checkout-summary/CheckoutConfirm.js +11 -1
  82. package/lib/module/checkout-summary/CheckoutConfirm.js.map +1 -1
  83. package/lib/module/chip/Chip.js +3 -1
  84. package/lib/module/chip/Chip.js.map +1 -1
  85. package/lib/module/dialog/Dialog.js +16 -7
  86. package/lib/module/dialog/Dialog.js.map +1 -1
  87. package/lib/module/dialog/Dialog.web.js +12 -6
  88. package/lib/module/dialog/Dialog.web.js.map +1 -1
  89. package/lib/module/dialog/placement.js +17 -1
  90. package/lib/module/dialog/placement.js.map +1 -1
  91. package/lib/module/icons/index.js +1 -0
  92. package/lib/module/icons/index.js.map +1 -1
  93. package/lib/module/icons/render-icon.js +59 -0
  94. package/lib/module/icons/render-icon.js.map +1 -0
  95. package/lib/module/loading/Loading.js +8 -4
  96. package/lib/module/loading/Loading.js.map +1 -1
  97. package/lib/module/loading/Loading.web.js +8 -4
  98. package/lib/module/loading/Loading.web.js.map +1 -1
  99. package/lib/module/loading/LoadingBase.js +49 -3
  100. package/lib/module/loading/LoadingBase.js.map +1 -1
  101. package/lib/module/page-header/PageHeader.js +6 -1
  102. package/lib/module/page-header/PageHeader.js.map +1 -1
  103. package/lib/module/price-breakdown/PriceSummary.js +11 -1
  104. package/lib/module/price-breakdown/PriceSummary.js.map +1 -1
  105. package/lib/module/price-breakdown/PriceSummaryLine.js +13 -1
  106. package/lib/module/price-breakdown/PriceSummaryLine.js.map +1 -1
  107. package/lib/module/rating/Rating.js +89 -4
  108. package/lib/module/rating/Rating.js.map +1 -1
  109. package/lib/module/stepper/Stepper.js +18 -5
  110. package/lib/module/stepper/Stepper.js.map +1 -1
  111. package/lib/module/tabs/Tabs.js +8 -1
  112. package/lib/module/tabs/Tabs.js.map +1 -1
  113. package/lib/typescript/commonjs/app-shell/AppShellEngine.d.ts.map +1 -1
  114. package/lib/typescript/commonjs/breadcrumb/Breadcrumb.d.ts.map +1 -1
  115. package/lib/typescript/commonjs/breadcrumb/types.d.ts +7 -0
  116. package/lib/typescript/commonjs/breadcrumb/types.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/button/Button.d.ts.map +1 -1
  118. package/lib/typescript/commonjs/button/Button.web.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/button/types.d.ts +10 -0
  120. package/lib/typescript/commonjs/button/types.d.ts.map +1 -1
  121. package/lib/typescript/commonjs/button-group/ButtonGroup.d.ts.map +1 -1
  122. package/lib/typescript/commonjs/button-group/types.d.ts +9 -0
  123. package/lib/typescript/commonjs/button-group/types.d.ts.map +1 -1
  124. package/lib/typescript/commonjs/cart-panel/CartLine.d.ts +10 -5
  125. package/lib/typescript/commonjs/cart-panel/CartLine.d.ts.map +1 -1
  126. package/lib/typescript/commonjs/cart-panel/CartPanel.d.ts +1 -1
  127. package/lib/typescript/commonjs/cart-panel/CartPanel.d.ts.map +1 -1
  128. package/lib/typescript/commonjs/cart-panel/shared.d.ts +1 -1
  129. package/lib/typescript/commonjs/cart-panel/shared.d.ts.map +1 -1
  130. package/lib/typescript/commonjs/cart-panel/types.d.ts +18 -0
  131. package/lib/typescript/commonjs/cart-panel/types.d.ts.map +1 -1
  132. package/lib/typescript/commonjs/checkout-summary/CheckoutConfirm.d.ts +4 -1
  133. package/lib/typescript/commonjs/checkout-summary/CheckoutConfirm.d.ts.map +1 -1
  134. package/lib/typescript/commonjs/checkout-summary/types.d.ts +6 -0
  135. package/lib/typescript/commonjs/checkout-summary/types.d.ts.map +1 -1
  136. package/lib/typescript/commonjs/chip/Chip.d.ts.map +1 -1
  137. package/lib/typescript/commonjs/chip/types.d.ts +8 -6
  138. package/lib/typescript/commonjs/chip/types.d.ts.map +1 -1
  139. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  140. package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
  141. package/lib/typescript/commonjs/dialog/placement.d.ts +13 -2
  142. package/lib/typescript/commonjs/dialog/placement.d.ts.map +1 -1
  143. package/lib/typescript/commonjs/dialog/types.d.ts +3 -2
  144. package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
  145. package/lib/typescript/commonjs/icons/index.d.ts +2 -0
  146. package/lib/typescript/commonjs/icons/index.d.ts.map +1 -1
  147. package/lib/typescript/commonjs/icons/render-icon.d.ts +55 -0
  148. package/lib/typescript/commonjs/icons/render-icon.d.ts.map +1 -0
  149. package/lib/typescript/commonjs/loading/Loading.d.ts.map +1 -1
  150. package/lib/typescript/commonjs/loading/Loading.web.d.ts.map +1 -1
  151. package/lib/typescript/commonjs/loading/LoadingBase.d.ts +18 -0
  152. package/lib/typescript/commonjs/loading/LoadingBase.d.ts.map +1 -1
  153. package/lib/typescript/commonjs/loading/types.d.ts +11 -0
  154. package/lib/typescript/commonjs/loading/types.d.ts.map +1 -1
  155. package/lib/typescript/commonjs/page-header/PageHeader.d.ts.map +1 -1
  156. package/lib/typescript/commonjs/price-breakdown/PriceSummary.d.ts.map +1 -1
  157. package/lib/typescript/commonjs/price-breakdown/PriceSummaryLine.d.ts +3 -1
  158. package/lib/typescript/commonjs/price-breakdown/PriceSummaryLine.d.ts.map +1 -1
  159. package/lib/typescript/commonjs/price-breakdown/types.d.ts +12 -0
  160. package/lib/typescript/commonjs/price-breakdown/types.d.ts.map +1 -1
  161. package/lib/typescript/commonjs/rating/Rating.d.ts +3 -1
  162. package/lib/typescript/commonjs/rating/Rating.d.ts.map +1 -1
  163. package/lib/typescript/commonjs/rating/index.d.ts +1 -1
  164. package/lib/typescript/commonjs/rating/index.d.ts.map +1 -1
  165. package/lib/typescript/commonjs/rating/types.d.ts +20 -0
  166. package/lib/typescript/commonjs/rating/types.d.ts.map +1 -1
  167. package/lib/typescript/commonjs/stepper/Stepper.d.ts +1 -1
  168. package/lib/typescript/commonjs/stepper/Stepper.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/stepper/types.d.ts +9 -0
  170. package/lib/typescript/commonjs/stepper/types.d.ts.map +1 -1
  171. package/lib/typescript/commonjs/tabs/Tabs.d.ts.map +1 -1
  172. package/lib/typescript/module/app-shell/AppShellEngine.d.ts.map +1 -1
  173. package/lib/typescript/module/breadcrumb/Breadcrumb.d.ts.map +1 -1
  174. package/lib/typescript/module/breadcrumb/types.d.ts +7 -0
  175. package/lib/typescript/module/breadcrumb/types.d.ts.map +1 -1
  176. package/lib/typescript/module/button/Button.d.ts.map +1 -1
  177. package/lib/typescript/module/button/Button.web.d.ts.map +1 -1
  178. package/lib/typescript/module/button/types.d.ts +10 -0
  179. package/lib/typescript/module/button/types.d.ts.map +1 -1
  180. package/lib/typescript/module/button-group/ButtonGroup.d.ts.map +1 -1
  181. package/lib/typescript/module/button-group/types.d.ts +9 -0
  182. package/lib/typescript/module/button-group/types.d.ts.map +1 -1
  183. package/lib/typescript/module/cart-panel/CartLine.d.ts +10 -5
  184. package/lib/typescript/module/cart-panel/CartLine.d.ts.map +1 -1
  185. package/lib/typescript/module/cart-panel/CartPanel.d.ts +1 -1
  186. package/lib/typescript/module/cart-panel/CartPanel.d.ts.map +1 -1
  187. package/lib/typescript/module/cart-panel/shared.d.ts +1 -1
  188. package/lib/typescript/module/cart-panel/shared.d.ts.map +1 -1
  189. package/lib/typescript/module/cart-panel/types.d.ts +18 -0
  190. package/lib/typescript/module/cart-panel/types.d.ts.map +1 -1
  191. package/lib/typescript/module/checkout-summary/CheckoutConfirm.d.ts +4 -1
  192. package/lib/typescript/module/checkout-summary/CheckoutConfirm.d.ts.map +1 -1
  193. package/lib/typescript/module/checkout-summary/types.d.ts +6 -0
  194. package/lib/typescript/module/checkout-summary/types.d.ts.map +1 -1
  195. package/lib/typescript/module/chip/Chip.d.ts.map +1 -1
  196. package/lib/typescript/module/chip/types.d.ts +8 -6
  197. package/lib/typescript/module/chip/types.d.ts.map +1 -1
  198. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  199. package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
  200. package/lib/typescript/module/dialog/placement.d.ts +13 -2
  201. package/lib/typescript/module/dialog/placement.d.ts.map +1 -1
  202. package/lib/typescript/module/dialog/types.d.ts +3 -2
  203. package/lib/typescript/module/dialog/types.d.ts.map +1 -1
  204. package/lib/typescript/module/icons/index.d.ts +2 -0
  205. package/lib/typescript/module/icons/index.d.ts.map +1 -1
  206. package/lib/typescript/module/icons/render-icon.d.ts +55 -0
  207. package/lib/typescript/module/icons/render-icon.d.ts.map +1 -0
  208. package/lib/typescript/module/loading/Loading.d.ts.map +1 -1
  209. package/lib/typescript/module/loading/Loading.web.d.ts.map +1 -1
  210. package/lib/typescript/module/loading/LoadingBase.d.ts +18 -0
  211. package/lib/typescript/module/loading/LoadingBase.d.ts.map +1 -1
  212. package/lib/typescript/module/loading/types.d.ts +11 -0
  213. package/lib/typescript/module/loading/types.d.ts.map +1 -1
  214. package/lib/typescript/module/page-header/PageHeader.d.ts.map +1 -1
  215. package/lib/typescript/module/price-breakdown/PriceSummary.d.ts.map +1 -1
  216. package/lib/typescript/module/price-breakdown/PriceSummaryLine.d.ts +3 -1
  217. package/lib/typescript/module/price-breakdown/PriceSummaryLine.d.ts.map +1 -1
  218. package/lib/typescript/module/price-breakdown/types.d.ts +12 -0
  219. package/lib/typescript/module/price-breakdown/types.d.ts.map +1 -1
  220. package/lib/typescript/module/rating/Rating.d.ts +3 -1
  221. package/lib/typescript/module/rating/Rating.d.ts.map +1 -1
  222. package/lib/typescript/module/rating/index.d.ts +1 -1
  223. package/lib/typescript/module/rating/index.d.ts.map +1 -1
  224. package/lib/typescript/module/rating/types.d.ts +20 -0
  225. package/lib/typescript/module/rating/types.d.ts.map +1 -1
  226. package/lib/typescript/module/stepper/Stepper.d.ts +1 -1
  227. package/lib/typescript/module/stepper/Stepper.d.ts.map +1 -1
  228. package/lib/typescript/module/stepper/types.d.ts +9 -0
  229. package/lib/typescript/module/stepper/types.d.ts.map +1 -1
  230. package/lib/typescript/module/tabs/Tabs.d.ts.map +1 -1
  231. package/package.json +1 -1
  232. package/src/app-shell/AppShellEngine.tsx +9 -5
  233. package/src/breadcrumb/Breadcrumb.tsx +29 -4
  234. package/src/breadcrumb/types.ts +7 -0
  235. package/src/button/Button.tsx +15 -6
  236. package/src/button/Button.web.tsx +30 -3
  237. package/src/button/types.ts +10 -0
  238. package/src/button-group/ButtonGroup.tsx +15 -6
  239. package/src/button-group/types.ts +9 -0
  240. package/src/cart-panel/CartLine.tsx +30 -7
  241. package/src/cart-panel/CartPanel.tsx +3 -0
  242. package/src/cart-panel/shared.ts +11 -1
  243. package/src/cart-panel/types.ts +18 -0
  244. package/src/checkout-summary/CheckoutConfirm.tsx +9 -0
  245. package/src/checkout-summary/types.ts +6 -0
  246. package/src/chip/Chip.tsx +3 -1
  247. package/src/chip/types.ts +8 -6
  248. package/src/dialog/Dialog.tsx +19 -8
  249. package/src/dialog/Dialog.web.tsx +15 -7
  250. package/src/dialog/placement.ts +19 -2
  251. package/src/dialog/types.ts +3 -2
  252. package/src/icons/index.ts +2 -0
  253. package/src/icons/render-icon.tsx +65 -0
  254. package/src/loading/Loading.tsx +6 -2
  255. package/src/loading/Loading.web.tsx +6 -2
  256. package/src/loading/LoadingBase.tsx +55 -5
  257. package/src/loading/types.ts +11 -0
  258. package/src/page-header/PageHeader.tsx +6 -1
  259. package/src/price-breakdown/PriceSummary.tsx +10 -0
  260. package/src/price-breakdown/PriceSummaryLine.tsx +12 -0
  261. package/src/price-breakdown/types.ts +12 -0
  262. package/src/rating/Rating.tsx +87 -3
  263. package/src/rating/index.ts +1 -0
  264. package/src/rating/types.ts +21 -0
  265. package/src/stepper/Stepper.tsx +18 -5
  266. package/src/stepper/types.ts +9 -0
  267. package/src/tabs/Tabs.tsx +3 -0
@@ -2,6 +2,7 @@ import React, { memo } from 'react';
2
2
  import { Platform, View } from 'react-native';
3
3
 
4
4
  import { RiStarFill } from '../icons/remix/RiStarFill';
5
+ import { useDirectionProps } from '../hooks/use-is-rtl';
5
6
  import { useTheme } from '../theme/use-theme';
6
7
  import { Text } from '../typography';
7
8
  import type { TypeScaleVariant } from '../typography/scale';
@@ -21,6 +22,16 @@ import type { RatingProps, RatingSize } from './types';
21
22
  * reviews") on the row — `role="img"` on web, where a plain `div` with an
22
23
  * `aria-label` is not announced, and one `accessible` element on native — so a
23
24
  * screen reader never reads "star, 4.92, open paren, 128".
25
+ *
26
+ * `variant="stars"` draws five stars before the value instead of one, 2px
27
+ * apart, each filled to its share of the value: the unfilled star in
28
+ * `emptyStarColor` (border), and over it the filled star clipped to the
29
+ * fraction. The clip is anchored with a LOGICAL inset (`insetInlineStart`) so a
30
+ * right-to-left row fills from the right — the root carries
31
+ * `useDirectionProps()` for react-native-web to resolve it.
32
+ *
33
+ * `color` / `starColor` / `countColor` recolour it for a surface the theme's
34
+ * text pair cannot sit on (a brand-coloured hero).
24
35
  */
25
36
 
26
37
  const SIZE_CONFIG: Record<RatingSize, { star: number; value: TypeScaleVariant; count: TypeScaleVariant }> = {
@@ -37,6 +48,59 @@ export function formatRatingValue(value: number | string): string {
37
48
 
38
49
  const IS_WEB = Platform.OS === 'web';
39
50
 
51
+ /** The number of stars in the `stars` variant. */
52
+ const STAR_COUNT = 5;
53
+ const STAR_GAP = 2;
54
+
55
+ /** How much of star `index` (0-based) a rating fills, `0..1`. */
56
+ export function starFill(rating: number, index: number): number {
57
+ if (!Number.isFinite(rating)) return 0;
58
+ return Math.min(1, Math.max(0, rating - index));
59
+ }
60
+
61
+ function StarRow({
62
+ rating,
63
+ size,
64
+ fill,
65
+ empty,
66
+ testID,
67
+ }: {
68
+ rating: number;
69
+ size: number;
70
+ fill: string;
71
+ empty: string;
72
+ testID?: string;
73
+ }) {
74
+ return (
75
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: STAR_GAP }} testID={testID}>
76
+ {Array.from({ length: STAR_COUNT }, (_, index) => {
77
+ const share = starFill(rating, index);
78
+ return (
79
+ <View key={index} style={{ width: size, height: size }}>
80
+ <RiStarFill width={size} height={size} fill={empty} />
81
+ {share > 0 ? (
82
+ <View
83
+ testID={testID ? `${testID}-${index}` : undefined}
84
+ style={{
85
+ position: 'absolute',
86
+ top: 0,
87
+ bottom: 0,
88
+ insetInlineStart: 0,
89
+ width: size * share,
90
+ overflow: 'hidden',
91
+ alignItems: 'flex-start',
92
+ }}
93
+ >
94
+ <RiStarFill width={size} height={size} fill={fill} />
95
+ </View>
96
+ ) : null}
97
+ </View>
98
+ );
99
+ })}
100
+ </View>
101
+ );
102
+ }
103
+
40
104
  function RatingComponent({
41
105
  value,
42
106
  count,
@@ -44,11 +108,20 @@ function RatingComponent({
44
108
  reviewsLabel = 'reviews',
45
109
  newLabel = 'New',
46
110
  size = 'medium',
111
+ variant = 'compact',
112
+ color,
113
+ starColor,
114
+ countColor,
115
+ emptyStarColor,
47
116
  accessibilityLabel,
48
117
  style,
49
118
  testID,
50
119
  }: RatingProps) {
51
120
  const theme = useTheme();
121
+ const directionProps = useDirectionProps();
122
+ const textColor = color ?? theme.colors.text;
123
+ const starPaint = starColor ?? textColor;
124
+ const countPaint = countColor ?? color ?? theme.colors.textSecondary;
52
125
  const config = SIZE_CONFIG[size];
53
126
  const rated = value != null && value !== '';
54
127
  const shownValue = rated ? formatRatingValue(value) : newLabel;
@@ -66,18 +139,29 @@ function RatingComponent({
66
139
 
67
140
  return (
68
141
  <View
142
+ {...directionProps}
69
143
  testID={testID}
70
144
  accessible
71
145
  accessibilityLabel={name}
72
146
  {...(IS_WEB ? { role: 'img' as const } : null)}
73
147
  style={[{ flexDirection: 'row', alignItems: 'center', gap: 4 }, style]}
74
148
  >
75
- <RiStarFill width={config.star} height={config.star} fill={theme.colors.text} />
76
- <Text variant={config.value} style={{ color: theme.colors.text, fontVariant: ['tabular-nums'] }}>
149
+ {variant === 'stars' && rated ? (
150
+ <StarRow
151
+ rating={typeof value === 'number' ? value : Number(value)}
152
+ size={config.star}
153
+ fill={starPaint}
154
+ empty={emptyStarColor ?? theme.colors.border}
155
+ testID={testID ? `${testID}-stars` : undefined}
156
+ />
157
+ ) : variant === 'stars' ? null : (
158
+ <RiStarFill width={config.star} height={config.star} fill={starPaint} />
159
+ )}
160
+ <Text variant={config.value} style={{ color: textColor, fontVariant: ['tabular-nums'] }}>
77
161
  {shownValue}
78
162
  </Text>
79
163
  {countText != null && (
80
- <Text variant={config.count} style={{ color: theme.colors.textSecondary }}>
164
+ <Text variant={config.count} style={{ color: countPaint }}>
81
165
  {countText}
82
166
  </Text>
83
167
  )}
@@ -8,4 +8,5 @@ export type {
8
8
  RatingInputSize,
9
9
  RatingProps,
10
10
  RatingSize,
11
+ RatingVariant,
11
12
  } from './types';
@@ -6,6 +6,13 @@ export type RatingSize = 'small' | 'medium';
6
6
  /** `parenthesis` draws "(128)"; `reviews` draws "· 128 reviews". */
7
7
  export type RatingCountStyle = 'parenthesis' | 'reviews';
8
8
 
9
+ /**
10
+ * `compact` (default) is one star and the value; `stars` a full row of `max`
11
+ * stars (five) filled to the value — fractionally, so 4.3 fills the fifth star
12
+ * 30% — before the value.
13
+ */
14
+ export type RatingVariant = 'compact' | 'stars';
15
+
9
16
  export interface RatingProps {
10
17
  /**
11
18
  * The rating on a 5 scale. A number is drawn with up to two decimals (4.9,
@@ -23,6 +30,20 @@ export interface RatingProps {
23
30
  newLabel?: string;
24
31
  /** Default `medium`. */
25
32
  size?: RatingSize;
33
+ /** Default `compact` — one star. `stars` draws a row of five, filled fractionally. */
34
+ variant?: RatingVariant;
35
+ /**
36
+ * Paints the star(s) and the value — and the count, unless `countColor` is
37
+ * given — e.g. white over a brand-coloured hero, where text-primary and
38
+ * text-secondary are illegible. Default: text-primary (count text-secondary).
39
+ */
40
+ color?: string;
41
+ /** The filled star(s) alone, e.g. a gold star beside neutral text. Default `color`. */
42
+ starColor?: string;
43
+ /** The count alone. Default `color` when given, else text-secondary. */
44
+ countColor?: string;
45
+ /** `stars` variant: the unfilled part of each star. Default the theme's border colour. */
46
+ emptyStarColor?: string;
26
47
  /**
27
48
  * Overrides the composed accessible name ("Rated 4.92 out of 5, 128
28
49
  * reviews"), which is English — pass a translated sentence here.
@@ -5,6 +5,7 @@ import { Button } from '../button';
5
5
  import { webDataSet } from '../styles/web-data';
6
6
  import { useAccessibleNameWarning } from '../hooks/use-accessible-name-warning';
7
7
  import { RiAddLine } from '../icons/remix/RiAddLine';
8
+ import { RiDeleteBinLine } from '../icons/remix/RiDeleteBinLine';
8
9
  import { RiSubtractLine } from '../icons/remix/RiSubtractLine';
9
10
  import { useRingOffsetStyle } from '../styles/surface-levels';
10
11
  import { interactiveWebCss, useInteractiveWebCss } from '../styles/interactive-web-css';
@@ -33,6 +34,14 @@ import { useFieldMembership } from '../field/membership';
33
34
  * the tab order, being pointer affordances for the same action. On native it
34
35
  * answers the `increment`/`decrement` accessibility actions (VoiceOver swipe
35
36
  * up/down, TalkBack volume keys).
37
+ *
38
+ * REMOVE AT THE FLOOR is opt-in (`onRemove`). With it, the `−` button at `min`
39
+ * turns into a trash button named `removeLabel` that calls `onRemove` — a
40
+ * basket line that goes from 1 to gone. Without it the button disables at
41
+ * `min`, as it always has. The keyboard and the accessibility actions on the
42
+ * value never remove: an arrow key or a volume-key swipe that deletes is a
43
+ * destructive action behind an arithmetic one. So that a keyboard user can
44
+ * still reach it, the button joins the tab order while it is the remove control.
36
45
  */
37
46
 
38
47
  const IS_WEB = Platform.OS === 'web';
@@ -83,6 +92,8 @@ function StepperComponent({
83
92
  accessibilityLabel,
84
93
  decrementLabel = 'Decrease',
85
94
  incrementLabel = 'Increase',
95
+ onRemove,
96
+ removeLabel = 'Remove',
86
97
  style,
87
98
  testID,
88
99
  }: StepperProps) {
@@ -99,6 +110,8 @@ function StepperComponent({
99
110
 
100
111
  const canDecrement = !disabled && value > min;
101
112
  const canIncrement = !disabled && (max === undefined || value < max);
113
+ // At the floor with `onRemove`, the decrement slot IS the remove control.
114
+ const removes = onRemove !== undefined && !disabled && value <= min;
102
115
 
103
116
  const change = useCallback(
104
117
  (target: number) => {
@@ -180,11 +193,11 @@ function StepperComponent({
180
193
  variant="secondary"
181
194
  size={config.button}
182
195
  iconOnly
183
- icon={RiSubtractLine}
184
- onPress={decrement}
185
- disabled={!canDecrement}
186
- accessibilityLabel={decrementLabel}
187
- tabIndex={-1}
196
+ icon={removes ? RiDeleteBinLine : RiSubtractLine}
197
+ onPress={removes ? onRemove : decrement}
198
+ disabled={!(canDecrement || removes)}
199
+ accessibilityLabel={removes ? removeLabel : decrementLabel}
200
+ tabIndex={removes ? 0 : -1}
188
201
  testID={testID ? `${testID}-decrement` : undefined}
189
202
  />
190
203
  <View
@@ -38,6 +38,15 @@ export interface StepperProps {
38
38
  decrementLabel?: string;
39
39
  /** Name of the `+` button. Default `"Increase"`. */
40
40
  incrementLabel?: string;
41
+ /**
42
+ * Opt-in remove at the floor: at `min` the `−` button becomes a trash button
43
+ * that calls this instead of disabling (a basket line going from 1 to gone).
44
+ * Only the button removes — the keyboard and accessibility actions on the
45
+ * value still stop at `min`. Without it the stepper floors at `min`.
46
+ */
47
+ onRemove?: () => void;
48
+ /** Name of the trash button drawn at `min` with `onRemove`. Default `"Remove"`. */
49
+ removeLabel?: string;
41
50
  style?: StyleProp<ViewStyle>;
42
51
  testID?: string;
43
52
  }
package/src/tabs/Tabs.tsx CHANGED
@@ -780,6 +780,9 @@ const TabsBarComponent = forwardRef<TabsDragController, TabsProps>(function Tabs
780
780
  ref={scrollRef}
781
781
  {...stripA11y}
782
782
  horizontal
783
+ // A tab strip owns its intrinsic cross-axis height. RN ScrollView's
784
+ // default flexGrow: 1 otherwise consumes the list's remaining space.
785
+ style={{ flexGrow: 0, flexShrink: 0 }}
783
786
  showsHorizontalScrollIndicator={false}
784
787
  contentContainerStyle={[containerStyle, style]}
785
788
  onLayout={(e) => {