@oxy.so/bloom 4.17.0 → 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.
- package/docs/adoption-matrix.mdx +4 -4
- package/docs/breadcrumb.mdx +11 -0
- package/docs/cart-panel.mdx +4 -2
- package/docs/checkout-summary.mdx +4 -0
- package/docs/chip.mdx +14 -1
- package/docs/dialog.mdx +5 -4
- package/docs/loading.mdx +11 -0
- package/docs/price-breakdown.mdx +17 -0
- package/docs/rating.mdx +22 -0
- package/docs/stepper.mdx +25 -0
- package/lib/commonjs/breadcrumb/Breadcrumb.js +36 -6
- package/lib/commonjs/breadcrumb/Breadcrumb.js.map +1 -1
- package/lib/commonjs/cart-panel/CartLine.js +32 -10
- package/lib/commonjs/cart-panel/CartLine.js.map +1 -1
- package/lib/commonjs/cart-panel/CartPanel.js +3 -0
- package/lib/commonjs/cart-panel/CartPanel.js.map +1 -1
- package/lib/commonjs/cart-panel/shared.js +2 -0
- package/lib/commonjs/cart-panel/shared.js.map +1 -1
- package/lib/commonjs/checkout-summary/CheckoutConfirm.js +11 -1
- package/lib/commonjs/checkout-summary/CheckoutConfirm.js.map +1 -1
- package/lib/commonjs/chip/Chip.js +3 -1
- package/lib/commonjs/chip/Chip.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.js +15 -6
- package/lib/commonjs/dialog/Dialog.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.web.js +11 -5
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/dialog/placement.js +18 -1
- package/lib/commonjs/dialog/placement.js.map +1 -1
- package/lib/commonjs/loading/Loading.js +7 -3
- package/lib/commonjs/loading/Loading.js.map +1 -1
- package/lib/commonjs/loading/Loading.web.js +7 -3
- package/lib/commonjs/loading/Loading.web.js.map +1 -1
- package/lib/commonjs/loading/LoadingBase.js +49 -2
- package/lib/commonjs/loading/LoadingBase.js.map +1 -1
- package/lib/commonjs/price-breakdown/PriceSummary.js +11 -1
- package/lib/commonjs/price-breakdown/PriceSummary.js.map +1 -1
- package/lib/commonjs/price-breakdown/PriceSummaryLine.js +13 -1
- package/lib/commonjs/price-breakdown/PriceSummaryLine.js.map +1 -1
- package/lib/commonjs/rating/Rating.js +90 -4
- package/lib/commonjs/rating/Rating.js.map +1 -1
- package/lib/commonjs/stepper/Stepper.js +18 -5
- package/lib/commonjs/stepper/Stepper.js.map +1 -1
- package/lib/module/breadcrumb/Breadcrumb.js +36 -6
- package/lib/module/breadcrumb/Breadcrumb.js.map +1 -1
- package/lib/module/cart-panel/CartLine.js +32 -10
- package/lib/module/cart-panel/CartLine.js.map +1 -1
- package/lib/module/cart-panel/CartPanel.js +3 -0
- package/lib/module/cart-panel/CartPanel.js.map +1 -1
- package/lib/module/cart-panel/shared.js +2 -0
- package/lib/module/cart-panel/shared.js.map +1 -1
- package/lib/module/checkout-summary/CheckoutConfirm.js +11 -1
- package/lib/module/checkout-summary/CheckoutConfirm.js.map +1 -1
- package/lib/module/chip/Chip.js +3 -1
- package/lib/module/chip/Chip.js.map +1 -1
- package/lib/module/dialog/Dialog.js +16 -7
- package/lib/module/dialog/Dialog.js.map +1 -1
- package/lib/module/dialog/Dialog.web.js +12 -6
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/dialog/placement.js +17 -1
- package/lib/module/dialog/placement.js.map +1 -1
- package/lib/module/loading/Loading.js +8 -4
- package/lib/module/loading/Loading.js.map +1 -1
- package/lib/module/loading/Loading.web.js +8 -4
- package/lib/module/loading/Loading.web.js.map +1 -1
- package/lib/module/loading/LoadingBase.js +49 -3
- package/lib/module/loading/LoadingBase.js.map +1 -1
- package/lib/module/price-breakdown/PriceSummary.js +11 -1
- package/lib/module/price-breakdown/PriceSummary.js.map +1 -1
- package/lib/module/price-breakdown/PriceSummaryLine.js +13 -1
- package/lib/module/price-breakdown/PriceSummaryLine.js.map +1 -1
- package/lib/module/rating/Rating.js +89 -4
- package/lib/module/rating/Rating.js.map +1 -1
- package/lib/module/stepper/Stepper.js +18 -5
- package/lib/module/stepper/Stepper.js.map +1 -1
- package/lib/typescript/commonjs/breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/lib/typescript/commonjs/breadcrumb/types.d.ts +7 -0
- package/lib/typescript/commonjs/breadcrumb/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/cart-panel/CartLine.d.ts +10 -5
- package/lib/typescript/commonjs/cart-panel/CartLine.d.ts.map +1 -1
- package/lib/typescript/commonjs/cart-panel/CartPanel.d.ts +1 -1
- package/lib/typescript/commonjs/cart-panel/CartPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/cart-panel/shared.d.ts +1 -1
- package/lib/typescript/commonjs/cart-panel/shared.d.ts.map +1 -1
- package/lib/typescript/commonjs/cart-panel/types.d.ts +18 -0
- package/lib/typescript/commonjs/cart-panel/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/checkout-summary/CheckoutConfirm.d.ts +4 -1
- package/lib/typescript/commonjs/checkout-summary/CheckoutConfirm.d.ts.map +1 -1
- package/lib/typescript/commonjs/checkout-summary/types.d.ts +6 -0
- package/lib/typescript/commonjs/checkout-summary/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/chip/Chip.d.ts.map +1 -1
- package/lib/typescript/commonjs/chip/types.d.ts +8 -6
- package/lib/typescript/commonjs/chip/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/placement.d.ts +13 -2
- package/lib/typescript/commonjs/dialog/placement.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/types.d.ts +3 -2
- package/lib/typescript/commonjs/dialog/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/loading/Loading.d.ts.map +1 -1
- package/lib/typescript/commonjs/loading/Loading.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/loading/LoadingBase.d.ts +18 -0
- package/lib/typescript/commonjs/loading/LoadingBase.d.ts.map +1 -1
- package/lib/typescript/commonjs/loading/types.d.ts +11 -0
- package/lib/typescript/commonjs/loading/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/price-breakdown/PriceSummary.d.ts.map +1 -1
- package/lib/typescript/commonjs/price-breakdown/PriceSummaryLine.d.ts +3 -1
- package/lib/typescript/commonjs/price-breakdown/PriceSummaryLine.d.ts.map +1 -1
- package/lib/typescript/commonjs/price-breakdown/types.d.ts +12 -0
- package/lib/typescript/commonjs/price-breakdown/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/rating/Rating.d.ts +3 -1
- package/lib/typescript/commonjs/rating/Rating.d.ts.map +1 -1
- package/lib/typescript/commonjs/rating/index.d.ts +1 -1
- package/lib/typescript/commonjs/rating/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/rating/types.d.ts +20 -0
- package/lib/typescript/commonjs/rating/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/stepper/Stepper.d.ts +1 -1
- package/lib/typescript/commonjs/stepper/Stepper.d.ts.map +1 -1
- package/lib/typescript/commonjs/stepper/types.d.ts +9 -0
- package/lib/typescript/commonjs/stepper/types.d.ts.map +1 -1
- package/lib/typescript/module/breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/lib/typescript/module/breadcrumb/types.d.ts +7 -0
- package/lib/typescript/module/breadcrumb/types.d.ts.map +1 -1
- package/lib/typescript/module/cart-panel/CartLine.d.ts +10 -5
- package/lib/typescript/module/cart-panel/CartLine.d.ts.map +1 -1
- package/lib/typescript/module/cart-panel/CartPanel.d.ts +1 -1
- package/lib/typescript/module/cart-panel/CartPanel.d.ts.map +1 -1
- package/lib/typescript/module/cart-panel/shared.d.ts +1 -1
- package/lib/typescript/module/cart-panel/shared.d.ts.map +1 -1
- package/lib/typescript/module/cart-panel/types.d.ts +18 -0
- package/lib/typescript/module/cart-panel/types.d.ts.map +1 -1
- package/lib/typescript/module/checkout-summary/CheckoutConfirm.d.ts +4 -1
- package/lib/typescript/module/checkout-summary/CheckoutConfirm.d.ts.map +1 -1
- package/lib/typescript/module/checkout-summary/types.d.ts +6 -0
- package/lib/typescript/module/checkout-summary/types.d.ts.map +1 -1
- package/lib/typescript/module/chip/Chip.d.ts.map +1 -1
- package/lib/typescript/module/chip/types.d.ts +8 -6
- package/lib/typescript/module/chip/types.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/module/dialog/placement.d.ts +13 -2
- package/lib/typescript/module/dialog/placement.d.ts.map +1 -1
- package/lib/typescript/module/dialog/types.d.ts +3 -2
- package/lib/typescript/module/dialog/types.d.ts.map +1 -1
- package/lib/typescript/module/loading/Loading.d.ts.map +1 -1
- package/lib/typescript/module/loading/Loading.web.d.ts.map +1 -1
- package/lib/typescript/module/loading/LoadingBase.d.ts +18 -0
- package/lib/typescript/module/loading/LoadingBase.d.ts.map +1 -1
- package/lib/typescript/module/loading/types.d.ts +11 -0
- package/lib/typescript/module/loading/types.d.ts.map +1 -1
- package/lib/typescript/module/price-breakdown/PriceSummary.d.ts.map +1 -1
- package/lib/typescript/module/price-breakdown/PriceSummaryLine.d.ts +3 -1
- package/lib/typescript/module/price-breakdown/PriceSummaryLine.d.ts.map +1 -1
- package/lib/typescript/module/price-breakdown/types.d.ts +12 -0
- package/lib/typescript/module/price-breakdown/types.d.ts.map +1 -1
- package/lib/typescript/module/rating/Rating.d.ts +3 -1
- package/lib/typescript/module/rating/Rating.d.ts.map +1 -1
- package/lib/typescript/module/rating/index.d.ts +1 -1
- package/lib/typescript/module/rating/index.d.ts.map +1 -1
- package/lib/typescript/module/rating/types.d.ts +20 -0
- package/lib/typescript/module/rating/types.d.ts.map +1 -1
- package/lib/typescript/module/stepper/Stepper.d.ts +1 -1
- package/lib/typescript/module/stepper/Stepper.d.ts.map +1 -1
- package/lib/typescript/module/stepper/types.d.ts +9 -0
- package/lib/typescript/module/stepper/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/breadcrumb/Breadcrumb.tsx +29 -4
- package/src/breadcrumb/types.ts +7 -0
- package/src/cart-panel/CartLine.tsx +30 -7
- package/src/cart-panel/CartPanel.tsx +3 -0
- package/src/cart-panel/shared.ts +11 -1
- package/src/cart-panel/types.ts +18 -0
- package/src/checkout-summary/CheckoutConfirm.tsx +9 -0
- package/src/checkout-summary/types.ts +6 -0
- package/src/chip/Chip.tsx +3 -1
- package/src/chip/types.ts +8 -6
- package/src/dialog/Dialog.tsx +19 -8
- package/src/dialog/Dialog.web.tsx +15 -7
- package/src/dialog/placement.ts +19 -2
- package/src/dialog/types.ts +3 -2
- package/src/loading/Loading.tsx +6 -2
- package/src/loading/Loading.web.tsx +6 -2
- package/src/loading/LoadingBase.tsx +55 -5
- package/src/loading/types.ts +11 -0
- package/src/price-breakdown/PriceSummary.tsx +10 -0
- package/src/price-breakdown/PriceSummaryLine.tsx +12 -0
- package/src/price-breakdown/types.ts +12 -0
- package/src/rating/Rating.tsx +87 -3
- package/src/rating/index.ts +1 -0
- package/src/rating/types.ts +21 -0
- package/src/stepper/Stepper.tsx +18 -5
- package/src/stepper/types.ts +9 -0
|
@@ -82,6 +82,7 @@ function PriceSummaryComponent({
|
|
|
82
82
|
label={line.label}
|
|
83
83
|
sublabel={line.sublabel}
|
|
84
84
|
amount={line.amount}
|
|
85
|
+
secondaryAmount={line.secondaryAmount}
|
|
85
86
|
tone={line.tone}
|
|
86
87
|
state={line.state}
|
|
87
88
|
info={line.info}
|
|
@@ -137,6 +138,15 @@ function PriceSummaryComponent({
|
|
|
137
138
|
>
|
|
138
139
|
{total.amount ?? pendingPlaceholder}
|
|
139
140
|
</Text>
|
|
141
|
+
{total.secondaryAmount ? (
|
|
142
|
+
<Text
|
|
143
|
+
variant="body-2-regular"
|
|
144
|
+
testID={testID ? `${testID}-total-secondary-amount` : undefined}
|
|
145
|
+
style={{ color: paint.textSecondary, fontVariant: ['tabular-nums'], textAlign: 'right' }}
|
|
146
|
+
>
|
|
147
|
+
{total.secondaryAmount}
|
|
148
|
+
</Text>
|
|
149
|
+
) : null}
|
|
140
150
|
{totalCaveat ? (
|
|
141
151
|
<Text
|
|
142
152
|
variant="caption-1-regular"
|
|
@@ -27,6 +27,8 @@ import type { PriceSummaryLineProps } from './types';
|
|
|
27
27
|
* state "Estimated" / "Pending" in caption-1 under the amount, so the
|
|
28
28
|
* caveat travels with the NUMBER rather than with the label; the
|
|
29
29
|
* row keeps its own reading order for a screen reader
|
|
30
|
+
* secondary `secondaryAmount` (a second currency) in body-2-regular
|
|
31
|
+
* secondary under the amount, tabular, right-aligned
|
|
30
32
|
* info a 32 round glyph after the label, opening a `Popover`
|
|
31
33
|
* height 32 minimum, whether or not the line has the info affordance
|
|
32
34
|
*
|
|
@@ -38,6 +40,7 @@ function PriceSummaryLineComponent({
|
|
|
38
40
|
label,
|
|
39
41
|
sublabel,
|
|
40
42
|
amount,
|
|
43
|
+
secondaryAmount,
|
|
41
44
|
tone = 'default',
|
|
42
45
|
state = 'final',
|
|
43
46
|
info,
|
|
@@ -120,6 +123,15 @@ function PriceSummaryLineComponent({
|
|
|
120
123
|
>
|
|
121
124
|
{amount ?? pendingPlaceholder}
|
|
122
125
|
</Text>
|
|
126
|
+
{secondaryAmount ? (
|
|
127
|
+
<Text
|
|
128
|
+
variant="body-2-regular"
|
|
129
|
+
testID={testID ? `${testID}-secondary-amount` : undefined}
|
|
130
|
+
style={{ color: paint.textSecondary, fontVariant: ['tabular-nums'], textAlign: 'right' }}
|
|
131
|
+
>
|
|
132
|
+
{secondaryAmount}
|
|
133
|
+
</Text>
|
|
134
|
+
) : null}
|
|
123
135
|
{caveat ? (
|
|
124
136
|
<Text
|
|
125
137
|
variant="caption-1-regular"
|
|
@@ -32,6 +32,12 @@ export interface PriceLine {
|
|
|
32
32
|
* app owns currency, locale and the minus sign. Omit it for a `pending` line.
|
|
33
33
|
*/
|
|
34
34
|
amount?: string;
|
|
35
|
+
/**
|
|
36
|
+
* A second, PRE-FORMATTED rendering of the same amount, drawn de-emphasised
|
|
37
|
+
* under it — the buyer's currency beside the shop's: `"≈ 12,00 €"`. Like
|
|
38
|
+
* `ListingPriceLine.secondary`, it is drawn as given; nothing converts.
|
|
39
|
+
*/
|
|
40
|
+
secondaryAmount?: string;
|
|
35
41
|
/** Default `default`. */
|
|
36
42
|
tone?: PriceLineTone;
|
|
37
43
|
/** Default `final`. */
|
|
@@ -54,6 +60,12 @@ export interface PriceTotal {
|
|
|
54
60
|
label: string;
|
|
55
61
|
/** PRE-FORMATTED, like every other amount here. */
|
|
56
62
|
amount?: string;
|
|
63
|
+
/**
|
|
64
|
+
* A second, PRE-FORMATTED rendering of the same amount, drawn de-emphasised
|
|
65
|
+
* under it — the buyer's currency beside the shop's: `"≈ 12,00 €"`. Like
|
|
66
|
+
* `ListingPriceLine.secondary`, it is drawn as given; nothing converts.
|
|
67
|
+
*/
|
|
68
|
+
secondaryAmount?: string;
|
|
57
69
|
/** A quieter line under the total — "Includes taxes". */
|
|
58
70
|
note?: string;
|
|
59
71
|
/** Default `final`. */
|
package/src/rating/Rating.tsx
CHANGED
|
@@ -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
|
-
|
|
76
|
-
|
|
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:
|
|
164
|
+
<Text variant={config.count} style={{ color: countPaint }}>
|
|
81
165
|
{countText}
|
|
82
166
|
</Text>
|
|
83
167
|
)}
|
package/src/rating/index.ts
CHANGED
package/src/rating/types.ts
CHANGED
|
@@ -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.
|
package/src/stepper/Stepper.tsx
CHANGED
|
@@ -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
|
package/src/stepper/types.ts
CHANGED
|
@@ -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
|
}
|