Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a9656d6
feat: enable jit features all the time
muhammadsammy Oct 4, 2021
e4e28d5
chore: pump up tailwindcss version to v3.0.0-alpha.1
muhammadsammy Oct 4, 2021
f978a3a
feat: add variants to the cli as it's removed from the new config
muhammadsammy Oct 4, 2021
8856c27
chore: move constants to a constants folder
muhammadsammy Oct 14, 2021
71b8d22
chore: add colors to constants
muhammadsammy Oct 15, 2021
462f8a7
feat: update config closure evaluator to evaluate new tailwind3 configs
muhammadsammy Oct 16, 2021
cc3e294
feat!: rename overflow-clip & overflow-ellipsis to text-clip & text-e…
muhammadsammy Oct 16, 2021
011ba1a
refactor: simplify pseudoclassess generation method
muhammadsammy Oct 20, 2021
3379bff
fix: use correct condition for adding a dark mode variant
muhammadsammy Oct 20, 2021
b86ba8e
chore: remove wrong doc comment for parser getVariants method
muhammadsammy Oct 21, 2021
233390b
refactor: add base pseudoclassess to thier array outside `for of` loop
muhammadsammy Oct 22, 2021
a8173c7
feat: generate utility function for all category types ( #293)
muhammadsammy Oct 22, 2021
13ac441
fix: pass the parser into the fileContentGenerator instead of prefix
muhammadsammy Oct 22, 2021
9969289
fix: disable duplicate breakpoint pseudoclass variants generation
muhammadsammy Oct 22, 2021
37e508c
chore: rename classnames template funtion in FileContentGenerator
muhammadsammy Oct 22, 2021
e9f9488
feat(cli): generate per-category classnames
muhammadsammy Oct 22, 2021
8172a88
feat: add pseudoclassnames to their category function
muhammadsammy Oct 23, 2021
584ef7a
perf: use TS template literal types to generate pseudoclassess types
muhammadsammy Oct 23, 2021
a64f0d9
chore: make utity functions camel cased
muhammadsammy Oct 23, 2021
a8e2061
feat: generate utility functions for subcategories instead of categories
muhammadsammy Oct 23, 2021
8b5f3f2
chore: change default export object shape
muhammadsammy Oct 23, 2021
b82d4ad
perf: disable JIT opacity prefix feature
muhammadsammy Oct 23, 2021
756053f
fix: generate correct module exports
muhammadsammy Oct 23, 2021
bafc548
refactor: use a generic type for utility functions
muhammadsammy Oct 24, 2021
9c63930
chore: remove redundant code in `FileContentGenerator` class
muhammadsammy Oct 24, 2021
417adb1
fix: correctly generate border colors with no side `border-red-100`
muhammadsammy Oct 24, 2021
30e7a20
refactor: make `_generatedClassnames` field readonly in FileContentG…
muhammadsammy Oct 31, 2021
ca1e8d1
feat: add classnames with important modifiers to utility functions
muhammadsammy Nov 5, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"rollup-plugin-terser": "^7.0.2",
"semver": "^7.3.2",
"standard-version": "^9.1.0",
"tailwindcss": "^2.2.0",
"tailwindcss": "^3.0.0-alpha.1",
"ts-jest": "~26.5.1",
"typescript": "^4.3.4"
}
Expand Down
162 changes: 32 additions & 130 deletions src/cli/core/ClassnamesGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import {nonConfigurableClassNames} from '../lib/non-configurable';
import {
TAllClassnames, Backgrounds, Layout, Borders, Tables, Effects,
Interactivity, TransitionsAndAnimations, Transforms, Accessibility, SVG,
FlexBox, Grid, Spacing, Sizing, Typography, TGeneratedClassnames, Filters
FlexBox, Grid, Spacing, Sizing, Typography, Filters
} from '../types/classes';
import {TConfigTheme, TConfigDarkMode} from '../types/config';
import {tailwindLabsPlugins} from '../lib/tailwindlabs-plugins';
import {regularClassGroupKeys} from './constants/regularClassGroupKeys';

