Skip to content

Commit 41d9803

Browse files
Components: Button (codesandbox#3301)
* button wip * write up link + danger * ts ignores Co-authored-by: Sara Vieira <hey@iamsaravieira.com>
1 parent 3da3a36 commit 41d9803

File tree

5 files changed

+184
-4
lines changed

5 files changed

+184
-4
lines changed

packages/common/src/design-language/theme.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ const theme = {
3434
},
3535

3636
shadows: {
37+
// based on elevation levels
38+
0: 'none',
39+
1: '0px 8px 4px rgba(0, 0, 0, 0.12), 0px 8px 16px rgba(0, 0, 0, 0.24)',
40+
2: '0px 4px 4px rgba(0, 0, 0, 0.12), 0px 16px 32px rgba(0, 0, 0, 0.24)',
41+
3742
// this part is ugly, this can be improved.
3843
// bonus: these are terrible names
3944
active: `inset 0px -2px 0px ${colors.blues[300]}`,

packages/common/src/themes/codesandbox-black.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const colors = {
1414
contrastActiveBorder: null,
1515
errorForeground: tokens.reds[500],
1616
focusBorder: tokens.grays[500],
17-
foreground: tokens.grays[300],
17+
foreground: tokens.grays[200],
1818
activityBar: {
1919
background: tokens.grays[700],
2020
border: tokens.grays[500],
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
import { Button } from '.';
3+
import { Stack } from '../Stack';
4+
5+
export default {
6+
title: 'components/Button',
7+
component: Button,
8+
};
9+
10+
// replace the text inside with Text variants when available
11+
export const Basic = () => <Button>Create Sandbox, it’s free</Button>;
12+
13+
export const Variants = () => (
14+
<Stack direction="vertical" gap={4} style={{ width: 200 }}>
15+
<Button variant="primary">primary by default</Button>
16+
<Button variant="secondary">Save as Template</Button>
17+
<Button variant="link">Open sandbox</Button>
18+
<Button variant="danger">Go live</Button>
19+
</Stack>
20+
);
21+
22+
export const Disabled = () => (
23+
<Stack direction="vertical" gap={4} style={{ width: 200 }}>
24+
<Button disabled variant="primary">
25+
primary by default
26+
</Button>
27+
<Button disabled variant="secondary">
28+
Save as Template
29+
</Button>
30+
<Button disabled variant="link">
31+
Open sandbox
32+
</Button>
33+
<Button disabled variant="danger">
34+
Go live
35+
</Button>
36+
</Stack>
37+
);
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import styled from 'styled-components';
2+
import css from '@styled-system/css';
3+
import deepmerge from 'deepmerge';
4+
import { Element } from '../Element';
5+
6+
const variantStyles = {
7+
primary: {
8+
backgroundColor: 'button.background',
9+
color: 'button.foreground',
10+
':hover': {
11+
// hoverBackground is polyfilled and uses a gradient
12+
// so we use background and not backgroundColor
13+
14+
// background is not hooked to the system like backgroundColor
15+
// so we need to write the long syntax
16+
// TODO @sid: extend our system to make background work as well
17+
background: theme => theme.colors.button.hoverBackground,
18+
},
19+
':focus': {
20+
// we use the same colors for hover and focus
21+
// but we add an active state to give
22+
background: theme => theme.colors.button.hoverBackground,
23+
},
24+
':disabled:hover': {
25+
background: 'transparent', // override hover
26+
backgroundColor: 'button.background',
27+
},
28+
},
29+
secondary: {
30+
backgroundColor: 'secondaryButton.background',
31+
color: 'secondaryButton.foreground',
32+
// same technique as primary
33+
':hover': {
34+
background: theme => theme.colors.secondaryButton.hoverBackground,
35+
},
36+
':focus': {
37+
background: theme => theme.colors.secondaryButton.hoverBackground,
38+
},
39+
':disabled:hover': {
40+
background: 'transparent', // override hover
41+
backgroundColor: 'secondaryButton.background',
42+
},
43+
},
44+
link: {
45+
backgroundColor: 'transparent',
46+
color: 'mutedForeground',
47+
// same technique as primary
48+
':hover': {
49+
color: 'foreground',
50+
},
51+
':focus': {
52+
color: 'foreground',
53+
},
54+
},
55+
danger: {
56+
backgroundColor: 'dangerButton.background',
57+
color: 'dangerButton.foreground',
58+
// same technique as primary
59+
':hover': {
60+
background: theme => theme.colors.dangerButton.hoverBackground,
61+
},
62+
':focus': {
63+
background: theme => theme.colors.dangerButton.hoverBackground,
64+
},
65+
':disabled:hover': {
66+
background: 'transparent', // override hover
67+
backgroundColor: 'dangerButton.background',
68+
},
69+
},
70+
};
71+
72+
export const Button = styled(Element).attrs({ as: 'button' })<{
73+
variant?: 'primary' | 'secondary' | 'link' | 'danger';
74+
}>(({ variant = 'primary', ...props }) =>
75+
css(
76+
deepmerge(
77+
{
78+
display: 'inline-block',
79+
cursor: 'pointer',
80+
height: 6,
81+
width: '100%',
82+
fontSize: 2,
83+
border: 'none',
84+
borderRadius: 'small',
85+
transition: 'all ease-in',
86+
transitionDuration: theme => theme.speeds[1],
87+
':hover': {
88+
// totally custom button shadow, static across themes
89+
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)',
90+
},
91+
':focus': {
92+
outline: 'none',
93+
// totally custom button shadow, static across themes
94+
boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.4)',
95+
},
96+
':active': {
97+
transform: 'scale(0.98)',
98+
},
99+
':disabled': {
100+
opacity: '0.4',
101+
cursor: 'not-allowed',
102+
},
103+
},
104+
// @ts-ignore deepmerge allows functions as values
105+
// it overrides instead of merging, which is what we want
106+
// but it's types don't like it. so we're going to ignore that
107+
// TODO: raise a pull request for deepmerge or pick a different
108+
// library to deep merge objects
109+
variantStyles[variant]
110+
)
111+
)
112+
);

packages/components/src/utils/polyfill-theme.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,49 @@
44
* some _polyfills_ to the theme tokens.
55
* These are mapped to existing variables from the vscode theme
66
* that always exists - editor, sidebar.
7+
*
8+
* These are our best guesses.
79
*/
810

9-
import deepmerge from 'deepmerge';
10-
1111
// TODO: For themes that we officially support, we have the option
1212
// to modify the theme and add our custom keys
1313
// which we can use when the polyfill is a bad alternate.
1414
// In that case, we should check if it exists before overriding it
15+
16+
import deepmerge from 'deepmerge';
17+
import designLanguage from '@codesandbox/common/lib/design-language';
18+
1519
const polyfillTheme = vsCodeTheme =>
1620
deepmerge(vsCodeTheme, {
17-
mutedForeground: vsCodeTheme.foreground, // todo: find a way to fill this value
1821
sideBar: {
1922
hoverBackground: vsCodeTheme.sideBar.border,
2023
},
24+
// this works for codesandbox-black but I doubt other themes define this
25+
mutedForeground: vsCodeTheme.input.placeholderForeground,
26+
// putting this here so that we remember to polyfill it
27+
input: {
28+
placeholderForeground: vsCodeTheme.input.placeholderForeground,
29+
},
2130
avatar: {
2231
border: vsCodeTheme.sideBar.border,
2332
},
33+
button: {
34+
// this key is can defined by vscode, but not always present
35+
// we add a 30% overlay on top of the background color using gradient
36+
hoverBackground: `linear-gradient(0deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2)), ${vsCodeTheme.button.background}`,
37+
},
38+
secondaryButton: {
39+
background: vsCodeTheme.input.background,
40+
foreground: vsCodeTheme.input.foreground,
41+
hoverBackground: `linear-gradient(0deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2)), ${vsCodeTheme.input.background}`,
42+
},
43+
dangerButton: {
44+
// @ts-ignore: The colors totally exist, our typings are incorrect
45+
background: designLanguage.colors.reds[300],
46+
foreground: '#fff',
47+
// @ts-ignore: The colors totally exist, our typings are incorrect
48+
hoverBackground: `linear-gradient(0deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2)), ${designLanguage.colors.reds[300]}`,
49+
},
2450
});
2551

2652
export default polyfillTheme;

0 commit comments

Comments
 (0)