Skip to content

Commit b1b7ad4

Browse files
authored
Merge pull request #64 from EnCiv/button-components-#43
Button components #43
2 parents 6bdc448 + 07519a0 commit b1b7ad4

File tree

5 files changed

+284
-0
lines changed

5 files changed

+284
-0
lines changed

app/components/button.jsx

+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
// https://github.com/EnCiv/civil-pursuit/issues/43
2+
import React, {useState, useRef} from 'react';
3+
import { createUseStyles } from 'react-jss';
4+
import cx from 'classnames';
5+
6+
/**
7+
* Button component(without stretch goal version) that is styled using react-jss.
8+
* It supports various states like hover, active, and disabled,
9+
* and can be configured with custom styles, titles, and callbacks.
10+
*
11+
* @param {Object} props - The props for the Button component.
12+
*/
13+
14+
function Button(props) {
15+
16+
const {
17+
className = "", // may or may not be passed. Should be applied to the outer most tag, after local classNames
18+
onDone = () => {}, // a function that is called when the button is clicked. - if it exists
19+
title = "", // text to display on hover
20+
disabled = false,
21+
disableOnClick = false, // if true, the button gets disabled after click and stays disabled - prevents resubmission
22+
children,
23+
...otherProps
24+
} = props;
25+
26+
const [isDisabled, setIsDisabled] = useState(disabled);
27+
28+
const classes = buttonStyles();
29+
const combinedClassName = cx(classes.buttonBase, className);
30+
31+
return (
32+
<button
33+
className={combinedClassName}
34+
title={title}
35+
disabled={isDisabled}
36+
onClick={() => {
37+
if (onDone) onDone();
38+
if (disableOnClick) setIsDisabled(true);
39+
}}
40+
{...otherProps}
41+
>
42+
{children}
43+
</button>
44+
)
45+
}
46+
47+
function ModifierButton(props) {
48+
const { className, ...otherProps } = props;
49+
const classes = buttonStyles();
50+
return <Button {...otherProps} className={cx(classes.modifierButton, className)} />;
51+
}
52+
53+
function SecondaryButton(props) {
54+
const { className, ...otherProps } = props;
55+
const classes = buttonStyles();
56+
return <Button {...otherProps} className={cx(classes.secondaryButton, className)} />;
57+
}
58+
59+
function PrimaryButton(props) {
60+
const { className, ...otherProps } = props;
61+
const classes = buttonStyles();
62+
return <Button {...otherProps} className={cx(classes.primaryButton, className)} />;
63+
}
64+
65+
function TextButton(props) {
66+
const { className, ...otherProps } = props;
67+
const classes = buttonStyles();
68+
return <Button {...otherProps} className={cx(classes.textButton, className)} />;
69+
}
70+
71+
const buttonStyles = createUseStyles(theme => ({
72+
buttonBase: { // These are common styles
73+
width: 'auto',
74+
height: 'auto',
75+
borderRadius: '0.5rem',
76+
padding: '0.5rem 1.25rem',
77+
fontFamily: 'Inter, sans-serif',
78+
fontWeight: 600,
79+
fontSize: '1rem',
80+
lineHeight: '1.5rem',
81+
textAlign: 'center',
82+
// Add any other common styles here
83+
},
84+
85+
secondaryButton: {
86+
extend: 'buttonBase',
87+
backgroundColor: theme.colors.white,
88+
color: theme.colors.primaryButtonBlue,
89+
border: `0.125rem solid ${theme.colors.primaryButtonBlue}`,
90+
91+
'&:focus': {
92+
},
93+
94+
'&:disabled': {
95+
backgroundColor: theme.colors.white,
96+
color: theme.colors.disableGray,
97+
border: `0.125rem solid ${theme.colors.disableSecBorderGray}`,
98+
textDecoration: 'none',
99+
transition: 'none',
100+
},
101+
102+
'&:hover, &.hover': {
103+
textDecoration: 'underline',
104+
backgroundColor: theme.colors.white,
105+
borderColor: theme.colors.primaryButtonBlue
106+
},
107+
108+
'&:active': {
109+
backgroundColor: theme.colors.primaryButtonBlue,
110+
color: theme.colors.white,
111+
border: `0.125rem solid ${theme.colors.primaryButtonBlue}`,
112+
textDecoration: 'none',
113+
},
114+
115+
},
116+
117+
modifierButton: {
118+
extend: 'buttonBase',
119+
backgroundColor: theme.colors.white,
120+
color: theme.colors.textBrown,
121+
border: `0.125rem solid ${theme.colors.encivYellow}`,
122+
123+
'&:focus': {
124+
},
125+
126+
'&:hover, &.hover': {
127+
textDecoration: 'underline',
128+
backgroundColor: theme.colors.white,
129+
borderColor: theme.colors.encivYellow
130+
},
131+
132+
'&:active': {
133+
backgroundColor: theme.colors.encivYellow,
134+
color: theme.colors.textBrown,
135+
border: `0.125rem solid ${theme.colors.encivYellow}`,
136+
textDecoration: 'none',
137+
},
138+
},
139+
140+
primaryButton: {
141+
extend: 'buttonBase',
142+
backgroundColor: theme.colors.primaryButtonBlue,
143+
color: theme.colors.white,
144+
border: `0.125rem solid ${theme.colors.primaryButtonBlue}`,
145+
146+
'&:focus': {
147+
},
148+
149+
'&:disabled': {
150+
backgroundColor: theme.colors.borderGray,
151+
color: theme.colors.disableTextBlack,
152+
border: `0.0625rem solid ${theme.colors.borderGray}`,
153+
textDecoration: 'none',
154+
transition: 'none',
155+
},
156+
157+
'&:hover, &.hover': {
158+
textDecoration: 'underline',
159+
backgroundColor: theme.colors.primaryButtonBlue,
160+
borderColor: theme.colors.primaryButtonBlue
161+
},
162+
163+
'&:active': {
164+
backgroundColor: theme.colors.mouseDownPrimeBlue,
165+
border: `0.125rem solid ${theme.colors.primaryButtonBlue}`,
166+
textDecoration: 'none',
167+
},
168+
},
169+
170+
textButton: {
171+
extend: 'buttonBase',
172+
backgroundColor: 'transparent',
173+
color: theme.colors.title,
174+
border: 'none',
175+
textAlign: 'left',
176+
textDecoration: 'underline',
177+
178+
'&:hover, &.hover': {
179+
textDecoration: 'underline',
180+
backgroundColor: 'transparent',
181+
borderColor: 'none'
182+
},
183+
184+
'&:active': {
185+
color: theme.colors.title,
186+
textDecoration: 'none',
187+
},
188+
}
189+
}))
190+
191+
192+
193+
export { Button, ModifierButton, SecondaryButton, PrimaryButton, TextButton };