/**
* Responsible for generating the types from a parsed config by ConfigScanner.
Expand Down Expand Up @@ -70,17 +71,12 @@ export class ClassnamesGenerator {
/**
* Get the generated classnames.
*/
public generate = (): TGeneratedClassnames => {
return {
regularClassnames: this._generatedRegularClassnames,
pseudoClassnames: this._generatedPseudoClassnames,
};
public generate = (): TAllClassnames => {
return this._generatedRegularClassnames;
};

private isJitModeEnabled = (): boolean => this._configParser.getMode() === 'jit';

private layout = (): Layout | Record<keyof Layout | 'content', string[]> => {
const classnames = {
return {
...nonConfigurableClassNames.layout,
objectPosition: Object.keys(this._theme.objectPosition).map(x => 'object-' + x),
inset: Object.keys(this._theme.inset).flatMap(insetValue => {
Expand All @@ -93,13 +89,8 @@ export class ClassnamesGenerator {
zIndex: Object.keys(this._theme.zIndex).flatMap(zIndexValue =>
zIndexValue.startsWith('-') ? `-z-${zIndexValue.substring(1)}` : `z-${zIndexValue}`,
),
content: Object.keys(this._theme.content).map(x => 'content-' + x),
};

if (this.isJitModeEnabled()) {
return {...classnames, content: Object.keys(this._theme.content).map(x => 'content-' + x)};
} else {
return classnames;
}
};

private backgrounds = (): Backgrounds => {
Expand All @@ -117,7 +108,7 @@ export class ClassnamesGenerator {
};

private borders = (): Borders | Record<keyof Borders | 'caretColor', string[]> => {
const classnames = {
return {
// Add all non configurable classes in `borders` plugin.
// These are utilities that their names never change e.g. border styles (dashed, solid etc.)
...nonConfigurableClassNames.borders,
Expand All @@ -133,7 +124,7 @@ export class ClassnamesGenerator {
const sides = ['t', 'r', 'b', 'l'];
return sides.map(side => `border-${side}-${width}`).concat(`border-${width}`);
}),

caretColor: this.generateClassesWithColors('caretColor'),
/* Dynamic divide utilities */
divideColor: this.generateClassesWithColors('divideColor'),
divideOpacity: this.getGeneratedClassesWithOpacities().divideOpacities,
Expand All @@ -154,10 +145,6 @@ export class ClassnamesGenerator {
ringOffsetColor: this.generateClassesWithColors('ringOffsetColor'),
ringOffsetWidth: Object.keys(this._theme.ringOffsetWidth).map(x => 'ring-offset-' + x),
};

return this.isJitModeEnabled()
? {...classnames, caretColor: this.generateClassesWithColors('caretColor')}
: classnames;
};

private tables = (): Tables => {
Expand Down Expand Up @@ -388,30 +375,14 @@ export class ClassnamesGenerator {
// and return them in a string array to be parsed and converted into a template string that
// will be a part of the final generated file. See `FileContentGenerator` class.
private pseudoClasses = (): string[] => {
// Initialise a pseudoclasses variable with empty array value.
const pseudoClasses: string[] = [];
// prettier-ignore
const allVariants = [
'responsive', 'motion-safe', 'motion-reduce', 'first', 'last', 'odd', 'even', 'visited', 'checked',
'group-hover', 'group-focus', 'focus-within', 'hover', 'focus', 'focus-visible', 'active', 'disabled',
// Exhaustive pseudo-classess
'only', 'first-of-type', 'last-of-type', 'only-of-type', 'target', 'default', 'indeterminate',
'placeholder-shown', 'autofill', 'required', 'valid', 'invalid', 'in-range', 'out-of-range',
// New peer-*, selection & marker variants and before/after
'peer-hover', 'peer-checked', 'peer-focus', 'selection', 'marker', 'before', 'after'
];

// HACK: This block is just to make accessibility object align with other types object shape
const variantsConfig = Object.entries(
_.merge(this._configParser.getVariants(), {
screenReaders: this._configParser.getVariants().accessibility,
}),
);
// Initialise a pseudoClasses array with base values.
const pseudoClasses: string[] = ['peer', 'group'];
if (this._darkMode === 'class') pseudoClasses.push('dark');

// Get the variants from config
const variants = this._configParser.getVariants();

// For every key-value pair in the variants section in tailwind config...
// eslint-disable-next-line prefer-const
for (let [regularClassGroupKey, pseudoClassesVariantsForKey] of variantsConfig) {
// Find all matching names from the generated regular classes with the key of the variants config
for (const regularClassGroupKey of regularClassGroupKeys) {
Object.keys(this._generatedRegularClassnames).map(key => {
// If the current key is found to be a member of the generated regular classes group...
if (
Expand All @@ -423,86 +394,22 @@ export class ClassnamesGenerator {
`${key}.${regularClassGroupKey}`,
) as string[];

// If JIT compiler mode is enabled...
if (this.isJitModeEnabled()) {
// Duplicate classnames with an important (!) prefix
const generatedClassGroupWithImportantPrefix = generatedClassGroup.map(
cls => '!' + cls,
);

// Append the classnames with important prefix to the regular classnames
generatedClassGroup = generatedClassGroup.concat(
generatedClassGroupWithImportantPrefix,
);

// Append the classnames with important prefix to the pseudo classes array
generatedClassGroupWithImportantPrefix.map(cls => pseudoClasses.push(cls));
}
// Duplicate classnames with an important (!) prefix
const generatedClassGroupWithImportantPrefix = generatedClassGroup.map(cls => '!' + cls);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it would improve or worsen perf, but some of the things this lib is doing can be accomplished using template string types:

export type TClassesWithModifiers = `!${TClasses}` | TClasses

This could potentially be used to implement a lot of things in the lib with less code.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I think this will make file size much smaller
Would you like to make a PR with this change to be merged into master for v2 releases?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a shot at it 👍

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm already using Tailwind 3 myself, so I thought maybe I should do the changes on top of this PR. Do you think that would be a good idea?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I've tested this approach on pseudoclasses, and it was extremely slow
But it was OK when applying this approach to important modifiers only

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yes, it makes more sense to do the changes on top of this PR. Thank you!

// Append the classnames with important prefix to the regular classnames
generatedClassGroup = generatedClassGroup.concat(generatedClassGroupWithImportantPrefix);
// Append the classnames with important prefix to the pseudo classes array
generatedClassGroupWithImportantPrefix.map(cls => pseudoClasses.push(cls));

// For every member of the found regular classes group...
generatedClassGroup.map(classname => {
const isDarkModeEnabled = this._darkMode !== false;

// If JIT compiler mode is enabled...
if (this.isJitModeEnabled()) {
// Enable all variants
pseudoClassesVariantsForKey = allVariants;
// Add 'peer' utility classname. used with peer-* classnames
pseudoClasses.push('peer');
}

// Generate the classname of each variant...
pseudoClassesVariantsForKey.map(variant => {
if (variant === 'responsive') {
// Get the breakpoints from config
const [breakpoints] = this._configParser.getThemeProperty('screens');

// Create the classname for each breakpoint
breakpoints.map((breakpointVariant: string) => {
// Push the created classes to the pseudoClasses array
pseudoClasses.push(
breakpointVariant + this._separator + this._prefix + classname,
);

// Add stackable dark and responsive pseudoclasses if the key has both variants
if (pseudoClassesVariantsForKey.includes('dark') && isDarkModeEnabled) {
pseudoClasses.push(
breakpointVariant +
this._separator +
'dark' +
this._separator +
this._prefix +
classname,
);
}
});
}
// Otherwise if the variant is 'dark'
else if (variant === 'dark') {
// If the dark mode is enabled...
if (isDarkModeEnabled) {
// Add the 'dark' prefix to the classname to create its pseudoclass
pseudoClasses.push(variant + this._separator + this._prefix + classname);
}
// Otherwise, do nothing.
}
// Otherwise...
else {
// Append the variant to the classname and push to the pseudoClasses array.
pseudoClasses.push(variant + this._separator + this._prefix + classname);

// Add 'group' class if a the variant is group-hover, group-focus etc.
if (variant.startsWith('group') && !pseudoClasses.includes('group'))
pseudoClasses.push('group');

// Add 'dark' class if dark mode stategy is set to "class"
if (this._darkMode === 'class' && !pseudoClasses.includes('dark'))
pseudoClasses.push('dark');
}
variants.map(variant => {
// Append the variant to the classname and push to the pseudoClasses array.
pseudoClasses.push(variant + this._separator + this._prefix + classname);
});
});
}
// Otherwise, skip and do nothing
});
}

Expand Down Expand Up @@ -533,9 +440,9 @@ export class ClassnamesGenerator {
if (typeof colorValue === 'object' && colorValue !== null) {
// Loop over the deep objects and return the result for each key of the object.
return Object.keys(colorValue).flatMap(shade => {
if (utilName === 'border' && this.isJitModeEnabled()) {
if (utilName === 'border') {
return ['', 't', 'r', 'b', 'l'].map(
side => `${utilName}-${side}-${colorName}-${shade}`,
side => `${utilName}-${side.length > 0 ? side + '-' : ''}${colorName}-${shade}`,
);
} else {
return `${utilName}-${colorName}-${shade}`;
Expand All @@ -545,7 +452,7 @@ export class ClassnamesGenerator {
// Otherwise...
else {
// Return the result of merging the utility name with color value
if (utilName === 'border' && this.isJitModeEnabled()) {
if (utilName === 'border') {
return ['', 't', 'r', 'b', 'l'].map(
side => `${utilName}-${side.length > 0 ? side + '-' : ''}${colorName}`,
);
Expand All @@ -555,17 +462,12 @@ export class ClassnamesGenerator {
}
});

// Add the opacities short hand suffix `/{opacity}`: "bg-red-100/50"
const classnamesWithColorsAndOpacitySuffix = Object.keys(
this._configParser.getTheme().opacity,
).flatMap(op => classnamesWithColors.map(cls => cls + '/' + op));
// // Add the opacities short hand suffix `/{opacity}`: "bg-red-100/50"
// const classnamesWithColorsAndOpacitySuffix = Object.keys(
// this._configParser.getTheme().opacity,
// ).flatMap(op => classnamesWithColors.map(cls => cls + '/' + op));

// Return the result classnames based on whether JIT mode is enabled or not
if (this.isJitModeEnabled()) {
return classnamesWithColors.concat(classnamesWithColorsAndOpacitySuffix);
} else {
return classnamesWithColors;
}
return classnamesWithColors;
};

private getGeneratedClassesWithOpacities = (): ClassesWithOpacities => {
Expand Down
Loading