Skip to content

Commit e3f1533

Browse files
authored
feat(tags): new light/dark mode colors (#1809)
1 parent 630d9f3 commit e3f1533

File tree

5 files changed

+165
-85
lines changed

5 files changed

+165
-85
lines changed

packages/tags/src/elements/Tag.spec.tsx

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import React from 'react';
99
import { render, renderRtl } from 'garden-test-utils';
10-
import { PALETTE_V8 } from '@zendeskgarden/react-theming';
1110
import { Tag } from './Tag';
1211

1312
describe('Tag', () => {
@@ -23,40 +22,4 @@ describe('Tag', () => {
2322

2423
expect(container.firstChild).toBe(ref.current);
2524
});
26-
27-
describe('hue', () => {
28-
it('renders the hue provided', () => {
29-
[
30-
'grey',
31-
'blue',
32-
'kale',
33-
'red',
34-
'green',
35-
'fuschia',
36-
'pink',
37-
'crimson',
38-
'orange',
39-
'lemon',
40-
'lime',
41-
'mint',
42-
'teal',
43-
'azure',
44-
'royal',
45-
'purple'
46-
].forEach(color => {
47-
const { container } = render(<Tag hue={color as any} />);
48-
49-
expect(container.firstChild).toHaveStyleRule(
50-
'background-color',
51-
(PALETTE_V8 as any)[color][600]
52-
);
53-
});
54-
});
55-
56-
it('handles yellow hue with specialized shading', () => {
57-
const { container } = render(<Tag hue="yellow" />);
58-
59-
expect(container.firstChild).toHaveStyleRule('background-color', PALETTE_V8.yellow[400]);
60-
});
61-
});
6225
});

packages/tags/src/styled/StyledClose.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const StyledClose = styled.button.attrs<unknown>({
2424
align-items: center;
2525
justify-content: center;
2626
transition: opacity 0.25s ease-in-out;
27-
opacity: 0.8;
27+
opacity: ${props => props.theme.opacity[1000]};
2828
border: 0; /* [1] */
2929
background: transparent; /* [1] */
3030
cursor: pointer;
@@ -34,13 +34,17 @@ export const StyledClose = styled.button.attrs<unknown>({
3434
appearance: none; /* [1] */
3535
3636
&:hover {
37-
opacity: 0.9;
37+
opacity: ${props => props.theme.opacity[1100]};
3838
}
3939
4040
&:focus {
4141
outline: none;
4242
}
4343
44+
&:active {
45+
opacity: ${props => props.theme.opacity[1200]};
46+
}
47+
4448
${props => retrieveComponentStyles(COMPONENT_ID, props)};
4549
`;
4650

packages/tags/src/styled/StyledTag.spec.tsx

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
*/
77

88
import React from 'react';
9-
import { render, renderRtl } from 'garden-test-utils';
10-
import { PALETTE, getColorV8 } from '@zendeskgarden/react-theming';
9+
import { render, renderDark, renderRtl } from 'garden-test-utils';
10+
import { PALETTE } from '@zendeskgarden/react-theming';
1111
import { StyledTag } from './StyledTag';
1212

1313
describe('StyledTag', () => {
@@ -82,32 +82,93 @@ describe('StyledTag', () => {
8282
});
8383

8484
describe('hue', () => {
85-
it('renders using a default neutral hue', () => {
86-
const { container } = render(<StyledTag />);
87-
const color = getColorV8('neutralHue', 200);
85+
it.each([['light'], ['dark']])('renders using a default hue for %s mode', mode => {
86+
const renderFn = mode === 'light' ? render : renderDark;
87+
const { container } = renderFn(<StyledTag />);
88+
const backgroundColor = mode === 'dark' ? PALETTE.grey[800] : PALETTE.grey[200];
89+
const foregroundColor = mode === 'dark' ? PALETTE.grey[300] : PALETTE.grey[900];
90+
91+
expect(container.firstChild).toHaveStyleRule('background-color', backgroundColor);
92+
expect(container.firstChild).toHaveStyleRule('color', foregroundColor);
93+
});
94+
95+
it.each([['light'], ['dark']])('renders using a "grey" hue in %s mode', mode => {
96+
const renderFn = mode === 'light' ? render : renderDark;
97+
const { container } = renderFn(<StyledTag hue="grey" />);
98+
const backgroundColor = mode === 'dark' ? PALETTE.grey[300] : PALETTE.grey[700];
99+
const foregroundColor = mode === 'dark' ? PALETTE.grey[1100] : PALETTE.white;
100+
101+
expect(container.firstChild).toHaveStyleRule('background-color', backgroundColor);
102+
expect(container.firstChild).toHaveStyleRule('color', foregroundColor);
103+
});
104+
105+
it.each([['light'], ['dark']])('renders using a "blue" hue in %s mode', mode => {
106+
const renderFn = mode === 'light' ? render : renderDark;
107+
const { container } = renderFn(<StyledTag hue="blue" />);
108+
const backgroundColor = mode === 'dark' ? PALETTE.blue[600] : PALETTE.blue[700];
109+
const foregroundColor = mode === 'dark' ? PALETTE.grey[1100] : PALETTE.white;
110+
111+
expect(container.firstChild).toHaveStyleRule('background-color', backgroundColor);
112+
expect(container.firstChild).toHaveStyleRule('color', foregroundColor);
113+
});
114+
115+
it.each([['light'], ['dark']])('renders using a "red" hue in %s mode', mode => {
116+
const renderFn = mode === 'light' ? render : renderDark;
117+
const { container } = renderFn(<StyledTag hue="red" />);
118+
const backgroundColor = mode === 'dark' ? PALETTE.red[600] : PALETTE.red[700];
119+
const foregroundColor = mode === 'dark' ? PALETTE.grey[1100] : PALETTE.white;
120+
121+
expect(container.firstChild).toHaveStyleRule('background-color', backgroundColor);
122+
expect(container.firstChild).toHaveStyleRule('color', foregroundColor);
123+
});
124+
125+
it.each([['light'], ['dark']])('renders using a "green" hue in %s mode', mode => {
126+
const renderFn = mode === 'light' ? render : renderDark;
127+
const { container } = renderFn(<StyledTag hue="green" />);
128+
const backgroundColor = mode === 'dark' ? PALETTE.green[600] : PALETTE.green[700];
129+
const foregroundColor = mode === 'dark' ? PALETTE.grey[1100] : PALETTE.white;
130+
131+
expect(container.firstChild).toHaveStyleRule('background-color', backgroundColor);
132+
expect(container.firstChild).toHaveStyleRule('color', foregroundColor);
133+
});
134+
135+
it.each([['light'], ['dark']])('renders using a "yellow" hue in %s mode', mode => {
136+
const renderFn = mode === 'light' ? render : renderDark;
137+
const { container } = renderFn(<StyledTag hue="yellow" />);
138+
const foregroundColor = mode === 'dark' ? PALETTE.grey[1100] : PALETTE.yellow[900];
139+
140+
expect(container.firstChild).toHaveStyleRule('background-color', PALETTE.yellow[400]);
141+
expect(container.firstChild).toHaveStyleRule('color', foregroundColor);
142+
});
143+
144+
it.each([['light'], ['dark']])('renders using a "kale" hue in %s mode', mode => {
145+
const renderFn = mode === 'light' ? render : renderDark;
146+
const { container } = renderFn(<StyledTag hue="kale" />);
147+
const backgroundColor = mode === 'dark' ? PALETTE.kale[500] : PALETTE.kale[800];
148+
const foregroundColor = mode === 'dark' ? PALETTE.grey[1100] : PALETTE.white;
88149

89-
expect(container.firstChild).toHaveStyleRule('background-color', color);
150+
expect(container.firstChild).toHaveStyleRule('background-color', backgroundColor);
151+
expect(container.firstChild).toHaveStyleRule('color', foregroundColor);
90152
});
91153

92-
it('renders using a custom hue', () => {
93-
const { container } = render(<StyledTag hue="azure" />);
94-
const color = getColorV8('azure', 600);
154+
it.each([['light'], ['dark']])('renders using a custom hue for %s mode', mode => {
155+
const renderFn = mode === 'light' ? render : renderDark;
156+
const { container } = renderFn(<StyledTag hue="azure" />);
157+
const backgroundColor = mode === 'dark' ? PALETTE.azure[500] : PALETTE.azure[700];
95158

96-
expect(container.firstChild).toHaveStyleRule('background-color', color);
159+
expect(container.firstChild).toHaveStyleRule('background-color', backgroundColor);
97160
});
98161

99162
it('renders a dark foreground on a light background', () => {
100163
const { container } = render(<StyledTag hue="white" />);
101-
const color = PALETTE.grey[800];
102164

103-
expect(container.firstChild).toHaveStyleRule('color', color);
165+
expect(container.firstChild).toHaveStyleRule('color', PALETTE.grey[1100]);
104166
});
105167

106168
it('renders a light foreground on a dark background', () => {
107169
const { container } = render(<StyledTag hue="black" />);
108-
const color = PALETTE.white;
109170

110-
expect(container.firstChild).toHaveStyleRule('color', color);
171+
expect(container.firstChild).toHaveStyleRule('color', PALETTE.white);
111172
});
112173
});
113174
});

packages/tags/src/styled/StyledTag.ts

Lines changed: 82 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,64 +9,115 @@ import styled, { css, ThemeProps, DefaultTheme } from 'styled-components';
99
import { math, readableColor } from 'polished';
1010
import {
1111
DEFAULT_THEME,
12-
getColorV8,
1312
retrieveComponentStyles,
1413
getLineHeight,
1514
SELECTOR_FOCUS_VISIBLE,
16-
focusStyles
15+
focusStyles,
16+
getColor,
17+
IGardenTheme
1718
} from '@zendeskgarden/react-theming';
1819
import { StyledAvatar } from './StyledAvatar';
1920
import { StyledClose } from './StyledClose';
2021
import { ITagProps } from '../types';
2122

2223
const COMPONENT_ID = 'tags.tag_view';
2324

24-
const colorStyles = (props: ITagProps & ThemeProps<DefaultTheme>) => {
25+
/*
26+
* 1. Anchor element reset
27+
* 2. Tags show focus state whether performed by mouse or keyboard
28+
*/
29+
const colorStyles = ({ theme, hue }: ITagProps & ThemeProps<DefaultTheme>) => {
2530
let backgroundColor;
2631
let foregroundColor;
27-
let closeColor;
28-
29-
if (props.hue) {
30-
const shade = props.hue === 'yellow' ? 400 : 600;
3132

32-
backgroundColor = getColorV8(props.hue, shade, props.theme);
33-
34-
if (props.hue === 'yellow' || props.hue === 'lemon') {
35-
foregroundColor = getColorV8('yellow', 800, props.theme);
36-
} else {
37-
foregroundColor = readableColor(
38-
backgroundColor!,
39-
props.theme.palette.grey[800],
40-
props.theme.palette.white as string
41-
);
33+
if (hue) {
34+
foregroundColor = getColor({ theme, variable: 'foreground.onEmphasis' });
35+
36+
switch (hue) {
37+
case 'grey':
38+
case 'neutralHue':
39+
backgroundColor = getColor({
40+
theme,
41+
variable: 'background.emphasis',
42+
dark: { offset: -300 }
43+
});
44+
break;
45+
46+
case 'blue':
47+
case 'primaryHue':
48+
backgroundColor = getColor({ theme, variable: 'background.primaryEmphasis' });
49+
break;
50+
51+
case 'red':
52+
case 'dangerHue':
53+
backgroundColor = getColor({ theme, variable: 'background.dangerEmphasis' });
54+
break;
55+
56+
case 'green':
57+
case 'successHue':
58+
backgroundColor = getColor({ theme, variable: 'background.successEmphasis' });
59+
break;
60+
61+
case 'yellow':
62+
case 'warningHue':
63+
backgroundColor = getColor({ theme, hue: 'warningHue', shade: 400 });
64+
65+
if (theme.colors.base === 'light') {
66+
foregroundColor = getColor({ theme, variable: 'foreground.warningEmphasis' });
67+
}
68+
69+
break;
70+
71+
case 'kale':
72+
case 'chromeHue':
73+
backgroundColor = getColor({
74+
theme,
75+
hue: 'chromeHue',
76+
dark: { shade: 500 },
77+
light: { shade: 800 }
78+
});
79+
80+
break;
81+
82+
default: {
83+
const lightTheme = { ...theme, colors: { ...theme.colors, base: 'light' } } as IGardenTheme;
84+
const darkTheme = { ...theme, colors: { ...theme.colors, base: 'dark' } } as IGardenTheme;
85+
const variable = 'foreground.onEmphasis';
86+
87+
backgroundColor = getColor({ theme, hue });
88+
foregroundColor = readableColor(
89+
backgroundColor,
90+
getColor({ theme: darkTheme, variable }),
91+
getColor({ theme: lightTheme, variable }),
92+
false /* disable strict mode to prevent black */
93+
);
94+
95+
break;
96+
}
4297
}
4398
} else {
44-
backgroundColor = getColorV8('neutralHue', 200, props.theme);
45-
foregroundColor = getColorV8('neutralHue', 700, props.theme);
46-
closeColor = getColorV8('neutralHue', 600, props.theme);
99+
backgroundColor = getColor({
100+
theme,
101+
hue: 'neutralHue',
102+
dark: { shade: 800 },
103+
light: { shade: 200 }
104+
});
105+
foregroundColor = getColor({ theme, variable: 'foreground.default' });
47106
}
48107

49108
return css`
50109
background-color: ${backgroundColor};
51110
color: ${foregroundColor};
52111
53112
&:hover {
54-
color: ${foregroundColor}; /* <a> element reset */
113+
color: ${foregroundColor}; /* [1] */
55114
}
56115
57-
/**
58-
* Tags show their focus state regardless of
59-
* whether it was performed by a mouse or keyboard.
60-
**/
61116
${focusStyles({
62-
theme: props.theme,
117+
theme,
63118
shadowWidth: 'sm',
64-
selector: '&:focus'
119+
selector: '&:focus' /* [2] */
65120
})}
66-
67-
& ${StyledClose} {
68-
color: ${closeColor};
69-
}
70121
`;
71122
};
72123

packages/tags/src/types/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ export interface ITagProps extends HTMLAttributes<HTMLDivElement> {
1414
size?: (typeof SIZE)[number];
1515
/**
1616
* Sets the color of the tag. Refer to
17-
* [PALETTE](/components/palette#palette)
17+
* theming [colors](components/theme-object#colors)
18+
* or [PALETTE](/components/palette#palette)
1819
* for available colors. Accepts any hex value.
1920
*/
2021
hue?: string;

0 commit comments

Comments
 (0)