Skip to content

Commit

Permalink
Add spacesAfterCommas config option
Browse files Browse the repository at this point in the history
  • Loading branch information
elchininet committed Jul 16, 2023
1 parent 3048239 commit 3a0bd29
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 21 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,16 @@ It is possible to instantiate the class using any of the previous inputs.
interface Options {
decimals?: number; // defaults to 6
legacyCSS: boolean; // defaults to false
spacesAfterCommas: boolean; // defaults to false
}
```

| Option | Only for CSS output | Description |
| ----------------- | ------------------- | -------------------------------------------------------------------------------------------------------------- |
| decimals | no | This options set what is the maximum number of decimals for the outputs |
| legacyCSS | yes | This options decides if the CSS output should be CSS Level 3 (legacy) or CSS Level 4 |
| spacesAfterCommas | yes | This options only takes place if `legacyCSS` is set to true. It decides if the comas should have a space after |

###### Class instantiation examples

```javascript
Expand Down Expand Up @@ -295,7 +302,8 @@ There are 43 static methods available, 16 of them to convert colors, 12 to creat

>Note: the library tries to detect some options automatically if you don‘t send them in the [options object](#options-object). These are the rules for this autodetection:
>
> * `legacyCSS`: if this option is set, then its value prevail, if it is not set, and all the CSS inputs are provided in CSS Level 3, then this option will be `true`, otherwise it will take its default value which is `false`.
> * `legacyCSS`: if this option is set, then its value prevails, if it is not set, and all the CSS inputs are provided in CSS Level 3, then this option will be `true`, otherwise it will take its default value which is `false`.
> * `spacesAfterCommas`: if this option is set, then its value prevails, if it is not set, and all the CSS inputs are provided with spaces after the commas, then this option will be `true`. If the inputs are not consistent in this aspect, then it will take its default value which is `false` (This option only takes place if `legacyCSS` is `true` or it has been autodetected as `true`)
###### Color conversion static methods

Expand Down
2 changes: 1 addition & 1 deletion dist/web/colortranslator.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/scripts/bundle.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/@types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface ObjectProps<T> {
export interface Options {
decimals: number;
legacyCSS: boolean;
spacesAfterCommas: boolean;
}

export type InputOptions = Partial<Options>;
25 changes: 16 additions & 9 deletions src/color/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import {
getOrderedArrayString
} from '#helpers';

const getComma = (withSpace: boolean): string => withSpace
? ', '
: ',';

const prepareColorForCss = (color: Color, isHex = false): NumberOrString[] => {
const props = getOrderedArrayString(Object.keys(color));
const model = VALID_COLOR_OBJECTS[props];
Expand Down Expand Up @@ -56,13 +60,14 @@ export const CSS = {
return getResultFromTemplate(template, values);
},
[ColorModel.RGB]: (color: RGBObject, options: Options): string => {
const { legacyCSS } = options;
const { legacyCSS, spacesAfterCommas } = options;
const comma = getComma(spacesAfterCommas);
const values = prepareColorForCss(color);
const template = legacyCSS
? (
values.length === 4
? 'rgba({1},{2},{3},{4})'
: 'rgb({1},{2},{3})'
? `rgba({1}${comma}{2}${comma}{3}${comma}{4})`
: `rgb({1}${comma}{2}${comma}{3})`
)
: (
values.length === 4
Expand All @@ -72,13 +77,14 @@ export const CSS = {
return getResultFromTemplate(template, values);
},
[ColorModel.HSL]: (color: HSLObject, options: Options): string => {
const { legacyCSS } = options;
const { legacyCSS, spacesAfterCommas } = options;
const comma = getComma(spacesAfterCommas);
const values = prepareColorForCss(color);
const template = legacyCSS
? (
values.length === 4
? 'hsla({1},{2}%,{3}%,{4})'
: 'hsl({1},{2}%,{3}%)'
? `hsla({1}${comma}{2}%${comma}{3}%${comma}{4})`
: `hsl({1}${comma}{2}%${comma}{3}%)`
)
: (
values.length === 4
Expand All @@ -88,13 +94,14 @@ export const CSS = {
return getResultFromTemplate(template, values);
},
[ColorModel.CMYK]: (color: CMYKObject, options: Options): string => {
const { legacyCSS } = options;
const { legacyCSS, spacesAfterCommas } = options;
const comma = getComma(spacesAfterCommas);
const values = prepareColorForCss(color);
const template = legacyCSS
? (
values.length === 5
? 'device-cmyk({1}%,{2}%,{3}%,{4}%,{5})'
: 'device-cmyk({1}%,{2}%,{3}%,{4}%)'
? `device-cmyk({1}%${comma}{2}%${comma}{3}%${comma}{4}%${comma}{5})`
: `device-cmyk({1}%${comma}{2}%${comma}{3}%${comma}{4}%)`
)
: (
values.length === 5
Expand Down
7 changes: 6 additions & 1 deletion src/constants/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,9 @@ export const VALID_COLOR_OBJECTS: Record<string, ColorModel> = {
AHLS: ColorModel.HSL,
CKMY: ColorModel.CMYK,
ACKMY: ColorModel.CMYK
};
};

export enum TypeOf {
NUMBER = 'number',
BOOLEAN = 'boolean'
}
3 changes: 2 additions & 1 deletion src/constants/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { MAX_DECIMALS } from './numbers';

export const DEFAULT_OPTIONS: Options = {
decimals: MAX_DECIMALS,
legacyCSS: false
legacyCSS: false,
spacesAfterCommas: false
};
41 changes: 34 additions & 7 deletions src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
PCENT,
HEX,
MAX_DECIMALS,
DEFAULT_OPTIONS
DEFAULT_OPTIONS,
TypeOf
} from '#constants';

//---Has property
Expand Down Expand Up @@ -62,7 +63,6 @@ export const getBase255Number = (color: string, alpha = false): number => {
return Math.min(+color, alpha ? 1 : 255);
};


//---Calculate a decimal 0-1 value from CMYK value
export const getCMYKNumber = (color: string): number => Math.min(PCENT.test(color) ? percentNumber(color) / 100 : +color, 1);

Expand All @@ -86,17 +86,44 @@ export const parseOptions = (options: Partial<Options>): Options => ({
...options
});

interface MatchOptions {
legacyCSS: number;
spacesAfterCommas: number;
}

export const getOptionsFromColorInput = (options: InputOptions, ...colors: ColorInput[]): Options => {
const cssColors = colors.filter((color: ColorInput): boolean => typeof color === 'string') as string[];
const allLegacy = cssColors.every((color: string): boolean => {
return color.includes(',');
const matchOptions: MatchOptions = {
legacyCSS: 0,
spacesAfterCommas: 0
};
cssColors.forEach((color: string): void => {
if (color.includes(',')){
matchOptions.legacyCSS ++;
const commasWithNextCharacter = color.match(/,( +|\d+)/g);
if (
new Set(commasWithNextCharacter).size === 1 &&
/ +/.test(commasWithNextCharacter[0].slice(1))
) {
matchOptions.spacesAfterCommas ++;
}
}
});
return {
decimals: typeof options.decimals === 'number'
decimals: typeof options.decimals === TypeOf.NUMBER
? options.decimals
: DEFAULT_OPTIONS.decimals,
legacyCSS: typeof options.legacyCSS === 'boolean'
legacyCSS: typeof options.legacyCSS === TypeOf.BOOLEAN
? options.legacyCSS
: Boolean(cssColors.length && allLegacy) || DEFAULT_OPTIONS.legacyCSS
: Boolean(
cssColors.length &&
matchOptions.legacyCSS === cssColors.length
) || DEFAULT_OPTIONS.legacyCSS,
spacesAfterCommas: typeof options.spacesAfterCommas === TypeOf.BOOLEAN
? options.spacesAfterCommas
: Boolean(
cssColors.length &&
matchOptions.spacesAfterCommas === cssColors.length
) || DEFAULT_OPTIONS.spacesAfterCommas
};
};
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,7 @@ export class ColorTranslator {
}

export {
InputOptions,
Harmony,
Mix,
HEXObject,
Expand Down
123 changes: 123 additions & 0 deletions tests/config-options.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { ColorTranslator, InputOptions } from '../src';
import { Options } from '../src/@types';
import { DEFAULT_OPTIONS } from '../src/constants';

interface TestCase {
options: InputOptions;
extraOptions?: InputOptions;
rgb: string;
rgba: string;
hsl: string;
hsla: string;
isDefault: boolean;
}

describe('ColorTranslator CSS config options', () => {

const COLOR = '#FF00FF';

const TEST_CASES: TestCase[] = [
{
options: { legacyCSS: true },
rgb: 'rgb(255,0,255)',
rgba: 'rgba(255,0,255,1)',
hsl: 'hsl(300,100%,50%)',
hsla: 'hsla(300,100%,50%,1)',
isDefault: false
},
{
options: { legacyCSS: false },
rgb: 'rgb(255 0 255)',
rgba: 'rgb(255 0 255 / 1)',
hsl: 'hsl(300 100% 50%)',
hsla: 'hsl(300 100% 50% / 1)',
isDefault: true
},
{
options: { spacesAfterCommas: true },
extraOptions: { legacyCSS: true },
rgb: 'rgb(255, 0, 255)',
rgba: 'rgba(255, 0, 255, 1)',
hsl: 'hsl(300, 100%, 50%)',
hsla: 'hsla(300, 100%, 50%, 1)',
isDefault: false
},
{
options: { spacesAfterCommas: false },
extraOptions: { legacyCSS: true },
rgb: 'rgb(255,0,255)',
rgba: 'rgba(255,0,255,1)',
hsl: 'hsl(300,100%,50%)',
hsla: 'hsla(300,100%,50%,1)',
isDefault: true
}
];

TEST_CASES.forEach((testCase: TestCase): void => {

const {
options,
extraOptions = {},
rgb,
rgba,
hsl,
hsla,
isDefault
} = testCase;

it(`Check ${JSON.stringify(options)}`, () => {
const mergedOptions = { ...options, ...extraOptions };
const instance = new ColorTranslator(COLOR, mergedOptions);
expect(instance.RGB).toBe(rgb);
expect(instance.RGBA).toBe(rgba);
expect(instance.HSL).toBe(hsl);
expect(instance.HSLA).toBe(hsla);
expect(ColorTranslator.toRGB(COLOR, mergedOptions)).toBe(rgb);
expect(ColorTranslator.toRGBA(COLOR, mergedOptions)).toBe(rgba);
expect(ColorTranslator.toHSL(COLOR, mergedOptions)).toBe(hsl);
expect(ColorTranslator.toHSLA(COLOR, mergedOptions)).toBe(hsla);
});

if (isDefault) {

const key: keyof Options = Object.keys(options)[0] as keyof Options;
const { [key]: defaultProp, ...defaultOptions } = { ...DEFAULT_OPTIONS };

it(`Check default value of ${key}:${defaultProp}`, () => {
const mergedOptions = { ...defaultOptions, ...extraOptions };
const instance = new ColorTranslator(COLOR, mergedOptions);
expect(instance.RGB).toBe(rgb);
expect(instance.RGBA).toBe(rgba);
expect(instance.HSL).toBe(hsl);
expect(instance.HSLA).toBe(hsla);
expect(ColorTranslator.toRGB(COLOR, mergedOptions)).toBe(rgb);
expect(ColorTranslator.toRGBA(COLOR, mergedOptions)).toBe(rgba);
expect(ColorTranslator.toHSL(COLOR, mergedOptions)).toBe(hsl);
expect(ColorTranslator.toHSLA(COLOR, mergedOptions)).toBe(hsla);
});

}

});

});

describe('ColorTranslator CSS config options autodetection', () => {

it(`legacyCSS auto detection`, () => {

expect(ColorTranslator.toRGB('rgba(255,0,255)')).toBe('rgb(255,0,255)');
expect(ColorTranslator.toHSLA('rgba(255 0 255 / 1)')).toBe('hsl(300 100% 50% / 1)');

});

it(`spacesAfterCommas auto detection`, () => {

expect(ColorTranslator.toRGBA('rgba(255,0,255)')).toBe('rgba(255,0,255,1)');
expect(ColorTranslator.toRGBA('rgba(255, 0,255)')).toBe('rgba(255,0,255,1)');
expect(ColorTranslator.toHSL('rgba(255, 0, 255, 1)')).toBe('hsl(300, 100%, 50%)');
expect(ColorTranslator.toHSL('rgba(255,0,255, 1)')).toBe('hsl(300,100%,50%)');

});

});

0 comments on commit 3a0bd29

Please sign in to comment.