New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More ā†’
Socket
Sign inDemoInstall
Socket

tailwindcss-theme-variants

Package Overview
Dependencies
Maintainers
1
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tailwindcss-theme-variants - npm Package Compare versions

Comparing version 0.0.5 to 0.1.0

122

dist/src/index.js

@@ -7,16 +7,9 @@ "use strict";

const plugin_1 = __importDefault(require("tailwindcss/plugin"));
const nameVariant = (renamedTheme, responsive, variantName) => {
const nameVariant = (renamedTheme, variantName) => {
if (variantName === "") {
if (responsive === "") {
return renamedTheme;
}
return `${renamedTheme}:${responsive}`;
return renamedTheme;
}
if (responsive === "") {
return `${renamedTheme}:${variantName}`;
}
return `${renamedTheme}:${responsive}:${variantName}`;
return `${renamedTheme}:${variantName}`;
};
const thisPlugin = plugin_1.default.withOptions(({ themes, baseSelector = ":root", fallback = false, rename = (themeName) => themeName, variants = {}, }) => ({ addVariant, e, postcss, theme, }) => {
var _a;
const thisPlugin = plugin_1.default.withOptions(({ themes, baseSelector = ":root", fallback = false, rename = (themeName) => themeName, variants = {}, }) => ({ addVariant, e, postcss, }) => {
const allThemes = Object.entries(themes);

@@ -26,3 +19,2 @@ if (allThemes.length === 0) {

}
const allScreens = Object.entries((_a = theme("screens", {})) !== null && _a !== void 0 ? _a : {});
if (fallback === true) {

@@ -39,68 +31,48 @@ fallback = allThemes[0][0]; // eslint-disable-line prefer-destructuring,no-param-reassign

}
// Don't even try to add responsive variants if there are no screens, because they won't create any CSS if used
(allScreens.length === 0 ? [false] : [false, true]).forEach((isResponsive) => {
// Use a dummy screen to reduce duplicating logic between the responsive and not responsive versions
const screens = isResponsive ? allScreens : [["", undefined]];
// Similarly, use a dummy default variant first
Object.entries({ "": (selector) => selector, ...variants }).forEach(([variantName, variantFunction]) => {
allThemes.forEach(([themeName, { mediaQuery, selector }]) => {
const nameThisVariant = (responsive) => nameVariant(rename(themeName), responsive, variantName);
addVariant(nameThisVariant(isResponsive ? "responsive" : ""), ({ container, separator }) => {
const nameSelector = (namedVariant, ruleSelector) => `${variantFunction(`.${e(`${namedVariant.replace(/:/g, separator)}${separator}`)}${ruleSelector.slice(1)}`)}`;
const originalContainer = container.clone();
// Remove the pre-existing (provided by Tailwind's core) CSS so that we don't duplicate it
container.removeAll();
screens.forEach(([screen, minWidth]) => {
// Tool to nest the utilities inside the screen media query if it exists
const nestIfNecessaryAndAdd = (source, destination) => {
if (minWidth) {
const screenAtRule = postcss.atRule({ name: "media", params: `(min-width: ${minWidth})` });
screenAtRule.append(source);
destination.append(screenAtRule);
}
else {
destination.append(source);
}
};
if (themeName === fallback) {
const containerFallBack = originalContainer.clone();
containerFallBack.walkRules((rule) => {
const namedSelector = nameSelector(nameThisVariant(""), rule.selector);
const inactiveThemes = selector ? allThemes.map(([_themeName, { selector: otherSelector }]) => `:not(${otherSelector})`) : [];
rule.selector = `${baseSelector}${inactiveThemes.join("")} ${namedSelector}`;
});
nestIfNecessaryAndAdd(containerFallBack, container);
// Use a dummy default variant first
Object.entries({ "": (selector) => selector, ...variants }).forEach(([variantName, variantFunction]) => {
allThemes.forEach(([themeName, { mediaQuery, selector }]) => {
const namedVariant = nameVariant(rename(themeName), variantName);
addVariant(namedVariant, ({ container, separator }) => {
const nameSelector = (ruleSelector) => `${variantFunction(`.${e(`${namedVariant.replace(/:/g, separator)}${separator}`)}${ruleSelector.slice(1)}`)}`;
const originalContainer = container.clone();
// Remove the pre-existing (provided by Tailwind's core) CSS so that we don't duplicate it
container.removeAll();
if (themeName === fallback) {
const containerFallBack = originalContainer.clone();
containerFallBack.walkRules((rule) => {
const namedSelector = nameSelector(rule.selector);
const inactiveThemes = selector ? allThemes.map(([_themeName, { selector: otherSelector }]) => ((selector === otherSelector) ? "" : `:not(${otherSelector})`)) : [];
rule.selector = `${baseSelector}${inactiveThemes.join("")} ${namedSelector}`;
});
container.append(containerFallBack);
}
if (mediaQuery) {
const queryAtRule = postcss.parse(mediaQuery).first; // eslint-disable-line @typescript-eslint/no-explicit-any
// Nest the utilities inside the given media query
const queryContainer = originalContainer.clone();
queryContainer.walkRules((rule) => {
const namedSelector = nameSelector(rule.selector);
if (fallback && baseSelector !== "") {
const inactiveThemes = selector ? allThemes.map(([_themeName, { selector: otherSelector }]) => ((selector === otherSelector) ? "" : `:not(${otherSelector})`)) : [];
rule.selector = `${baseSelector}${inactiveThemes.join("")} ${namedSelector}`;
}
if (mediaQuery) {
const queryAtRule = postcss.parse(mediaQuery).first; // eslint-disable-line @typescript-eslint/no-explicit-any
// Nest the utilities inside the given media query
const queryContainer = originalContainer.clone();
queryContainer.walkRules((rule) => {
const namedSelector = nameSelector(nameThisVariant(screen), rule.selector);
// Make sure specifity is high enough for media-query-backed themes to overcome their fallbackconst namedSelector = nameSelector(e, nameThisVariant(""), separator, rule.selector, variantFunction);
if (fallback && baseSelector !== "") {
const inactiveThemes = selector ? allThemes.map(([_themeName, { selector: otherSelector }]) => `:not(${otherSelector})`) : [];
rule.selector = `${baseSelector}${inactiveThemes.join("")} ${namedSelector}`;
}
else {
rule.selector = namedSelector;
}
});
if (queryContainer.nodes) {
queryAtRule.append(queryContainer.nodes);
}
nestIfNecessaryAndAdd(queryAtRule, container);
else {
rule.selector = namedSelector;
}
if (selector) {
const normalScreenContainer = originalContainer.clone();
normalScreenContainer.walkRules((rule) => {
const namedSelector = nameSelector(nameThisVariant(screen), rule.selector);
const activator = `${baseSelector}${selector}`;
rule.selector = `${activator} ${namedSelector}`;
});
// Nest the utilities inside the screen media query if it exists
nestIfNecessaryAndAdd(normalScreenContainer, container);
}
});
});
if (queryContainer.nodes) {
queryAtRule.append(queryContainer.nodes);
}
container.append(queryAtRule);
}
if (selector) {
const normalScreenContainer = originalContainer.clone();
normalScreenContainer.walkRules((rule) => {
const namedSelector = nameSelector(rule.selector);
const activator = `${baseSelector}${selector}`;
rule.selector = `${activator} ${namedSelector}`;
});
container.append(normalScreenContainer);
}
});

@@ -107,0 +79,0 @@ });

{
"name": "tailwindcss-theme-variants",
"version": "0.0.5",
"version": "0.1.0",
"description": "JavaScript- or media-query-based theme variants with fallback for Tailwind CSS",

@@ -34,2 +34,3 @@ "keywords": [

"devDependencies": {
"@danestves/tailwindcss-darkmode": "^1.1.5",
"@types/assert": "^1.4.7",

@@ -49,2 +50,4 @@ "@types/lodash": "^4.14.153",

"source-map": "^0.7.3",
"tailwindcss-dark-mode": "^1.1.4",
"tailwindcss-theme-variants": "^0.0.5",
"ts-node": "^8.10.2",

@@ -51,0 +54,0 @@ "typescript": "^3.9.3"

@@ -155,9 +155,13 @@ This Tailwind CSS plugin registers variants for theming without needing custom properties. It has support for responsive variants, extra stacked variants, media queries, and falling back to a particular theme when none matches.

- `fallback` (default `false`): chooses a theme to fall back to when none of the media queries or selectors are active. You can either manually select a theme by giving a string like `"
- `fallback` (default `false`): chooses a theme to fall back to when none of the media queries or selectors are active. You can either manually select a theme by giving a string like `"solarized-dark"` or implicitly select the first one listed in `themes` by giving `true`.
- `rename` (default is a function that gives back exactly what was passed as in `rename("red") === "red"`, i.e. no renaming actually takes place): a function for renaming every theme, which changes the name of the generated variants. The most usual way to use this is to add a prefix or suffix to reduce duplication. For example, you can ``rename: (themeName) => `${themeName}-theme` `` to make `themes: { red, green, blue }` have corresponding variants `red-theme`, `green-theme`, and `blue-theme`. This also means that their generated class names are like `red-theme\:bg-green-300` instead of just `red\:bg-green-300`.
- `rename` (default is a function that gives back exactly what was passed, as in `rename("red") === "red"`, i.e. no renaming actually takes place): a function for renaming every theme, which changes the name of the generated variants.
- `variants` (default is nothing): an object mapping the name of extra variants to a function that explains what has to be done to the selector for it to be active. For example, the importable `even` variant takes a `selector` and returns `` `${selector}:nth-child(even)` ``. The importable `groupHover` (which you are recommended to name `"group-hover"` for consistency) variant returns `` `.group:hover ${selector}` ``
The most usual way to use this is to add a prefix or suffix to reduce duplication. For example, you can ``rename: (themeName) => `${themeName}-theme` `` to make `themes: { red, green, blue }` have corresponding variants `red-theme`, `green-theme`, and `blue-theme`. This also means that their generated class names are like `red-theme\:bg-green-300` instead of just `red\:bg-green-300`.
- `variants` (default is nothing): an object mapping the name of extra variants to a function that explains what has to be done to the selector for it to be active.
For example, the importable `even` variant takes a `selector` and returns `` `${selector}:nth-child(even)` ``. The importable `groupHover` (which you are recommended to name `"group-hover"` for consistency) variant returns `` `.group:hover ${selector}` ``
## Examples

@@ -193,4 +197,82 @@ šŸ’” At the time of writing, this documentation is a work in progress. For all examples, where I've done my best to stretch the plugin to its limits (especially towards the end of the file), see the test suite in [`tests/index.ts`](https://github.com/SirNavith/tailwindcss-theme-variants/blob/master/tests/index.ts#L46).

<table>
<thead>
<tr>
<th></th>
<th><a href="https://tailwindcss.com/docs/breakpoints/#dark-mode">Native screens</a></th>
<th><a href="https://github.com/ChanceArthur/tailwindcss-dark-mode">tailwindcss-dark-mode</a></th>
<th><a href="https://github.com/danestves/tailwindcss-darkmode">tailwindcss-darkmode</a></th>
<th><a href="https://github.com/javifm86/tailwindcss-prefers-dark-mode">tailwindcss-prefers-dark-mode</a></th>
<th><a href="https://github.com/crswll/tailwindcss-theme-swapper">tailwindcss-theme-swapper</a></th>
<th><a href="https://github.com/SirNavith/tailwindcss-theme-variants">tailwindcss-theme-variants</a></th>
<th><a href="https://github.com/innocenzi/tailwindcss-theming">tailwindcss-theming</a></th>
</tr>
</thead>
<tbody>
<tr>
<th>Controllable with selectors (classes or data attributes)</th>
<td>āŒ</td>
<td>āœ…</td>
<td>āœ…</td>
<td>āœ…</td>
<td>āœ…</td>
<td>āœ…</td>
<td>āœ…</td>
</tr>
<tr>
<th>Responsive</th>
<td>āŒ</td>
<td>āœ…</td>
<td>āœ…</td>
<td></td>
<td></td>
<td>āœ…</td>
<td></td>
</tr>
<tr>
<th>Requires <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*">custom properties</a></th>
<td>āŒ</td>
<td>āŒ</td>
<td>āŒ</td>
<td>āŒ</td>
<td>āœ…</td>
<td>āŒ</td>
<td>āœ…</td>
</tr>
<tr>
<th>Supports <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme"><code>prefers-color-scheme: dark</code></a></th>
<td>āœ…</td>
<td>With JavaScript</td>
<td>āŒ</td>
<td>āœ…</td>
<td>āœ…</td>
<td>āœ…</td>
<td></td>
</tr>
<tr>
<th>Supports <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme"><code>prefers-color-scheme: light</code></a></th>
<td>āœ…</td>
<td>With JavaScript</td>
<td>āŒ</td>
<td>āŒ</td>
<td>āœ…</td>
<td>āœ…</td>
<td></td>
</tr>
<tr>
<th>Other thing</th>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
---
*Repository preview image generated with [GitHub Social Preview](https://social-preview.pqt.dev/)*
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with āš”ļø by Socket Inc