I ended up finding a solution to my problem while writing this issue, but I believe it's something that styled-tools should handle by default. I'm working with the sample below which a reakit theme, and the issue is in contrastText. What ends up happening is that bg resolves to a prop-getter function instead of a string. The reason being that bgNeedle is a prop-getter that resolves to a prop-getter which is not supported by withProp. What I ended up doing is writing a custom implementation of withProp (below the example) that recursively resolves prop-getter functions. It would be useful if this was either the default behavior of withProp or was exposed as a separate function.
// utils.ts
import { range } from 'lodash-es';
import { getLuminance, lighten } from 'polished';
import { Needle, palette as p, withProp } from 'styled-tools';
export const contrastText = (bgNeedle: Needle<any>) =>
withProp(
[bgNeedle, p('black'), p('white')] as any,
(bg: string, black: string, white: string) => {
// bg ends up being a prop getter function here instead of a string.
return getLuminance(bg) > 0.179 ? black : white;
},
);
export const contrastPalette = (palette: string, tone?: number) =>
contrastText(p(palette, tone));
export const lightenPalette = (
amount: number,
palette: string,
tone?: number,
) =>
withProp([p(palette, tone)] as any, (color: string) =>
lighten(amount, color),
);
export const tonePalette = (palette: string) => [
p(palette),
...range(0.1, 0.5, 0.1).map(i => lightenPalette(i, palette)),
];
export const tonePaletteText = (palette: string) =>
range(5).map(i => contrastPalette(palette, i));
export const tonePaletteWithText = (name: string, palette: string) => ({
[name]: tonePalette(palette),
[`${name}Text`]: tonePaletteText(name)
});
// index.ts
import { tonePaletteWithText } from './utils';
export const palette = {
white: '#fff',
black: '#000',
astronautBlue: '#003a5d',
...tonePaletteWithText('primary', 'astronautBlue'),
};
Solution
// simple deepWithProp
const deepWithProp = <Props extends object, T = undefined>(
needle: Needle<Props> | Needle<Props>[],
fn: (...args: any[]) => T
) => (props = {}): T => {
if (Array.isArray(needle)) {
const needles = needle.map(arg => deepWithProp(arg, x => x)(props));
return fn(...needles);
}
if (typeof needle === "function") {
return fn(deepWithProp(needle(props as Props), x => x)(props));
}
return fn(prop(needle, needle)(props));
};
I ended up finding a solution to my problem while writing this issue, but I believe it's something that styled-tools should handle by default. I'm working with the sample below which a reakit theme, and the issue is in
contrastText. What ends up happening is thatbgresolves to a prop-getter function instead of a string. The reason being thatbgNeedleis a prop-getter that resolves to a prop-getter which is not supported bywithProp. What I ended up doing is writing a custom implementation ofwithProp(below the example) that recursively resolves prop-getter functions. It would be useful if this was either the default behavior ofwithPropor was exposed as a separate function.Solution