Skip to content

Commit

Permalink
feat(labs): Add color expansion support to theme object
Browse files Browse the repository at this point in the history
  • Loading branch information
anicholls committed Oct 31, 2019
1 parent b191cb8 commit 2d90b40
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 22 deletions.
11 changes: 10 additions & 1 deletion modules/_labs/core/react/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ import type from './lib/type';
import space from './lib/space';
import CanvasProvider from './lib/CanvasProvider';
import {breakpoints, CanvasBreakpoints, BreakpointKey} from './lib/theming/breakpoints';
import createCanvasTheme from './lib/theming/createCanvasTheme';

export default type;
export {breakpoints, type, space, BreakpointKey, CanvasBreakpoints, CanvasProvider};
export {
breakpoints,
type,
space,
BreakpointKey,
CanvasBreakpoints,
CanvasProvider,
createCanvasTheme,
};
export * from './lib/type';
export * from './lib/theming/types';
export * from './lib/theming/theme';
87 changes: 87 additions & 0 deletions modules/_labs/core/react/lib/theming/createCanvasTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import chroma from 'chroma-js';
import deepmerge from 'deepmerge';
import colors from '@workday/canvas-colors-web';
import {defaultCanvasTheme} from './theme';
import {
CanvasTheme,
PartialCanvasTheme,
CanvasThemePalette,
PartialCanvasThemePalette,
} from './types';
import {CanvasColor} from '@workday/canvas-kit-react-core';

const {gradients, primary, ...allColors} = colors;

// TODO: Make darken prop more readable.
function shiftColor(hexColor: string, darken: boolean = true) {
const canvasColor = Object.keys(allColors).find(
key => allColors[key as CanvasColor] === hexColor
);

if (canvasColor) {
const colorRegex = /([a-zAz]*)(\d{3})/g;
const match = colorRegex.exec(canvasColor);

if (match) {
const baseColor = match[1];
const shadeNumber = parseInt(match[2], 10);

const newShade = darken ? shadeNumber + 100 : shadeNumber - 100;

if (newShade >= 100 && newShade <= 600) {
return colors[(baseColor + newShade) as CanvasColor];
}
}
}

const newColor = darken ? chroma(hexColor).darken() : chroma(hexColor).brighten();

return newColor.hex();
}

function fillPalette(palette?: PartialCanvasThemePalette): CanvasThemePalette | {} {
if (!palette) {
return {};
}
const shades = {...palette};

if (!shades.main) {
console.warn(
'The color provided to fillPalette(palette) is invalid. The palette object needs to have a `main` property'
);
return {};
}

const dark = shiftColor(shades.main);
const darkest = shiftColor(dark);
const light = shiftColor(shades.main, false);
const lightest = shiftColor(light, false);

return {
lightest,
light,
main: shades.main,
dark,
darkest,
contrast: shades.contrast || colors.frenchVanilla100,
};
}

export default function createCanvasTheme(partialTheme: PartialCanvasTheme): CanvasTheme {
const {palette, breakpoints = {}} = partialTheme;
const {primary, alert, error, success, neutral, common = {}} = palette!;

const mergable: PartialCanvasTheme = {
palette: {
common,
primary: fillPalette(primary),
alert: fillPalette(alert),
error: fillPalette(error),
success: fillPalette(success),
neutral: fillPalette(neutral),
},
breakpoints,
};

return deepmerge(defaultCanvasTheme, mergable) as CanvasTheme;
}
18 changes: 0 additions & 18 deletions modules/_labs/core/react/lib/theming/theme.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import * as React from 'react';
import colors from '@workday/canvas-colors-web';
import deepmerge from 'deepmerge';
import {CanvasTheme} from './types';
import {ThemeContext} from '@emotion/core';
import {breakpoints, up, down, between, only} from './breakpoints';

/**
* Considerations:
* - Hex vs. Canvas colors
* - Hover/Active and constrasting text colors need to be calculateable. Two options:
* 1. Reverse lookup. i.e. given blueberry 400, we assume hover is 500 and active is 600. We still need to calculate colors outside our range though (i.e. Hex or if we run out of shades)
* 2. Calculate all colors. This would likely require a change to our colors, but would use the same approach in all cases.
* - Should consumers be able to theme grays? (e.g. pills, secondary buttons, etc.)
* - Should components that accept a color be controlled by the theme (e.g. StatusIndicator), or is it only errors and alerts?
* - Text colors?
* - Background?
*/

export const defaultCanvasTheme: CanvasTheme = {
palette: {
primary: {
Expand Down Expand Up @@ -105,8 +92,3 @@ export function useTheme(theme?: Object): CanvasTheme {

return defaultCanvasTheme;
}

// TODO: Should we use PartialCanvasTheme here?
export function createCanvasTheme(partialTheme: Object): CanvasTheme {
return deepmerge(defaultCanvasTheme, partialTheme);
}
6 changes: 4 additions & 2 deletions modules/_labs/core/react/lib/theming/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {CanvasBreakpoints, BreakpointFnParam} from './breakpoints';
/**
* A single palette within a Canvas theme
*/
type CanvasThemePalette = {
export type CanvasThemePalette = {
lightest: string;
light: string;
main: string;
Expand All @@ -25,7 +25,8 @@ export interface CanvasTheme {
primary: CanvasThemePalette;
error: CanvasThemePalette;
alert: CanvasThemePalette;
[index: string]: CanvasThemePalette | CanvasThemeCommonPalette;
success: CanvasThemePalette;
neutral: CanvasThemePalette;
};
breakpoints: {
values: CanvasBreakpoints;
Expand All @@ -51,3 +52,4 @@ type RecursivePartial<T> = {
};

export type PartialCanvasTheme = RecursivePartial<CanvasTheme>;
export type PartialCanvasThemePalette = RecursivePartial<CanvasThemePalette>;
2 changes: 1 addition & 1 deletion modules/_labs/core/react/stories/stories_theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const PaletteTitle = styled(Swatch)(

const createSwatch = (name: string, color: string, contrast: string, Component = Swatch) => {
return (
<Component bg={color} contrast={contrast} key={color}>
<Component bg={color} contrast={contrast} key={`${name}-${color}`}>
{name}
{contrast && <span>{name}</span>}
</Component>
Expand Down

0 comments on commit 2d90b40

Please sign in to comment.