Skip to content

Commit a745bde

Browse files
authored
feat(theming): add new getCheckeredBackground utility (#1793)
1 parent 2190e56 commit a745bde

File tree

10 files changed

+169
-77
lines changed

10 files changed

+169
-77
lines changed

packages/colorpickers/src/styled/ColorPicker/StyledAlphaRange.ts

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

88
import styled, { DefaultTheme, ThemeProps } from 'styled-components';
9-
import { DEFAULT_THEME } from '@zendeskgarden/react-theming';
9+
import { DEFAULT_THEME, getCheckeredBackground } from '@zendeskgarden/react-theming';
1010
import { getTrackHeight, getTrackMargin, StyledRange } from '../common/StyledRange';
11-
import { checkeredBackground } from '../common/checkeredBackground';
1211
import { IRGBColor } from '../../types';
1312

1413
const COMPONENT_ID = 'colorpickers.colorpicker_alpha';
@@ -19,14 +18,15 @@ const background = (props: IRGBColor & ThemeProps<DefaultTheme>) => {
1918
const toColor = `rgb(${props.red}, ${props.green}, ${props.blue})`;
2019
const positionY = getTrackMargin(props);
2120
const height = getTrackHeight(props);
22-
const gradientBackground = `linear-gradient(${direction}, ${fromColor}, ${toColor}) 0 ${positionY}px / 100% ${height}px no-repeat`;
21+
const overlay = `linear-gradient(${direction}, ${fromColor}, ${toColor}) 0 ${positionY}px / 100% ${height}px no-repeat`;
2322

24-
return `${gradientBackground}, ${checkeredBackground(
25-
props.theme,
26-
height,
23+
return getCheckeredBackground({
24+
theme: props.theme,
25+
size: height,
2726
positionY,
28-
'repeat-x'
29-
)}`;
27+
repeat: 'repeat-x',
28+
overlay
29+
});
3030
};
3131

