Skip to content

Commit

Permalink
Merge branch 'release-1.2.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
muhammadsammy committed May 12, 2020
2 parents f75655e + dfc0e75 commit 308346c
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 156 deletions.
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,22 +170,21 @@ export const buttonClasses = {
The default types exported from this package are tailwindcss default ones.
But if you modified some classes in your tailwind config file, you can use the CLI tool to create a file with generated types for these classes.

### Use per project:
### CLI arguments:

- -c --config The name of TailwindCSS config file.
- -o --output _(Optional)_ The name of generated file

Add it in your package.json scripts:

```json
"scripts": {
"generate" : "tailwindcss-classnames"
"generate-types" : "tailwindcss-classnames --config tailwind.config.js"
}
```

or simply run `npx tailwindcss-classnames`

### Install globally:

just `npm i -g tailwindcss-classnames` and run the command where the config file is located.

## Custom typing

By default you have all the classes available as types, though you might not use all of them. You can customize your own by:
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tailwindcss-classnames",
"version": "1.2.2",
"version": "1.2.3",
"description": "Functional typed classnames for TailwindCSS",
"author": "Christian Alfoni <[email protected]>",
"contributors": [
Expand All @@ -21,7 +21,7 @@
"build:lib": "tsc --outDir lib --module commonjs",
"build:es": "tsc --outDir es --module es2015",
"build:umd": "npm run build:es && rollup --config && dts-bundle --name dist/bundle --main es --outputAsModuleFolder",
"clean": "rimraf dist es lib coverage",
"clean": "rimraf dist es lib coverage tailwindcss-classnames.ts",
"typecheck": "tsc --noEmit",
"lint": "tslint --project tsconfig.json --format stylish",
"format": "prettier '**/*.{md,js,jsx,json,ts,tsx}' --write",
Expand All @@ -47,6 +47,7 @@
],
"dependencies": {
"classnames": "^2.2.6",
"commander": "^5.1.0",
"inquirer": "^7.1.0",
"lodash.isempty": "^4.4.0",
"tslib": "^1.9.3"
Expand Down
188 changes: 40 additions & 148 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,156 +1,48 @@
#!/usr/bin/env node

/* tslint:disable:no-eval no-console */
import fs from 'fs';
import commander from 'commander';
import inquirer from 'inquirer';
import isEmpty from 'lodash.isempty';

import { baseTemplateString, defaultColors, defaultScreens, defaultSpacing, generateTypes } from './utils';

inquirer
.prompt([
{
name: 'configFilename',
type: 'input',
default: 'tailwind.config.js',
message: 'Tailwind configuration filename',
},
{
name: 'outputFilename',
type: 'input',
default: 'tailwindcss-classnames.ts',
message: 'Name of the file with generated types',
},
])
.then(answers => {
fs.readFile(`./${answers.configFilename}`, { encoding: 'utf-8' }, (err, data: any) => {
if (err) {
console.error(err);
}

data = data.replace(/('|")?plugins('|")? *: *\[(.*|\n)*?\],?/g, '');

const CONFIG = eval(data);
const THEME_CONFIG = CONFIG.theme;
const PREFIX_CONFIG = CONFIG.prefix;
const SEPARATOR_CONFIG = CONFIG.separator;

const prefix = isEmpty(PREFIX_CONFIG) ? '' : PREFIX_CONFIG;
const separator = isEmpty(SEPARATOR_CONFIG) ? ':' : SEPARATOR_CONFIG;
const themeColors = isEmpty(THEME_CONFIG?.colors) ? defaultColors : THEME_CONFIG?.colors;
const extendedThemeColors = THEME_CONFIG?.extend?.colors;
const AllColors = extendedThemeColors ? { ...themeColors, ...extendedThemeColors } : themeColors;

const backgroundColors: string[] = [];
const placeholderColors: string[] = [];
const borderColors: string[] = [];
const textColors: string[] = [];
// theme: {
// colors: {
// colorkey: colorVal ( "#fff" | {light: "#fff", lighter: "#f0f0f0",...} )
// }
// }
const colors = Object.keys(AllColors);
for (let i = 0; i < colors.length; i += 1) {
const colorKey = colors[i];
const colorVal = AllColors[colorKey];
if (colorVal instanceof Object) {
const colorVariants = Object.keys(colorVal);
colorVariants.map((variant: string) => {
if (variant === 'default') {
variant = '';
} else {
variant = `-${variant}`;
}
backgroundColors.push(`${prefix}bg-${colorKey}${variant}`);
placeholderColors.push(`${prefix}placeholder-${colorKey}${variant}`);
borderColors.push(`${prefix}border-${colorKey}${variant}`);
textColors.push(`${prefix}text-${colorKey}${variant}`);
});
} else {
backgroundColors.push(`${prefix}bg-${colorKey}`);
placeholderColors.push(`${prefix}placeholder-${colorKey}`);
borderColors.push(`${prefix}border-${colorKey}`);
textColors.push(`${prefix}text-${colorKey}`);
}
}

const themeBreakpoints = isEmpty(THEME_CONFIG?.screens) ? defaultScreens : THEME_CONFIG?.screens;
const extendedThemeBreakpoints = THEME_CONFIG?.extend?.screens;
const breakpoints = extendedThemeBreakpoints
? { ...themeBreakpoints, ...extendedThemeBreakpoints }
: themeBreakpoints;

const breakpointExportStatements: string[] = [];
const breakpointCreateCustomParams: string[] = [];
const breakpointCreateCustomReturns: string[] = [];
const maxWidthByBreakpoints: string[] = [];

Object.keys(breakpoints).map((breakpoint: string) => {
breakpointExportStatements.push(
`export const ${breakpoint}: TPseudoClass = className => ('${prefix}${breakpoint}${separator}' + className) as TTailwindString;`,
);
breakpointCreateCustomParams.push(`${breakpoint}: TPseudoClass<T>;`);
breakpointCreateCustomReturns.push(`${breakpoint},`);
maxWidthByBreakpoints.push(`${prefix}max-w-screen-${breakpoint}`);
});

const themeSpacings = isEmpty(THEME_CONFIG?.spacing) ? defaultSpacing : THEME_CONFIG?.spacing;
const extendedThemeSpacings = THEME_CONFIG?.extend?.spacing;
const allSpacings = extendedThemeSpacings ? { ...themeSpacings, ...extendedThemeSpacings } : themeSpacings;

const paddingSpacings: string[] = [];
const marginSpacings: string[] = [];
const widthSpacings: string[] = [];
const heightSpacings: string[] = [];

const sides = ['', 'y', 'x', 't', 'r', 'b', 'l'];

sides.map(side => {
paddingSpacings.push(`${prefix}p${side}-auto`);
marginSpacings.push(`${prefix}m${side}-auto`);
import { createFileWithGeneratedTypes } from './createFile';

commander
.option('-c, --config <config>', 'Name of the TailwindCSS config file')
.option('-o, --output <output>', 'Name of the file with the generated types', 'tailwindcss-classnames.ts')
.action(({ config, output }) => {
if (config) {
createFileWithGeneratedTypes({
configFilename: config,
outputFilename: output,
});

Object.keys(allSpacings).map((spacing, i) => {
widthSpacings.push(`${prefix}w-${spacing}`);
heightSpacings.push(`${prefix}h-${spacing}`);
sides.map(side => {
paddingSpacings.push(`${prefix}p${side}-${spacing}`);
marginSpacings.push(`${prefix}m${side}-${spacing}`);
if (parseInt(spacing, 10) !== 0 && Object.values(allSpacings)[i] !== 0) {
paddingSpacings.push(`${prefix}-p${side}-${spacing}`);
marginSpacings.push(`${prefix}-m${side}-${spacing}`);
} else {
inquirer
.prompt([
{
name: 'configFilename',
type: 'input',
default: 'tailwind.config.js',
message: 'Tailwind configuration filename',
},
{
name: 'outputFilename',
type: 'input',
default: 'tailwindcss-classnames.ts',
message: 'Name of the file with generated types',
},
])
.then(answers => {
createFileWithGeneratedTypes({
configFilename: answers.configFilename,
outputFilename: answers.outputFilename,
});
})
.catch(error => {
if (error.isTtyError) {
console.error("Prompt couldn't be rendered in the current environment");
} else {
console.error('Something went wrong with the prompt');
}
});
});

const result = baseTemplateString
.replace(/_PREFIX_/g, prefix)
.replace(/_SEPARATOR_/g, separator)
.replace(/MAX_WIDTH_BY_BREAKPOINTS/g, generateTypes(maxWidthByBreakpoints))
.replace(/BREAKPOINT_EXPORT_STATEMENTS/g, breakpointExportStatements.join('\n\n'))
.replace(/BREAKPOINTS_CREATE_CUSTOM_PARAMS/g, breakpointCreateCustomParams.join('\n '))
.replace(/BREAKPOINTS_CREATE_CUSTOM_RETURNS/g, breakpointCreateCustomReturns.join('\n '))
.replace(/PADDINGS/g, generateTypes(paddingSpacings))
.replace(/MARGINS/g, generateTypes(marginSpacings))
.replace(/WIDTH_SPACINGS/g, generateTypes(widthSpacings))
.replace(/HEIGHT_SPACINGS/g, generateTypes(heightSpacings))
.replace(/BACKGROUND_COLORS/g, generateTypes(backgroundColors))
.replace(/PLACEHOLDER_COLORS/g, generateTypes(placeholderColors))
.replace(/BORDER_COLORS/g, generateTypes(borderColors))
.replace(/TEXT_COLORS/g, generateTypes(textColors));

fs.writeFile(`${answers.outputFilename}`, result, 'utf8', error => {
if (error) {
console.error(error);
}
});
});
})
.catch(error => {
if (error.isTtyError) {
console.error("Prompt couldn't be rendered in the current environment");
} else {
console.error('Something went wrong with the prompt');
}
});

commander.parse(process.argv);
132 changes: 132 additions & 0 deletions src/createFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* tslint:disable:no-eval no-console */

import fs from 'fs';
import isEmpty from 'lodash.isempty';
import { baseTemplateString, defaultColors, defaultScreens, defaultSpacing, generateTypes } from './utils';

interface IOptions {
configFilename: string;
outputFilename: string;
}

export function createFileWithGeneratedTypes({ configFilename, outputFilename }: IOptions) {
fs.readFile(`./${configFilename}`, { encoding: 'utf-8' }, (err, data: any) => {
if (err) {
console.error(err);
}

data = data.replace(/('|")?plugins('|")? *: *\[(.*|\n)*?\],?/g, '');

const CONFIG = eval(data);
const THEME_CONFIG = CONFIG.theme;
const PREFIX_CONFIG = CONFIG.prefix;
const SEPARATOR_CONFIG = CONFIG.separator;

const prefix = isEmpty(PREFIX_CONFIG) ? '' : PREFIX_CONFIG;
const separator = isEmpty(SEPARATOR_CONFIG) ? ':' : SEPARATOR_CONFIG;
const themeColors = isEmpty(THEME_CONFIG?.colors) ? defaultColors : THEME_CONFIG?.colors;
const extendedThemeColors = THEME_CONFIG?.extend?.colors;
const AllColors = extendedThemeColors ? { ...themeColors, ...extendedThemeColors } : themeColors;

const backgroundColors: string[] = [];
const placeholderColors: string[] = [];
const borderColors: string[] = [];
const textColors: string[] = [];
// theme: {
// colors: {
// colorkey: colorVal ( "#fff" | {light: "#fff", lighter: "#f0f0f0",...} )
// }
// }
const colors = Object.keys(AllColors);
for (let i = 0; i < colors.length; i += 1) {
const colorKey = colors[i];
const colorVal = AllColors[colorKey];
if (colorVal instanceof Object) {
const colorVariants = Object.keys(colorVal);
colorVariants.map((variant: string) => {
variant = variant === 'default' ? '' : `-${variant}`;
backgroundColors.push(`${prefix}bg-${colorKey}${variant}`);
placeholderColors.push(`${prefix}placeholder-${colorKey}${variant}`);
borderColors.push(`${prefix}border-${colorKey}${variant}`);
textColors.push(`${prefix}text-${colorKey}${variant}`);
});
} else {
backgroundColors.push(`${prefix}bg-${colorKey}`);
placeholderColors.push(`${prefix}placeholder-${colorKey}`);
borderColors.push(`${prefix}border-${colorKey}`);
textColors.push(`${prefix}text-${colorKey}`);
}
}

const themeBreakpoints = isEmpty(THEME_CONFIG?.screens) ? defaultScreens : THEME_CONFIG?.screens;
const extendedThemeBreakpoints = THEME_CONFIG?.extend?.screens;
const breakpoints = extendedThemeBreakpoints
? { ...themeBreakpoints, ...extendedThemeBreakpoints }
: themeBreakpoints;

const breakpointExportStatements: string[] = [];
const breakpointCreateCustomParams: string[] = [];
const breakpointCreateCustomReturns: string[] = [];
const maxWidthByBreakpoints: string[] = [];

Object.keys(breakpoints).map((breakpoint: string) => {
breakpointExportStatements.push(
`export const ${breakpoint}: TPseudoClass = className => ('${prefix}${breakpoint}${separator}' + className) as TTailwindString;`,
);
breakpointCreateCustomParams.push(`${breakpoint}: TPseudoClass<T>;`);
breakpointCreateCustomReturns.push(`${breakpoint},`);
maxWidthByBreakpoints.push(`${prefix}max-w-screen-${breakpoint}`);
});

const themeSpacings = isEmpty(THEME_CONFIG?.spacing) ? defaultSpacing : THEME_CONFIG?.spacing;
const extendedThemeSpacings = THEME_CONFIG?.extend?.spacing;
const allSpacings = extendedThemeSpacings ? { ...themeSpacings, ...extendedThemeSpacings } : themeSpacings;

const paddingSpacings: string[] = [];
const marginSpacings: string[] = [];
const widthSpacings: string[] = [];
const heightSpacings: string[] = [];

const sides = ['', 'y', 'x', 't', 'r', 'b', 'l'];

sides.map(side => {
paddingSpacings.push(`${prefix}p${side}-auto`);
marginSpacings.push(`${prefix}m${side}-auto`);
});

Object.keys(allSpacings).map((spacing, i) => {
widthSpacings.push(`${prefix}w-${spacing}`);
heightSpacings.push(`${prefix}h-${spacing}`);
sides.map(side => {
paddingSpacings.push(`${prefix}p${side}-${spacing}`);
marginSpacings.push(`${prefix}m${side}-${spacing}`);
if (parseInt(spacing, 10) !== 0 && Object.values(allSpacings)[i] !== 0) {
paddingSpacings.push(`${prefix}-p${side}-${spacing}`);
marginSpacings.push(`${prefix}-m${side}-${spacing}`);
}
});
});

const result = baseTemplateString
.replace(/_PREFIX_/g, prefix)
.replace(/_SEPARATOR_/g, separator)
.replace(/MAX_WIDTH_BY_BREAKPOINTS/g, generateTypes(maxWidthByBreakpoints))
.replace(/BREAKPOINT_EXPORT_STATEMENTS/g, breakpointExportStatements.join('\n\n'))
.replace(/BREAKPOINTS_CREATE_CUSTOM_PARAMS/g, breakpointCreateCustomParams.join('\n '))
.replace(/BREAKPOINTS_CREATE_CUSTOM_RETURNS/g, breakpointCreateCustomReturns.join('\n '))
.replace(/PADDINGS/g, generateTypes(paddingSpacings))
.replace(/MARGINS/g, generateTypes(marginSpacings))
.replace(/WIDTH_SPACINGS/g, generateTypes(widthSpacings))
.replace(/HEIGHT_SPACINGS/g, generateTypes(heightSpacings))
.replace(/BACKGROUND_COLORS/g, generateTypes(backgroundColors))
.replace(/PLACEHOLDER_COLORS/g, generateTypes(placeholderColors))
.replace(/BORDER_COLORS/g, generateTypes(borderColors))
.replace(/TEXT_COLORS/g, generateTypes(textColors));

fs.writeFile(`${outputFilename}`, result, 'utf8', error => {
if (error) {
console.error(error);
}
});
});
}

0 comments on commit 308346c

Please sign in to comment.