Skip to content

Commit

Permalink
feat/tokenized-gradients: fix gradient token helper
Browse files Browse the repository at this point in the history
  • Loading branch information
8coon committed Sep 24, 2024
1 parent 6eb7fc0 commit 4624626
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/build/helpers/getGradientPointsFromColor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ export function getGradientPointsFromColor(
): GradientPoints {
const gradientPointData = typeof colorArg === 'function' ? colorArg() : { value: colorArg };

const colorRGB: string = color(gradientPointData.value).rgb().array().join(', ');
const colorRGB: string = color(gradientPointData.value).rgb().array().slice(0, 3).join(', ');
const colorAlpha = color(gradientPointData.value).alpha();

return opacityPoints
.map(([pointOpacity, pointCoordinate]) => {
const targetOpacity = colorAlpha < 1 ? colorAlpha : pointOpacity;
const targetOpacity = colorAlpha * pointOpacity;
const colorValue = `rgba(${colorRGB}, ${Math.round(targetOpacity * opacityMultiplier * 1000) / 1000})`;

if (typeof gradientPointData.key === 'string') {
Expand Down
45 changes: 40 additions & 5 deletions src/build/helpers/tokenHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,53 @@ describe('tokenHelpers', () => {
});

describe('gradient', () => {
test('calculates gradient string', () => {
test('calculates gradient string from 1 color with variable', () => {
const gradientToken = gradient(['blue']);
const gradientValue = gradientToken({});

expect(gradientValue).toEqual(
[
'rgba(0, 0, 255, 0) 0%',
'rgba(0, 0, 255, 0.05) 15%',
'rgba(0, 0, 255, 0.2) 30%',
'rgba(0, 0, 255, 0.8) 70%',
'rgba(0, 0, 255, 0.95) 85%',
'rgba(0, 0, 255, 1) 100%',
].join(', '),
);
});

test('calculates gradient string from 1 color with variable', () => {
const gradientToken = gradient([namedAlias('colorIconPrimary')]);
const gradientValue = gradientToken({ colors: { colorIconPrimary: 'blue' } as any });

expect(gradientValue).toEqual(
[
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 0)) 0%',
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 0.05)) 15%',
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 0.2)) 30%',
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 0.8)) 70%',
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 0.95)) 85%',
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 1)) 100%',
].join(', '),
);
});

test('calculates gradient string from 2 colors', () => {
const gradientToken = gradient([namedAlias('colorIconPrimary'), 'transparent']);
const gradientValue = gradientToken({ colors: { colorIconPrimary: 'blue' } as any });

expect(gradientValue).toEqual(
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 1)) 0%, rgba(0, 0, 0, 0, 0) 100%',
'var(--vkui--color_icon_primary, rgba(0, 0, 255, 1)) 0%, rgba(0, 0, 0, 0) 100%',
);
});

test('fails if bad number of arguments is given', () => {
expect(() => gradient([namedAlias('colorIconPrimary')])).toThrowError(
'Gradient stops length (1) is not equal to the number of opacity points given (2)',
test('calculates gradient string from 3 colors', () => {
const gradientToken = gradient(['blue', 'black', 'red']);
const gradientValue = gradientToken({});

expect(gradientValue).toEqual(
'rgba(0, 0, 255, 1) 0%, rgba(0, 0, 0, 1) 50%, rgba(255, 0, 0, 1) 100%',
);
});
});
Expand Down
32 changes: 19 additions & 13 deletions src/build/helpers/tokenHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import type { Property } from 'csstype';
import { ThemeDescription } from '@/interfaces/general';
import { Token } from '@/interfaces/general/tools/tokenValue';

import { getGradientPointsFromColor, makeGradientPointRaw } from './getGradientPointsFromColor';
import {
defaultOpacityPoints,
getGradientPointsFromColor,
makeGradientPointRaw,
OpacityPoints,
} from './getGradientPointsFromColor';

export type TokenFunction<T extends ThemeDescription> = (theme: Partial<T>) => Token<any, T>;
export type NamedTokenFunction<T extends ThemeDescription> = (
Expand Down Expand Up @@ -32,25 +37,26 @@ export function staticRef<T>(value: Token<T, any>): T {
return value;
}

function makeOpacityPoints(count: number): OpacityPoints {
const result: OpacityPoints = [];

for (let i = 0; i < count; i++) {
const percent = Math.round(i * (1 / (count - 1)) * 100);
result.push([1, percent]);
}

return result;
}

export function gradient<T extends ThemeDescription>(
stops: (Property.Color | NamedTokenFunction<T>)[],
opacityPoints: OpacityPoint[] = [
[1, 0],
[1, 100],
],
): TokenFunction<T> {
if (stops.length !== opacityPoints.length) {
throw new Error(
`Gradient stops length (${
stops.length
}) is not equal to the number of opacity points given (${opacityPoints.length})`,
);
}
const opacityPoints = stops.length > 1 ? makeOpacityPoints(stops.length) : defaultOpacityPoints;

return (theme) => {
return opacityPoints
.map(([pointOpacity, pointCoordinate], index) => {
const stop = stops[index];
const stop = stops[index] ?? stops[stops.length - 1];
const [stopKey, stopValue] = typeof stop === 'function' ? stop(theme) : [undefined, stop];

const pointRaw = makeGradientPointRaw(stopValue, stopKey);
Expand Down

0 comments on commit 4624626

Please sign in to comment.