3232
export const StyledAlphaRange = styled(StyledRange as 'input').attrs<IRGBColor>(props => ({

packages/colorpickers/src/styled/ColorPicker/StyledPreview.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77

88
import styled, { DefaultTheme, ThemeProps } from 'styled-components';
99
import { rgba } from 'polished';
10-
import { retrieveComponentStyles, DEFAULT_THEME } from '@zendeskgarden/react-theming';
11-
import { checkeredBackground } from '../common/checkeredBackground';
10+
import {
11+
retrieveComponentStyles,
12+
DEFAULT_THEME,
13+
getCheckeredBackground
14+
} from '@zendeskgarden/react-theming';
1215
import { IRGBColor } from '../../types';
1316

1417
const COMPONENT_ID = 'colorpickers.colorpicker_preview_box';
@@ -19,11 +22,14 @@ interface IStyledColorPreviewProps extends IRGBColor {
1922

2023
const background = (props: IStyledColorPreviewProps & ThemeProps<DefaultTheme>) => {
2124
const alpha = props.alpha ? props.alpha / 100 : 0;
22-
const color = `rgba(${props.red}, ${props.green}, ${props.blue}, ${alpha})`;
23-
let retVal = `linear-gradient(${color}, ${color})`;
25+
let retVal = `rgba(${props.red}, ${props.green}, ${props.blue}, ${alpha})`;
2426

2527
if (!props.isOpaque) {
26-
retVal = `${retVal}, ${checkeredBackground(props.theme, 13)}`;
28+
retVal = getCheckeredBackground({
29+
theme: props.theme,
30+
size: 13,
31+
overlay: retVal
32+
});
2733
}
2834

2935
return retVal;

packages/colorpickers/src/styled/ColorPickerDialog/StyledButtonPreview.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77

88
import styled, { ThemeProps, DefaultTheme } from 'styled-components';
99
import { rgba } from 'polished';
10-
import { retrieveComponentStyles, DEFAULT_THEME } from '@zendeskgarden/react-theming';
11-
import { checkeredBackground } from '../common/checkeredBackground';
10+
import {
11+
retrieveComponentStyles,
12+
DEFAULT_THEME,
13+
getCheckeredBackground
14+
} from '@zendeskgarden/react-theming';
1215
import { IColorPickerDialogProps } from '../../types';
1316

1417
const COMPONENT_ID = 'colorpickers.colordialog_preview';
@@ -19,24 +22,28 @@ export interface IStyleButtonPreviewProps extends ThemeProps<DefaultTheme> {
1922

2023
const background = (props: IStyleButtonPreviewProps) => {
2124
const { backgroundColor } = props;
22-
let color;
25+
let retVal;
2326

2427
if (typeof backgroundColor === 'string') {
25-
color = backgroundColor;
28+
retVal = backgroundColor;
2629
} else if (backgroundColor === undefined) {
27-
color = props.theme.palette.white;
30+
retVal = props.theme.palette.white as string;
2831
} else {
2932
const { red, green, blue, alpha = 1 } = backgroundColor;
3033

31-
color = `rgba(${red}, ${green}, ${blue}, ${alpha ? alpha / 100 : 0})`;
34+
retVal = `rgba(${red}, ${green}, ${blue}, ${alpha ? alpha / 100 : 0})`;
3235
}
3336

34-
return `linear-gradient(${color}, ${color})`;
37+
return retVal;
3538
};
3639

3740
export const StyledButtonPreview = styled.span.attrs<IStyleButtonPreviewProps>(props => ({
3841
style: {
39-
background: `${background(props)}, ${checkeredBackground(props.theme, 8)}`
42+
background: getCheckeredBackground({
43+
theme: props.theme,
44+
size: 8,
45+
overlay: background(props)
46+
})
4047
},
4148
'data-garden-id': COMPONENT_ID,
4249
'data-garden-version': PACKAGE_VERSION,

packages/colorpickers/src/styled/common/checkeredBackground.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

packages/theming/demo/stories/GetColorStory.tsx

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,10 @@
77

88
import React from 'react';
99
import { StoryFn } from '@storybook/react';
10-
import styled, { DefaultTheme, useTheme } from 'styled-components';
11-
import { IGardenTheme, getColor } from '@zendeskgarden/react-theming';
10+
import styled, { useTheme } from 'styled-components';
11+
import { IGardenTheme, getCheckeredBackground, getColor } from '@zendeskgarden/react-theming';
1212
import { Tag } from '@zendeskgarden/react-tags';
1313

14-
const toBackground = (theme: DefaultTheme, backgroundColor: string) => {
15-
const color = getColor({ hue: 'neutralHue', shade: 300, theme });
16-
const size = 26;
17-
const dimensions = `${size}px ${size}px`;
18-
const positionX1 = theme.rtl ? '100%' : '0';
19-
const positionX2 = theme.rtl ? `calc(100% - ${size / 2}px)` : `${size / 2}px`;
20-
const position1 = `${positionX1} 0`;
21-
const position2 = `${positionX2} ${size / 2}px`;
22-
const position3 = `${positionX2} 0`;
23-
const position4 = `${positionX1} ${size / -2}px`;
24-
25-
return `
26-
linear-gradient(${backgroundColor}, ${backgroundColor}),
27-
linear-gradient(45deg, ${color} 25%, transparent 25%) ${position1} / ${dimensions} repeat,
28-
linear-gradient(45deg, transparent 75%, ${color} 75%) ${position2} / ${dimensions} repeat,
29-
linear-gradient(135deg, ${color} 25%, transparent 25%) ${position3} / ${dimensions} repeat,
30-
linear-gradient(135deg, transparent 75%, ${color} 75%) ${position4} / ${dimensions} repeat
31-
`;
32-
};
33-
3414
const StyledDiv = styled.div<{ background: string }>`
3515
display: flex;
3616
align-items: center;
@@ -66,7 +46,11 @@ const Color = ({ dark, hue, light, offset, shade, theme, transparency, variable
6646
variable
6747
});
6848

69-
background = toBackground(theme, backgroundColor);
49+
background = getCheckeredBackground({
50+
theme,
51+
size: 26,
52+
overlay: backgroundColor
53+
});
7054
tag = (
7155
<Tag hue={getColor({ theme, variable: 'background.default' })} size="large">
7256
{backgroundColor}

packages/theming/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export { default as PALETTE } from './elements/palette';
1111
export { default as PALETTE_V8 } from './elements/palette/v8';
1212
export { default as retrieveComponentStyles } from './utils/retrieveComponentStyles';
1313
export { getArrowPosition } from './utils/getArrowPosition';
14+
export { getCheckeredBackground } from './utils/getCheckeredBackground';
1415
export { getColor } from './utils/getColor';
1516
export { getColorV8 } from './utils/getColorV8';
1617
export { getFloatingPlacements } from './utils/getFloatingPlacements';
@@ -33,6 +34,7 @@ export {
3334
type IGardenTheme,
3435
type IThemeProviderProps,
3536
type ArrowPosition,
37+
type CheckeredBackgroundParameters,
3638
type ColorParameters,
3739
type FocusBoxShadowParameters,
3840
type FocusStylesParameters,

packages/theming/src/types/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ export const PLACEMENT = [
4545

4646
export type Placement = (typeof PLACEMENT)[number];
4747

48+
export type CheckeredBackgroundParameters = {
49+
overlay?: string;
50+
positionY?: number;
51+
repeat?: 'repeat' | 'repeat-x';
52+
size: number;
53+
theme: IGardenTheme;
54+
};
55+
4856
export type ColorParameters = {
4957
dark?: {
5058
hue?: string;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Copyright Zendesk, Inc.
3+
*
4+
* Use of this source code is governed under the Apache License, Version 2.0
5+
* found at http://www.apache.org/licenses/LICENSE-2.0.
6+
*/
7+
8+
import { getCheckeredBackground } from './getCheckeredBackground';
9+
import DEFAULT_THEME from '../elements/theme';
10+
import PALETTE from '../elements/palette';
11+
12+
describe('getCheckeredBackground', () => {
13+
it('returns a valid background', () => {
14+
const size = 10;
15+
const result = getCheckeredBackground({ theme: DEFAULT_THEME, size });
16+
const expected1 = `0 0px / ${size}px ${size}px repeat`;
17+
const expected2 = `${size / 2}px ${size / 2}px / ${size}px ${size}px repeat`;
18+
19+
expect(result).toContain(expected1);
20+
expect(result).toContain(expected2);
21+
});
22+
23+
it('handles color overlay as expected', () => {
24+
const expected = `${PALETTE.blue[700]}80`;
25+
const result = getCheckeredBackground({ theme: DEFAULT_THEME, size: 10, overlay: expected });
26+
27+
expect(result).toContain(`linear-gradient(${expected}, ${expected})`);
28+
});
29+
30+
it('handles linear-gradient overlay as expected', () => {
31+
const expected = `linear-gradient(to right, ${PALETTE.white}, ${PALETTE.black})`;
32+
const result = getCheckeredBackground({ theme: DEFAULT_THEME, size: 10, overlay: expected });
33+
34+
expect(result).toContain(`${expected},`);
35+
});
36+
37+
it('handles vertical position as expected', () => {
38+
const size = 10;
39+
const positionY = DEFAULT_THEME.space.base;
40+
const result = getCheckeredBackground({ theme: DEFAULT_THEME, size, positionY });
41+
const expected1 = `0 ${positionY}px`;
42+
const expected2 = `${size / 2}px ${size / 2 + positionY}px`;
43+
44+
expect(result).toContain(expected1);
45+
expect(result).toContain(expected2);
46+
});
47+
48+
it('handles repeat as expected', () => {
49+
const repeat = 'repeat-x';
50+
const result = getCheckeredBackground({ theme: DEFAULT_THEME, size: 10, repeat });
51+
52+
expect(result).toContain(repeat);
53+
});
54+
55+
it('handles RTL as expected', () => {
56+
const theme = { ...DEFAULT_THEME, rtl: true };
57+
const size = 10;
58+
const result = getCheckeredBackground({ theme, size });
59+
const expected1 = `100% 0px / ${size}px ${size}px repeat`;
60+
const expected2 = `calc(100% - ${size / 2}px) ${size / 2}px / ${size}px ${size}px repeat`;
61+
62+
expect(result).toContain(expected1);
63+
expect(result).toContain(expected2);
64+
});
65+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Copyright Zendesk, Inc.
3+
*
4+
* Use of this source code is governed under the Apache License, Version 2.0
5+
* found at http://www.apache.org/licenses/LICENSE-2.0.
6+
*/
7+
8+
import { CheckeredBackgroundParameters } from '../types';
9+
import { getColor } from './getColor';
10+
11+
/**
12+
* Get a checkered background image.
13+
*
14+
* @param {Object} options.theme Provides information for pattern color and LTR/RTL layout
15+
* @param {number} options.size The pixel size of the checkered pattern
16+
* @param {string} [options.overlay] Optional
17+
* [color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) with transparency or
18+
* [`linear-gradient()`](https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient)
19+
* overlay to apply on top of the checkered pattern
20+
* @param {number} [options.positionY=0] Optional vertical position for starting the pattern (default `0`)
21+
* @param {string} [options.repeat='repeat'] Optional repeat value for the pattern; either `'repeat'` or `'repeat-x'` (default `'repeat'`)
22+
*/
23+
export const getCheckeredBackground = ({
24+
theme,
25+
size,
26+
overlay,
27+
positionY = 0,
28+
repeat = 'repeat'
29+
}: CheckeredBackgroundParameters) => {
30+
const color = getColor({ theme, variable: 'border.default' });
31+
const dimensions = `${size}px ${size}px`;
32+
const positionX1 = theme.rtl ? '100%' : '0';
33+
const positionX2 = theme.rtl ? `calc(100% - ${size / 2}px)` : `${size / 2}px`;
34+
const position1 = `${positionX1} ${positionY}px`;
35+
const position2 = `${positionX2} ${size / 2 + positionY}px`;
36+
const position3 = `${positionX2} ${positionY}px`;
37+
const position4 = `${positionX1} ${size / -2 + positionY}px`;
38+
let retVal = `
39+
linear-gradient(45deg, ${color} 25%, transparent 25%) ${position1} / ${dimensions} ${repeat},
40+
linear-gradient(45deg, transparent 75%, ${color} 75%) ${position2} / ${dimensions} ${repeat},
41+
linear-gradient(135deg, ${color} 25%, transparent 25%) ${position3} / ${dimensions} ${repeat},
42+
linear-gradient(135deg, transparent 75%, ${color} 75%) ${position4} / ${dimensions} ${repeat}
43+
`;
44+
45+
if (overlay) {
46+
retVal = overlay.startsWith('linear-gradient')
47+
? `${overlay}, ${retVal}`
48+
: `linear-gradient(${overlay}, ${overlay}), ${retVal}`;
49+
}
50+
51+
return retVal;
52+
};

packages/theming/src/utils/getColor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ const toProperty = (object: object, path: string) => {
134134
* `shade`, `offset`, and `transparency` are used as fallbacks to determine the
135135
* color.
136136
*
137-
* @param {Object} [options.theme] Provides values used to resolve the desired color
137+
* @param {Object} options.theme Provides values used to resolve the desired color
138138
* @param {string} [options.variable] A variable key (i.e. `'background.default'`) used to resolve a color value for the theme color base
139139
* @param {Object} [options.dark] An object with `hue`, `shade`, `offset`, and `transparency` values to be used in dark mode
140140
* @param {Object} [options.light] An object with `hue`, `shade`, `offset`, and `transparency` values to be used in light mode

0 commit comments

Comments
 (0)