@butternutbox/pawprint-native 0.5.1 → 0.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.
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +11 -0
- package/dist/index.cjs +94 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.js +94 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/molecules/ButtonDock/ButtonDock.tsx +10 -4
- package/src/components/molecules/Notification/Notification.tsx +36 -10
- package/src/components/molecules/Radio/Radio.stories.tsx +46 -0
- package/src/components/molecules/Radio/Radio.test.tsx +18 -0
- package/src/components/molecules/Radio/Radio.tsx +19 -1
package/package.json
CHANGED
|
@@ -22,12 +22,14 @@ const StyledDockRoot = styled(View)<{
|
|
|
22
22
|
dockBorderTopWidth: number
|
|
23
23
|
dockBorderTopColor: string
|
|
24
24
|
dockPaddingVertical: number
|
|
25
|
+
dockPaddingHorizontal: number
|
|
25
26
|
}>(
|
|
26
27
|
({
|
|
27
28
|
dockBgColor,
|
|
28
29
|
dockBorderTopWidth,
|
|
29
30
|
dockBorderTopColor,
|
|
30
|
-
dockPaddingVertical
|
|
31
|
+
dockPaddingVertical,
|
|
32
|
+
dockPaddingHorizontal
|
|
31
33
|
}) => ({
|
|
32
34
|
alignItems: "center",
|
|
33
35
|
justifyContent: "center",
|
|
@@ -35,7 +37,8 @@ const StyledDockRoot = styled(View)<{
|
|
|
35
37
|
backgroundColor: dockBgColor,
|
|
36
38
|
borderTopWidth: dockBorderTopWidth,
|
|
37
39
|
borderTopColor: dockBorderTopColor,
|
|
38
|
-
paddingVertical: dockPaddingVertical
|
|
40
|
+
paddingVertical: dockPaddingVertical,
|
|
41
|
+
paddingHorizontal: dockPaddingHorizontal
|
|
39
42
|
})
|
|
40
43
|
)
|
|
41
44
|
|
|
@@ -51,7 +54,7 @@ const StyledStackedInner = styled(View)<{ innerGap: number }>(
|
|
|
51
54
|
const StyledButtonGroup = styled(View)<{
|
|
52
55
|
groupDirection: "column" | "row"
|
|
53
56
|
groupAlign: "stretch" | "center"
|
|
54
|
-
groupJustify: "center" | "space-
|
|
57
|
+
groupJustify: "center" | "space-between"
|
|
55
58
|
groupGap: number
|
|
56
59
|
}>(({ groupDirection, groupAlign, groupJustify, groupGap }) => ({
|
|
57
60
|
flexDirection: groupDirection,
|
|
@@ -105,6 +108,9 @@ const ButtonDock = React.forwardRef<View, ButtonDockProps>(
|
|
|
105
108
|
dockPaddingVertical={parseTokenValue(
|
|
106
109
|
buttonDock.spacing[variant].mobile.topPadding
|
|
107
110
|
)}
|
|
111
|
+
dockPaddingHorizontal={parseTokenValue(
|
|
112
|
+
buttonDock.spacing[variant].mobile.horizontalPadding
|
|
113
|
+
)}
|
|
108
114
|
{...rest}
|
|
109
115
|
>
|
|
110
116
|
{isStacked ? (
|
|
@@ -134,7 +140,7 @@ const ButtonDock = React.forwardRef<View, ButtonDockProps>(
|
|
|
134
140
|
<StyledButtonGroup
|
|
135
141
|
groupDirection="row"
|
|
136
142
|
groupAlign="center"
|
|
137
|
-
groupJustify="space-
|
|
143
|
+
groupJustify="space-between"
|
|
138
144
|
groupGap={groupGap}
|
|
139
145
|
>
|
|
140
146
|
{children}
|
|
@@ -29,7 +29,7 @@ type InlineVariantProps = BaseProps & {
|
|
|
29
29
|
title?: string
|
|
30
30
|
onClose?: () => void
|
|
31
31
|
size?: never
|
|
32
|
-
link?:
|
|
32
|
+
link?: { label: string; href?: string; onPress?: () => void }
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
type ToastVariantProps = BaseProps & {
|
|
@@ -45,7 +45,7 @@ type SystemVariantProps = BaseProps & {
|
|
|
45
45
|
size?: NotificationSize
|
|
46
46
|
title?: never
|
|
47
47
|
onClose?: never
|
|
48
|
-
link?:
|
|
48
|
+
link?: { label: string; href?: string; onPress?: () => void }
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
type NotificationOwnProps =
|
|
@@ -207,7 +207,7 @@ const StyledCloseButton = styled(Pressable)({
|
|
|
207
207
|
* variants — inline (within content flow), toast (floating overlay), and
|
|
208
208
|
* system (full-width banner) — each with four severity types.
|
|
209
209
|
*
|
|
210
|
-
* Note: Unlike the web version,
|
|
210
|
+
* Note: Unlike the web version, links use `onPress` callback instead
|
|
211
211
|
* of `href` for navigation. The `href` prop is also available and opens
|
|
212
212
|
* the URL via `Linking`.
|
|
213
213
|
*
|
|
@@ -216,7 +216,7 @@ const StyledCloseButton = styled(Pressable)({
|
|
|
216
216
|
* @param {boolean} [showIcon=true] - Whether to show the status icon.
|
|
217
217
|
* @param {string} [title] - Optional headline (inline variant only).
|
|
218
218
|
* @param {() => void} [onClose] - Close callback (inline and toast variants).
|
|
219
|
-
* @param {{ label: string; href?: string; onPress?: () => void }} [link] - Optional action link (
|
|
219
|
+
* @param {{ label: string; href?: string; onPress?: () => void }} [link] - Optional action link (all variants).
|
|
220
220
|
* @param {"sm" | "lg"} [size="sm"] - Size variant (system variant only).
|
|
221
221
|
* @param {React.ReactNode} children - The notification body text.
|
|
222
222
|
*
|
|
@@ -286,12 +286,24 @@ export const Notification = React.forwardRef<View, NotificationProps>(
|
|
|
286
286
|
aria-label={type}
|
|
287
287
|
/>
|
|
288
288
|
)}
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
289
|
+
<View style={{ flexDirection: "column", gap: 8, flex: 1 }}>
|
|
290
|
+
<Typography
|
|
291
|
+
token={systemNotifications.notifications.typography.default}
|
|
292
|
+
color={systemNotifications.notification.colour.text.default}
|
|
293
|
+
>
|
|
294
|
+
{children}
|
|
295
|
+
</Typography>
|
|
296
|
+
{link && (
|
|
297
|
+
<Link
|
|
298
|
+
href={link.href}
|
|
299
|
+
onPress={link.onPress}
|
|
300
|
+
weight="semiBold"
|
|
301
|
+
size="md"
|
|
302
|
+
>
|
|
303
|
+
{link.label}
|
|
304
|
+
</Link>
|
|
305
|
+
)}
|
|
306
|
+
</View>
|
|
295
307
|
</StyledSystemRoot>
|
|
296
308
|
)
|
|
297
309
|
}
|
|
@@ -408,6 +420,20 @@ export const Notification = React.forwardRef<View, NotificationProps>(
|
|
|
408
420
|
</Typography>
|
|
409
421
|
</StyledInlineCopy>
|
|
410
422
|
</StyledCopyRow>
|
|
423
|
+
{link && (
|
|
424
|
+
<StyledLinkWrapper
|
|
425
|
+
linkPaddingLeft={parseTokenValue(content.copy.spacing.gap)}
|
|
426
|
+
>
|
|
427
|
+
<Link
|
|
428
|
+
href={link.href}
|
|
429
|
+
onPress={link.onPress}
|
|
430
|
+
weight="semiBold"
|
|
431
|
+
size="md"
|
|
432
|
+
>
|
|
433
|
+
{link.label}
|
|
434
|
+
</Link>
|
|
435
|
+
</StyledLinkWrapper>
|
|
436
|
+
)}
|
|
411
437
|
</StyledContents>
|
|
412
438
|
{onClose && (
|
|
413
439
|
<StyledCloseButton
|
|
@@ -3,6 +3,7 @@ import { View, StyleSheet } from "react-native"
|
|
|
3
3
|
import { RadioGroup } from "./RadioGroup"
|
|
4
4
|
import type { RadioGroupProps } from "./RadioGroup"
|
|
5
5
|
import { Typography } from "../../atoms/Typography"
|
|
6
|
+
import { StarRate } from "@butternutbox/pawprint-icons/core"
|
|
6
7
|
|
|
7
8
|
export default {
|
|
8
9
|
title: "Molecules/Radio",
|
|
@@ -95,6 +96,51 @@ export const TileVariant = () => (
|
|
|
95
96
|
</View>
|
|
96
97
|
)
|
|
97
98
|
|
|
99
|
+
export const WithTag = () => (
|
|
100
|
+
<View style={styles.column}>
|
|
101
|
+
<View style={styles.section}>
|
|
102
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
103
|
+
Tile with tag
|
|
104
|
+
</Typography>
|
|
105
|
+
<RadioGroup name="tag-tile" defaultValue="1">
|
|
106
|
+
<RadioGroup.Radio
|
|
107
|
+
variant="tile"
|
|
108
|
+
value="1"
|
|
109
|
+
label="1 pouch over 2 days"
|
|
110
|
+
subText="400g pouches"
|
|
111
|
+
tag={{ children: "Save up to £12.20 per box" }}
|
|
112
|
+
/>
|
|
113
|
+
<RadioGroup.Radio
|
|
114
|
+
variant="tile"
|
|
115
|
+
value="2"
|
|
116
|
+
label="1 pouch per day"
|
|
117
|
+
subText="200g pouches"
|
|
118
|
+
/>
|
|
119
|
+
</RadioGroup>
|
|
120
|
+
</View>
|
|
121
|
+
|
|
122
|
+
<View style={styles.section}>
|
|
123
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
124
|
+
Tag variants & icon
|
|
125
|
+
</Typography>
|
|
126
|
+
<RadioGroup name="tag-variants" defaultValue="1">
|
|
127
|
+
<RadioGroup.Radio
|
|
128
|
+
value="1"
|
|
129
|
+
label="Most popular"
|
|
130
|
+
subText="Recommended for most dogs"
|
|
131
|
+
tag={{ children: "Best value", variant: "promo", icon: StarRate }}
|
|
132
|
+
/>
|
|
133
|
+
<RadioGroup.Radio
|
|
134
|
+
value="2"
|
|
135
|
+
label="Flexible plan"
|
|
136
|
+
subText="Change anytime"
|
|
137
|
+
tag={{ children: "New", variant: "success" }}
|
|
138
|
+
/>
|
|
139
|
+
</RadioGroup>
|
|
140
|
+
</View>
|
|
141
|
+
</View>
|
|
142
|
+
)
|
|
143
|
+
|
|
98
144
|
export const States = () => (
|
|
99
145
|
<View style={styles.column}>
|
|
100
146
|
<View style={styles.section}>
|
|
@@ -40,6 +40,24 @@ describe("Radio", () => {
|
|
|
40
40
|
})
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
+
describe("when rendering a tag", () => {
|
|
44
|
+
it("renders the tag when provided", () => {
|
|
45
|
+
renderWithTheme(
|
|
46
|
+
<Radio
|
|
47
|
+
value="chicken"
|
|
48
|
+
label="Chicken"
|
|
49
|
+
tag={{ children: "Save up to £12.20 per box" }}
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
expect(screen.getByText("Save up to £12.20 per box")).toBeInTheDocument()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it("does not render a tag when omitted", () => {
|
|
56
|
+
renderWithTheme(<Radio value="chicken" label="Chicken" />)
|
|
57
|
+
expect(screen.queryByText("Best value")).not.toBeInTheDocument()
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
43
61
|
describe("when component is interactive", () => {
|
|
44
62
|
it("calls onSelect when pressed", async () => {
|
|
45
63
|
const user = userEvent.setup()
|
|
@@ -4,6 +4,7 @@ import styled from "@emotion/native"
|
|
|
4
4
|
import { useTheme } from "@emotion/react"
|
|
5
5
|
import { Typography } from "../../atoms/Typography"
|
|
6
6
|
import { Illustration, type IllustrationProps } from "../../atoms/Illustration"
|
|
7
|
+
import { Tag, type TagProps } from "../../atoms/Tag"
|
|
7
8
|
|
|
8
9
|
export type RadioOwnProps = {
|
|
9
10
|
value: string
|
|
@@ -11,6 +12,7 @@ export type RadioOwnProps = {
|
|
|
11
12
|
label?: React.ReactNode
|
|
12
13
|
subText?: React.ReactNode
|
|
13
14
|
asset?: IllustrationProps
|
|
15
|
+
tag?: TagProps
|
|
14
16
|
disabled?: boolean
|
|
15
17
|
selected?: boolean
|
|
16
18
|
onSelect?: (value: string) => void
|
|
@@ -102,6 +104,13 @@ const StyledAssetWrapper = styled(View)({
|
|
|
102
104
|
alignSelf: "center"
|
|
103
105
|
})
|
|
104
106
|
|
|
107
|
+
const StyledTagWrapper = styled(View)<{ tagTopPadding: number }>(
|
|
108
|
+
({ tagTopPadding }) => ({
|
|
109
|
+
alignItems: "flex-start",
|
|
110
|
+
paddingTop: tagTopPadding
|
|
111
|
+
})
|
|
112
|
+
)
|
|
113
|
+
|
|
105
114
|
/**
|
|
106
115
|
* Radio button component for single selection within a group.
|
|
107
116
|
*
|
|
@@ -110,6 +119,7 @@ const StyledAssetWrapper = styled(View)({
|
|
|
110
119
|
* @param {React.ReactNode} [label] - Main label text or content.
|
|
111
120
|
* @param {React.ReactNode} [subText] - Optional descriptive subtext.
|
|
112
121
|
* @param {IllustrationProps} [asset] - Optional illustration asset for tile variant.
|
|
122
|
+
* @param {TagProps} [tag] - Optional tag rendered below the label/subtext. Accepts the full Tag API (variant, icon, size). Hidden when omitted.
|
|
113
123
|
* @param {boolean} [disabled=false] - Whether the radio is disabled.
|
|
114
124
|
* @param {boolean} [selected=false] - Whether the radio is currently selected.
|
|
115
125
|
* @param {(value: string) => void} [onSelect] - Callback when radio is selected.
|
|
@@ -124,6 +134,7 @@ export const Radio = React.forwardRef<View, RadioProps>(
|
|
|
124
134
|
label,
|
|
125
135
|
subText,
|
|
126
136
|
asset,
|
|
137
|
+
tag,
|
|
127
138
|
disabled = false,
|
|
128
139
|
value,
|
|
129
140
|
selected = false,
|
|
@@ -215,7 +226,7 @@ export const Radio = React.forwardRef<View, RadioProps>(
|
|
|
215
226
|
)}
|
|
216
227
|
</StyledRadioControl>
|
|
217
228
|
|
|
218
|
-
{(label || subText) && (
|
|
229
|
+
{(label || subText || tag) && (
|
|
219
230
|
<StyledTextContent
|
|
220
231
|
textContentGap={parseTokenValue(spacing.content.gap)}
|
|
221
232
|
>
|
|
@@ -232,6 +243,13 @@ export const Radio = React.forwardRef<View, RadioProps>(
|
|
|
232
243
|
{subText}
|
|
233
244
|
</Typography>
|
|
234
245
|
)}
|
|
246
|
+
{tag && (
|
|
247
|
+
<StyledTagWrapper
|
|
248
|
+
tagTopPadding={parseTokenValue(spacing.content.tag.topPadding)}
|
|
249
|
+
>
|
|
250
|
+
<Tag {...tag} />
|
|
251
|
+
</StyledTagWrapper>
|
|
252
|
+
)}
|
|
235
253
|
</StyledTextContent>
|
|
236
254
|
)}
|
|
237
255
|
|