app/components/theme.js

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ const Theme = {
1010
title: '#1A1A1A',
1111
textBrown: '#403105',
1212
encivYellow: '#FFC315',
13+
disableSecBorderGray: '#5D5D5C',
14+
disableTextBlack: '#343433',
15+
primaryButtonBlue: '#06335C',
16+
mouseDownPrimeBlue: '#01172C',
1317
},
1418
font: {
1519
fontFamily: 'Inter',

package-lock.json

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"@babel/preset-env": "^7.12.7",
6666
"@babel/preset-react": "^7.12.7",
6767
"@babel/runtime": "^7.12.5",
68+
"@codastic/react-positioning-portal": "^0.7.0",
6869
"@svgr/cli": "^8.1.0",
6970
"autosize": "^3.0.15",
7071
"aws-sdk": "^2.353.0",

stories/button.stories.jsx

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from 'react';
2+
import { Button, ModifierButton, SecondaryButton, PrimaryButton, TextButton } from '../app/components/button';
3+
4+
export default {
5+
title: "Button",
6+
component: Button,
7+
}
8+
9+
10+
const Template = (Component) => (args) => <Component {...args} />;
11+
12+
export const Base = Template(Button).bind({});
13+
Base.args = {
14+
style: {},
15+
onDone: null,
16+
title: "Press me",
17+
disabled: false,
18+
disableOnClick: false,
19+
children: "Base Button"
20+
};
21+
22+
export const Secondary = Template(SecondaryButton).bind({});
23+
Secondary.args = {
24+
onDone: null,
25+
title: "Press me",
26+
disabled: false,
27+
disableOnClick: false,
28+
children: "Secondary Button"
29+
};
30+
31+
export const Modifier = Template(ModifierButton).bind({});
32+
Modifier.args = {
33+
onDone: null,
34+
title: "Press me",
35+
disabled: false,
36+
disableOnClick: false,
37+
children: "Modifier Button"
38+
};
39+
40+
export const Primary = Template(PrimaryButton).bind({});
41+
Primary.args = {
42+
onDone: null,
43+
title: "Press me",
44+
disabled: false,
45+
disableOnClick: false,
46+
children: "Primary Button"
47+
};
48+
49+
export const Text = Template(TextButton).bind({});
50+
Text.args = {
51+
onDone: null,
52+
title: "Press me",
53+
disabled: false,
54+
disableOnClick: false,
55+
children: "Text Button"
56+
};
57+
58+
export const HoverTest = Template(SecondaryButton).bind({});
59+
HoverTest.args = {
60+
className: "hover",
61+
onDone: null,
62+
title: "Press me",
63+
disabled: false,
64+
disableOnClick: false,
65+
children: "Hover State Button"
66+
};

0 commit comments

Comments
 (0)