@butternutbox/pawprint-native 0.0.1
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 +30 -0
- package/COMPONENT_GUIDELINES.md +610 -0
- package/README.md +72 -0
- package/dist/ibm-plex-sans-condensed-400-normal-I2XLJNNB.woff2 +0 -0
- package/dist/ibm-plex-sans-condensed-500-normal-IEQBNVGX.woff2 +0 -0
- package/dist/ibm-plex-sans-condensed-600-normal-UX5ZU5T6.woff2 +0 -0
- package/dist/ibm-plex-sans-condensed-700-normal-4PFYFTSO.woff2 +0 -0
- package/dist/ida-narrow-500-normal-C6I2PK4T.woff2 +0 -0
- package/dist/ida-narrow-700-normal-UPHPRIN6.woff2 +0 -0
- package/dist/index.cjs +2686 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +780 -0
- package/dist/index.d.ts +780 -0
- package/dist/index.js +2617 -0
- package/dist/index.js.map +1 -0
- package/eslint.config.js +3 -0
- package/llms.txt +458 -0
- package/package.json +57 -0
- package/src/components/atoms/Avatar/Avatar.stories.tsx +125 -0
- package/src/components/atoms/Avatar/Avatar.tsx +159 -0
- package/src/components/atoms/Avatar/index.ts +7 -0
- package/src/components/atoms/Badge/Badge.stories.tsx +231 -0
- package/src/components/atoms/Badge/Badge.tsx +184 -0
- package/src/components/atoms/Badge/index.ts +2 -0
- package/src/components/atoms/Button/Button.stories.tsx +145 -0
- package/src/components/atoms/Button/Button.tsx +261 -0
- package/src/components/atoms/Button/index.ts +7 -0
- package/src/components/atoms/Hint/Hint.stories.tsx +84 -0
- package/src/components/atoms/Hint/Hint.tsx +59 -0
- package/src/components/atoms/Hint/index.ts +2 -0
- package/src/components/atoms/Icon/Icon.stories.tsx +200 -0
- package/src/components/atoms/Icon/Icon.tsx +112 -0
- package/src/components/atoms/Icon/index.ts +8 -0
- package/src/components/atoms/IconButton/IconButton.stories.tsx +162 -0
- package/src/components/atoms/IconButton/IconButton.tsx +227 -0
- package/src/components/atoms/IconButton/index.ts +7 -0
- package/src/components/atoms/Illustration/Illustration.stories.tsx +167 -0
- package/src/components/atoms/Illustration/Illustration.tsx +81 -0
- package/src/components/atoms/Illustration/index.ts +6 -0
- package/src/components/atoms/Input/Input.stories.tsx +142 -0
- package/src/components/atoms/Input/Input.tsx +110 -0
- package/src/components/atoms/Input/InputDescription.tsx +49 -0
- package/src/components/atoms/Input/InputError.tsx +39 -0
- package/src/components/atoms/Input/InputField.tsx +119 -0
- package/src/components/atoms/Input/InputLabel.tsx +61 -0
- package/src/components/atoms/Input/index.ts +10 -0
- package/src/components/atoms/Link/Link.stories.tsx +119 -0
- package/src/components/atoms/Link/Link.tsx +118 -0
- package/src/components/atoms/Link/index.ts +2 -0
- package/src/components/atoms/Logo/Logo.registry.ts +39 -0
- package/src/components/atoms/Logo/Logo.tsx +68 -0
- package/src/components/atoms/Logo/index.ts +4 -0
- package/src/components/atoms/Spinner/Spinner.stories.tsx +98 -0
- package/src/components/atoms/Spinner/Spinner.tsx +91 -0
- package/src/components/atoms/Spinner/index.ts +2 -0
- package/src/components/atoms/Switch/Switch.stories.tsx +120 -0
- package/src/components/atoms/Switch/Switch.tsx +196 -0
- package/src/components/atoms/Switch/index.ts +2 -0
- package/src/components/atoms/Tag/Tag.stories.tsx +89 -0
- package/src/components/atoms/Tag/Tag.tsx +122 -0
- package/src/components/atoms/Tag/index.ts +2 -0
- package/src/components/atoms/Typography/Typography.stories.tsx +315 -0
- package/src/components/atoms/Typography/Typography.tsx +284 -0
- package/src/components/atoms/Typography/index.ts +2 -0
- package/src/components/atoms/index.ts +14 -0
- package/src/components/index.ts +2 -0
- package/src/components/molecules/ButtonDock/ButtonDock.stories.tsx +95 -0
- package/src/components/molecules/ButtonDock/ButtonDock.tsx +148 -0
- package/src/components/molecules/ButtonDock/index.ts +2 -0
- package/src/components/molecules/ButtonGroup/ButtonGroup.stories.tsx +82 -0
- package/src/components/molecules/ButtonGroup/ButtonGroup.tsx +94 -0
- package/src/components/molecules/ButtonGroup/index.ts +2 -0
- package/src/components/molecules/Checkbox/Checkbox.stories.tsx +148 -0
- package/src/components/molecules/Checkbox/Checkbox.tsx +279 -0
- package/src/components/molecules/Checkbox/CheckboxGroup.tsx +53 -0
- package/src/components/molecules/Checkbox/index.ts +4 -0
- package/src/components/molecules/Radio/Radio.stories.tsx +182 -0
- package/src/components/molecules/Radio/Radio.tsx +249 -0
- package/src/components/molecules/Radio/RadioGroup.tsx +142 -0
- package/src/components/molecules/Radio/index.ts +4 -0
- package/src/components/molecules/SegmentedControl/SegmentedControl.stories.tsx +151 -0
- package/src/components/molecules/SegmentedControl/SegmentedControl.tsx +323 -0
- package/src/components/molecules/SegmentedControl/index.ts +5 -0
- package/src/components/molecules/Slider/Slider.stories.tsx +144 -0
- package/src/components/molecules/Slider/Slider.tsx +303 -0
- package/src/components/molecules/Slider/index.ts +2 -0
- package/src/components/molecules/index.ts +6 -0
- package/src/fonts/ibm-plex-sans-condensed-400-normal.woff2 +0 -0
- package/src/fonts/ibm-plex-sans-condensed-500-normal.woff2 +0 -0
- package/src/fonts/ibm-plex-sans-condensed-600-normal.woff2 +0 -0
- package/src/fonts/ibm-plex-sans-condensed-700-normal.woff2 +0 -0
- package/src/fonts/ida-narrow-500-normal.woff2 +0 -0
- package/src/fonts/ida-narrow-700-normal.woff2 +0 -0
- package/src/fonts/index.ts +49 -0
- package/src/index.ts +9 -0
- package/src/theme/PawprintProvider.tsx +26 -0
- package/src/theme/ThemeProvider.tsx +63 -0
- package/src/theme/index.ts +5 -0
- package/src/theme/theme.ts +3 -0
- package/src/theme/utils.ts +31 -0
- package/src/types/fonts.d.ts +4 -0
- package/src/types/index.ts +1 -0
- package/src/types/theme.ts +24 -0
- package/tsconfig.json +5 -0
- package/tsup.config.ts +11 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View, StyleSheet, Text } from "react-native"
|
|
3
|
+
import { ButtonDock } from "./ButtonDock"
|
|
4
|
+
import type { ButtonDockProps } from "./ButtonDock"
|
|
5
|
+
import { Button } from "../../atoms/Button"
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: "Molecules/ButtonDock",
|
|
9
|
+
component: ButtonDock,
|
|
10
|
+
argTypes: {
|
|
11
|
+
variant: {
|
|
12
|
+
control: { type: "select" },
|
|
13
|
+
options: ["stacked", "inline"],
|
|
14
|
+
description: "Layout variant (stacked or inline)"
|
|
15
|
+
},
|
|
16
|
+
description: {
|
|
17
|
+
control: { type: "text" },
|
|
18
|
+
description: "Helper text below buttons (stacked only)"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Playground = {
|
|
24
|
+
args: {
|
|
25
|
+
variant: "stacked",
|
|
26
|
+
description: "Helper text goes here"
|
|
27
|
+
},
|
|
28
|
+
render: (args: ButtonDockProps) => (
|
|
29
|
+
<ButtonDock {...args}>
|
|
30
|
+
<Button fullWidth>Continue</Button>
|
|
31
|
+
<Button fullWidth variant="outlined">
|
|
32
|
+
Go back
|
|
33
|
+
</Button>
|
|
34
|
+
</ButtonDock>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const Stacked = () => (
|
|
39
|
+
<View style={styles.column}>
|
|
40
|
+
<ButtonDock variant="stacked" description="Need help? Contact support.">
|
|
41
|
+
<Button fullWidth>Continue</Button>
|
|
42
|
+
<Button fullWidth variant="outlined">
|
|
43
|
+
Go back
|
|
44
|
+
</Button>
|
|
45
|
+
</ButtonDock>
|
|
46
|
+
</View>
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
export const Inline = () => (
|
|
50
|
+
<View style={styles.column}>
|
|
51
|
+
<ButtonDock variant="inline">
|
|
52
|
+
<Button>Confirm</Button>
|
|
53
|
+
<Button variant="outlined">Cancel</Button>
|
|
54
|
+
</ButtonDock>
|
|
55
|
+
</View>
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export const WithLeadingContent = () => (
|
|
59
|
+
<View style={styles.column}>
|
|
60
|
+
<ButtonDock
|
|
61
|
+
variant="stacked"
|
|
62
|
+
leadingContent={
|
|
63
|
+
<Text style={styles.leadingText}>
|
|
64
|
+
By continuing you agree to our terms and conditions.
|
|
65
|
+
</Text>
|
|
66
|
+
}
|
|
67
|
+
description="You can change this later in settings."
|
|
68
|
+
>
|
|
69
|
+
<Button fullWidth>Accept & Continue</Button>
|
|
70
|
+
<Button fullWidth variant="outlined">
|
|
71
|
+
Go back
|
|
72
|
+
</Button>
|
|
73
|
+
</ButtonDock>
|
|
74
|
+
</View>
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
export const StackedSingleButton = () => (
|
|
78
|
+
<View style={styles.column}>
|
|
79
|
+
<ButtonDock variant="stacked" description="Only one action available.">
|
|
80
|
+
<Button fullWidth>Continue</Button>
|
|
81
|
+
</ButtonDock>
|
|
82
|
+
</View>
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const styles = StyleSheet.create({
|
|
86
|
+
column: {
|
|
87
|
+
flexDirection: "column",
|
|
88
|
+
gap: 24
|
|
89
|
+
},
|
|
90
|
+
leadingText: {
|
|
91
|
+
textAlign: "center",
|
|
92
|
+
fontSize: 14,
|
|
93
|
+
color: "#666"
|
|
94
|
+
}
|
|
95
|
+
})
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View, ViewProps } from "react-native"
|
|
3
|
+
import styled from "@emotion/native"
|
|
4
|
+
import { useTheme } from "@emotion/react"
|
|
5
|
+
import { Typography } from "../../atoms/Typography"
|
|
6
|
+
|
|
7
|
+
type ButtonDockVariant = "stacked" | "inline"
|
|
8
|
+
|
|
9
|
+
type ButtonDockOwnProps = {
|
|
10
|
+
variant?: ButtonDockVariant
|
|
11
|
+
leadingContent?: React.ReactNode
|
|
12
|
+
description?: React.ReactNode
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type ButtonDockProps = ButtonDockOwnProps &
|
|
16
|
+
Omit<ViewProps, keyof ButtonDockOwnProps>
|
|
17
|
+
|
|
18
|
+
const parseTokenValue = (value: string): number => parseFloat(value)
|
|
19
|
+
|
|
20
|
+
const StyledDockRoot = styled(View)<{
|
|
21
|
+
dockBgColor: string
|
|
22
|
+
dockBorderTopWidth: number
|
|
23
|
+
dockBorderTopColor: string
|
|
24
|
+
dockPaddingVertical: number
|
|
25
|
+
}>(
|
|
26
|
+
({
|
|
27
|
+
dockBgColor,
|
|
28
|
+
dockBorderTopWidth,
|
|
29
|
+
dockBorderTopColor,
|
|
30
|
+
dockPaddingVertical
|
|
31
|
+
}) => ({
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
width: "100%",
|
|
35
|
+
backgroundColor: dockBgColor,
|
|
36
|
+
borderTopWidth: dockBorderTopWidth,
|
|
37
|
+
borderTopColor: dockBorderTopColor,
|
|
38
|
+
paddingVertical: dockPaddingVertical
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const StyledStackedInner = styled(View)({
|
|
43
|
+
alignItems: "center",
|
|
44
|
+
gap: 16,
|
|
45
|
+
width: "100%",
|
|
46
|
+
maxWidth: 520
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const StyledButtonGroup = styled(View)<{
|
|
50
|
+
groupDirection: "column" | "row"
|
|
51
|
+
groupAlign: "stretch" | "center"
|
|
52
|
+
groupJustify: "center" | "space-around"
|
|
53
|
+
groupGap: number
|
|
54
|
+
}>(({ groupDirection, groupAlign, groupJustify, groupGap }) => ({
|
|
55
|
+
flexDirection: groupDirection,
|
|
56
|
+
alignItems: groupAlign,
|
|
57
|
+
justifyContent: groupJustify,
|
|
58
|
+
gap: groupGap,
|
|
59
|
+
width: "100%",
|
|
60
|
+
...(groupDirection === "column" ? { maxWidth: 520 } : {})
|
|
61
|
+
}))
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A layout container for action buttons, typically placed at the bottom of a
|
|
65
|
+
* page or section.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* import { ButtonDock, Button } from "@butternutbox/pawprint-native"
|
|
70
|
+
*
|
|
71
|
+
* <ButtonDock variant="stacked" description="Helper text">
|
|
72
|
+
* <Button fullWidth>Continue</Button>
|
|
73
|
+
* <Button fullWidth variant="filled" colour="secondary">Back</Button>
|
|
74
|
+
* </ButtonDock>
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @param variant - *(optional)* Layout variant: stacked (default) or inline
|
|
78
|
+
* @param leadingContent - *(optional)* Content rendered above buttons (stacked only)
|
|
79
|
+
* @param description - *(optional)* Helper text rendered below buttons (stacked only)
|
|
80
|
+
*/
|
|
81
|
+
const ButtonDock = React.forwardRef<View, ButtonDockProps>(
|
|
82
|
+
(
|
|
83
|
+
{ variant = "stacked", leadingContent, description, children, ...rest },
|
|
84
|
+
ref
|
|
85
|
+
) => {
|
|
86
|
+
const theme = useTheme()
|
|
87
|
+
const { buttonDock, buttonGroup } = theme.tokens.components
|
|
88
|
+
const { dimensions } = theme.tokens.semantics
|
|
89
|
+
const isStacked = variant === "stacked"
|
|
90
|
+
|
|
91
|
+
const groupGap = parseTokenValue(
|
|
92
|
+
isStacked
|
|
93
|
+
? buttonGroup.spacing.stacked.gap
|
|
94
|
+
: buttonGroup.spacing.sideBySide.gap
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<StyledDockRoot
|
|
99
|
+
ref={ref}
|
|
100
|
+
dockBgColor={buttonDock.colour.background}
|
|
101
|
+
dockBorderTopWidth={parseTokenValue(dimensions.borderWidth.sm)}
|
|
102
|
+
dockBorderTopColor={buttonDock.colour.border}
|
|
103
|
+
dockPaddingVertical={parseTokenValue(
|
|
104
|
+
buttonDock.spacing[variant].desktop.verticalPadding
|
|
105
|
+
)}
|
|
106
|
+
{...rest}
|
|
107
|
+
>
|
|
108
|
+
{isStacked ? (
|
|
109
|
+
<StyledStackedInner>
|
|
110
|
+
{leadingContent}
|
|
111
|
+
<StyledButtonGroup
|
|
112
|
+
groupDirection="column"
|
|
113
|
+
groupAlign="stretch"
|
|
114
|
+
groupJustify="center"
|
|
115
|
+
groupGap={groupGap}
|
|
116
|
+
>
|
|
117
|
+
{children}
|
|
118
|
+
</StyledButtonGroup>
|
|
119
|
+
{description && (
|
|
120
|
+
<Typography
|
|
121
|
+
variant="body"
|
|
122
|
+
size="md"
|
|
123
|
+
weight="medium"
|
|
124
|
+
align="center"
|
|
125
|
+
>
|
|
126
|
+
{typeof description === "string" ? description : description}
|
|
127
|
+
</Typography>
|
|
128
|
+
)}
|
|
129
|
+
</StyledStackedInner>
|
|
130
|
+
) : (
|
|
131
|
+
<StyledButtonGroup
|
|
132
|
+
groupDirection="row"
|
|
133
|
+
groupAlign="center"
|
|
134
|
+
groupJustify="space-around"
|
|
135
|
+
groupGap={groupGap}
|
|
136
|
+
>
|
|
137
|
+
{children}
|
|
138
|
+
</StyledButtonGroup>
|
|
139
|
+
)}
|
|
140
|
+
</StyledDockRoot>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
ButtonDock.displayName = "ButtonDock"
|
|
146
|
+
|
|
147
|
+
export { ButtonDock }
|
|
148
|
+
export type { ButtonDockProps, ButtonDockVariant }
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View, StyleSheet } from "react-native"
|
|
3
|
+
import { ButtonGroup } from "./ButtonGroup"
|
|
4
|
+
import type { ButtonGroupProps } from "./ButtonGroup"
|
|
5
|
+
import { Button } from "../../atoms/Button"
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: "Molecules/ButtonGroup",
|
|
9
|
+
component: ButtonGroup,
|
|
10
|
+
argTypes: {
|
|
11
|
+
layout: {
|
|
12
|
+
control: { type: "select" },
|
|
13
|
+
options: ["stacked", "inline"],
|
|
14
|
+
description: "Layout direction (stacked or inline)"
|
|
15
|
+
},
|
|
16
|
+
description: {
|
|
17
|
+
control: { type: "text" },
|
|
18
|
+
description: "Optional text below buttons"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Playground = {
|
|
24
|
+
args: {
|
|
25
|
+
layout: "stacked",
|
|
26
|
+
description: "Choose an option below"
|
|
27
|
+
},
|
|
28
|
+
render: (args: ButtonGroupProps) => (
|
|
29
|
+
<ButtonGroup {...args}>
|
|
30
|
+
<Button fullWidth>Confirm</Button>
|
|
31
|
+
<Button fullWidth variant="outlined">
|
|
32
|
+
Cancel
|
|
33
|
+
</Button>
|
|
34
|
+
</ButtonGroup>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const Stacked = () => (
|
|
39
|
+
<View style={styles.column}>
|
|
40
|
+
<ButtonGroup layout="stacked" description="Two buttons stacked vertically">
|
|
41
|
+
<Button fullWidth>Primary action</Button>
|
|
42
|
+
<Button fullWidth variant="outlined">
|
|
43
|
+
Secondary action
|
|
44
|
+
</Button>
|
|
45
|
+
</ButtonGroup>
|
|
46
|
+
</View>
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
export const Inline = () => (
|
|
50
|
+
<View style={styles.column}>
|
|
51
|
+
<ButtonGroup layout="inline" description="Two buttons side by side">
|
|
52
|
+
<Button>Confirm</Button>
|
|
53
|
+
<Button variant="outlined">Cancel</Button>
|
|
54
|
+
</ButtonGroup>
|
|
55
|
+
</View>
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
export const SingleButton = () => (
|
|
59
|
+
<View style={styles.column}>
|
|
60
|
+
<ButtonGroup layout="stacked" description="Just one button">
|
|
61
|
+
<Button fullWidth>Continue</Button>
|
|
62
|
+
</ButtonGroup>
|
|
63
|
+
</View>
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export const WithoutDescription = () => (
|
|
67
|
+
<View style={styles.column}>
|
|
68
|
+
<ButtonGroup layout="stacked">
|
|
69
|
+
<Button fullWidth>Confirm</Button>
|
|
70
|
+
<Button fullWidth variant="outlined">
|
|
71
|
+
Cancel
|
|
72
|
+
</Button>
|
|
73
|
+
</ButtonGroup>
|
|
74
|
+
</View>
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
const styles = StyleSheet.create({
|
|
78
|
+
column: {
|
|
79
|
+
flexDirection: "column",
|
|
80
|
+
gap: 24
|
|
81
|
+
}
|
|
82
|
+
})
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View, ViewProps } from "react-native"
|
|
3
|
+
import styled from "@emotion/native"
|
|
4
|
+
import { useTheme } from "@emotion/react"
|
|
5
|
+
import { Typography } from "../../atoms/Typography"
|
|
6
|
+
|
|
7
|
+
export type ButtonGroupLayout = "stacked" | "inline"
|
|
8
|
+
|
|
9
|
+
type ButtonGroupOwnProps = {
|
|
10
|
+
layout?: ButtonGroupLayout
|
|
11
|
+
description?: React.ReactNode
|
|
12
|
+
children: React.ReactNode
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ButtonGroupProps = ButtonGroupOwnProps &
|
|
16
|
+
Omit<ViewProps, keyof ButtonGroupOwnProps>
|
|
17
|
+
|
|
18
|
+
const parseTokenValue = (value: string): number => parseFloat(value)
|
|
19
|
+
|
|
20
|
+
const StyledGroupRoot = styled(View)<{
|
|
21
|
+
rootGap: number
|
|
22
|
+
}>(({ rootGap }) => ({
|
|
23
|
+
gap: rootGap,
|
|
24
|
+
alignItems: "center",
|
|
25
|
+
width: "100%"
|
|
26
|
+
}))
|
|
27
|
+
|
|
28
|
+
const StyledButtonRow = styled(View)<{
|
|
29
|
+
rowDirection: "row-reverse" | "column"
|
|
30
|
+
rowAlign?: "center"
|
|
31
|
+
rowGap: number
|
|
32
|
+
}>(({ rowDirection, rowAlign, rowGap }) => ({
|
|
33
|
+
flexDirection: rowDirection,
|
|
34
|
+
width: "100%",
|
|
35
|
+
gap: rowGap,
|
|
36
|
+
...(rowAlign ? { alignItems: rowAlign } : {})
|
|
37
|
+
}))
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* ButtonGroup arranges 1 or 2 buttons in a stacked or inline layout
|
|
41
|
+
* with an optional description below.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* <ButtonGroup description="Choose an option">
|
|
46
|
+
* <Button colour="primary">Confirm</Button>
|
|
47
|
+
* <Button colour="secondary">Cancel</Button>
|
|
48
|
+
* </ButtonGroup>
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @param {"stacked" | "inline"} [layout="stacked"] - Layout direction for buttons.
|
|
52
|
+
* @param {React.ReactNode} [description] - Optional text displayed below the buttons.
|
|
53
|
+
* @param {React.ReactNode} children - 1 or 2 Button elements.
|
|
54
|
+
*/
|
|
55
|
+
export const ButtonGroup = React.forwardRef<View, ButtonGroupProps>(
|
|
56
|
+
({ layout = "stacked", description, children, ...rest }, ref) => {
|
|
57
|
+
const theme = useTheme()
|
|
58
|
+
const { buttonGroup } = theme.tokens.components
|
|
59
|
+
|
|
60
|
+
const isInline = layout === "inline"
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<StyledGroupRoot
|
|
64
|
+
ref={ref}
|
|
65
|
+
accessibilityRole="none"
|
|
66
|
+
rootGap={parseTokenValue(buttonGroup.spacing.gap)}
|
|
67
|
+
{...rest}
|
|
68
|
+
>
|
|
69
|
+
<StyledButtonRow
|
|
70
|
+
rowDirection={isInline ? "row-reverse" : "column"}
|
|
71
|
+
rowAlign={isInline ? "center" : undefined}
|
|
72
|
+
rowGap={parseTokenValue(
|
|
73
|
+
isInline
|
|
74
|
+
? buttonGroup.spacing.sideBySide.gap
|
|
75
|
+
: buttonGroup.spacing.stacked.gap
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
{children}
|
|
79
|
+
</StyledButtonRow>
|
|
80
|
+
{description && (
|
|
81
|
+
<Typography
|
|
82
|
+
token={buttonGroup.typography.description}
|
|
83
|
+
color={buttonGroup.colour.text}
|
|
84
|
+
align="center"
|
|
85
|
+
>
|
|
86
|
+
{description}
|
|
87
|
+
</Typography>
|
|
88
|
+
)}
|
|
89
|
+
</StyledGroupRoot>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
ButtonGroup.displayName = "ButtonGroup"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View, StyleSheet } from "react-native"
|
|
3
|
+
import { Checkbox } from "./Checkbox"
|
|
4
|
+
import type { CheckboxProps } from "./Checkbox"
|
|
5
|
+
import { CheckboxGroup } from "./CheckboxGroup"
|
|
6
|
+
import { Typography } from "../../atoms/Typography"
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: "Molecules/Checkbox",
|
|
10
|
+
component: Checkbox,
|
|
11
|
+
argTypes: {
|
|
12
|
+
variant: {
|
|
13
|
+
control: { type: "select" },
|
|
14
|
+
options: ["standalone", "tile"],
|
|
15
|
+
description: "Visual layout variant"
|
|
16
|
+
},
|
|
17
|
+
label: {
|
|
18
|
+
control: { type: "text" },
|
|
19
|
+
description: "Visible label text"
|
|
20
|
+
},
|
|
21
|
+
subText: {
|
|
22
|
+
control: { type: "text" },
|
|
23
|
+
description: "Optional secondary descriptive text"
|
|
24
|
+
},
|
|
25
|
+
checked: {
|
|
26
|
+
control: { type: "boolean" },
|
|
27
|
+
description: "Controlled checked state"
|
|
28
|
+
},
|
|
29
|
+
disabled: {
|
|
30
|
+
control: { type: "boolean" },
|
|
31
|
+
description: "Prevents interaction"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const Playground = {
|
|
37
|
+
args: {
|
|
38
|
+
variant: "standalone",
|
|
39
|
+
label: "Accept terms",
|
|
40
|
+
subText: "Required to proceed",
|
|
41
|
+
disabled: false
|
|
42
|
+
},
|
|
43
|
+
render: (args: CheckboxProps) => <Checkbox {...args} />
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const Standalone = () => (
|
|
47
|
+
<View style={styles.column}>
|
|
48
|
+
<View style={styles.section}>
|
|
49
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
50
|
+
Default
|
|
51
|
+
</Typography>
|
|
52
|
+
<CheckboxGroup>
|
|
53
|
+
<Checkbox label="Chicken" subText="Tender & tasty" />
|
|
54
|
+
<Checkbox label="Beef" subText="Rich & hearty" />
|
|
55
|
+
<Checkbox label="Lamb" subText="Slow cooked" />
|
|
56
|
+
</CheckboxGroup>
|
|
57
|
+
</View>
|
|
58
|
+
|
|
59
|
+
<View style={styles.section}>
|
|
60
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
61
|
+
Disabled
|
|
62
|
+
</Typography>
|
|
63
|
+
<CheckboxGroup>
|
|
64
|
+
<Checkbox label="Chicken" subText="Tender & tasty" disabled />
|
|
65
|
+
<Checkbox
|
|
66
|
+
label="Beef"
|
|
67
|
+
subText="Rich & hearty"
|
|
68
|
+
disabled
|
|
69
|
+
defaultChecked
|
|
70
|
+
/>
|
|
71
|
+
</CheckboxGroup>
|
|
72
|
+
</View>
|
|
73
|
+
</View>
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
export const Tile = () => (
|
|
77
|
+
<View style={styles.column}>
|
|
78
|
+
<View style={styles.section}>
|
|
79
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
80
|
+
Vertical
|
|
81
|
+
</Typography>
|
|
82
|
+
<CheckboxGroup orientation="vertical">
|
|
83
|
+
<Checkbox variant="tile" label="Chicken" subText="Tender & tasty" />
|
|
84
|
+
<Checkbox variant="tile" label="Beef" subText="Rich & hearty" />
|
|
85
|
+
<Checkbox variant="tile" label="Lamb" subText="Slow cooked" />
|
|
86
|
+
</CheckboxGroup>
|
|
87
|
+
</View>
|
|
88
|
+
|
|
89
|
+
<View style={styles.section}>
|
|
90
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
91
|
+
Horizontal
|
|
92
|
+
</Typography>
|
|
93
|
+
<CheckboxGroup orientation="horizontal">
|
|
94
|
+
<Checkbox variant="tile" label="Chicken" />
|
|
95
|
+
<Checkbox variant="tile" label="Beef" />
|
|
96
|
+
<Checkbox variant="tile" label="Lamb" />
|
|
97
|
+
</CheckboxGroup>
|
|
98
|
+
</View>
|
|
99
|
+
|
|
100
|
+
<View style={styles.section}>
|
|
101
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
102
|
+
Disabled
|
|
103
|
+
</Typography>
|
|
104
|
+
<CheckboxGroup orientation="vertical">
|
|
105
|
+
<Checkbox variant="tile" label="Chicken" disabled />
|
|
106
|
+
<Checkbox variant="tile" label="Beef" disabled defaultChecked />
|
|
107
|
+
</CheckboxGroup>
|
|
108
|
+
</View>
|
|
109
|
+
</View>
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
export const AllStates = () => (
|
|
113
|
+
<View style={styles.column}>
|
|
114
|
+
{(["standalone", "tile"] as const).map((variant) => (
|
|
115
|
+
<View key={variant} style={styles.section}>
|
|
116
|
+
<Typography size="sm" weight="semiBold" color="tertiary">
|
|
117
|
+
{variant}
|
|
118
|
+
</Typography>
|
|
119
|
+
<View style={styles.row}>
|
|
120
|
+
<Checkbox variant={variant} label="Unchecked" />
|
|
121
|
+
<Checkbox variant={variant} label="Checked" defaultChecked />
|
|
122
|
+
<Checkbox variant={variant} label="Disabled" disabled />
|
|
123
|
+
<Checkbox
|
|
124
|
+
variant={variant}
|
|
125
|
+
label="Checked + Disabled"
|
|
126
|
+
disabled
|
|
127
|
+
defaultChecked
|
|
128
|
+
/>
|
|
129
|
+
</View>
|
|
130
|
+
</View>
|
|
131
|
+
))}
|
|
132
|
+
</View>
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const styles = StyleSheet.create({
|
|
136
|
+
column: {
|
|
137
|
+
flexDirection: "column",
|
|
138
|
+
gap: 32
|
|
139
|
+
},
|
|
140
|
+
section: {
|
|
141
|
+
flexDirection: "column",
|
|
142
|
+
gap: 12
|
|
143
|
+
},
|
|
144
|
+
row: {
|
|
145
|
+
flexDirection: "column",
|
|
146
|
+
gap: 8
|
|
147
|
+
}
|
|
148
|
+
})
|