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.6.0 to 0.7.0

28

dist/src/index.js

@@ -26,5 +26,5 @@ "use strict";

const thisPlugin = plugin_1.default.withOptions(({ themes, baseSelector, fallback = false, variants = {}, }) => ({ addVariant, e, postcss }) => {
const allThemes = Object.entries(themes);
const allThemes = Object.entries(themes !== null && themes !== void 0 ? themes : {});
if (allThemes.length === 0) {
console.warn("tailwindcss-theme-variants: no themes were given in this plugin's configuration under the `themes` key, so no variants can be generated");
console.warn("tailwindcss-theme-variants: no themes were given in this plugin's configuration under the `themes` key, so no variants can be generated. this can be fixed by specifying a theme like `light: { selector: '.light' }` in `themes` of this plugin's configuration. see the README for more information");
}

@@ -34,10 +34,3 @@ if (fallback === true) {

}
if (fallback && allThemes.length === 1) {
if (baseSelector === "") {
console.warn(`tailwindcss-theme-variants: the \`${fallback}\` theme was selected for fallback, but it is the only one available, so it will always be active, which is unusual. this can be "fixed" by adding another theme to \`themes\` in this plugin's configuration, disabling \`fallback\` in this plugin's configuration, or setting a \`baseSelector\` in this plugin's configuration (there is no way to silence this warning)`);
}
else {
console.warn(`tailwindcss-theme-variants: the \`${fallback}\` theme was selected for fallback, but it is the only one available, so it will always be active as long as \`${baseSelector}\` exists. this is an unusual pattern, so if you meant not to do this, it can be "fixed" by adding another theme to \`themes\` in this plugin's configuration, disabling \`fallback\` in this plugin's configuration, or changing \`baseSelector\` to \`""\` and setting this theme's \`selector\` to the current value of \`baseSelector\` (there is no way to silence this warning)`);
}
}
const usesAnySelectors = allThemes.some(([_name, { selector }]) => selector);
if (baseSelector === undefined) {

@@ -47,4 +40,17 @@ // Implicitly disable `baseSelector` on behalf of the person only using media queries to set their themes

// eslint-disable-next-line no-param-reassign
baseSelector = allThemes.some(([_name, { selector }]) => selector) ? ":root" : "";
baseSelector = usesAnySelectors ? ":root" : "";
}
if (fallback) {
if (allThemes.length === 1) {
if (baseSelector === "") {
console.warn(`tailwindcss-theme-variants: the "${fallback}" theme was selected for fallback, but it is the only one available, so it will always be active, which is unusual. this can be "fixed" by adding another theme to \`themes\` in this plugin's configuration, disabling \`fallback\` in this plugin's configuration, or setting a \`baseSelector\` in this plugin's configuration (there is no way to silence this warning)`);
}
else {
console.warn(`tailwindcss-theme-variants: the "${fallback}" theme was selected for fallback, but it is the only one available, so it will always be active as long as \`${baseSelector}\` exists. this is an unusual pattern, so if you meant not to do this, it can be "fixed" by adding another theme to \`themes\` in this plugin's configuration, disabling \`fallback\` in this plugin's configuration, or changing \`baseSelector\` to \`""\` and setting this theme's \`selector\` to the current value of \`baseSelector\` (there is no way to silence this warning)`);
}
}
if (usesAnySelectors && baseSelector === "") {
console.warn(`tailwindcss-theme-variants: the "${fallback}" theme was selected for fallback, but you specified \`baseSelector: ""\` even though you use theme(s) that need a selector to activate, which will result in confusing and erroneous behavior of when themes activate. this can be fixed by disabling \`fallback\` in this plugin's configuration, or setting a \`baseSelector\` in this plugin's configuration (there is no way to silence this warning)`);
}
}
// Use a normal default variant first

@@ -51,0 +57,0 @@ Object.entries({ "": (selector) => selector, ...variants }).forEach(([variantName, variantFunction]) => {

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

@@ -27,7 +27,7 @@ "keywords": [

"test": "cross-env TS_NODE_FILES=true mocha --require ts-node/register 'tests/**/*.ts'",
"prepublish": "tsc"
"prepare": "tsc"
},
"dependencies": {
"postcss-selector-parser": "^6.0.2",
"tailwindcss": "^1.5.2"
"tailwindcss": "^1.6.2"
},

@@ -37,8 +37,9 @@ "devDependencies": {

"@types/assert": "^1.5.1",
"@types/lodash": "^4.14.158",
"@types/mocha": "^8.0.0",
"@typescript-eslint/eslint-plugin": "^3.7.0",
"@typescript-eslint/parser": "^3.7.0",
"@types/lodash": "^4.14.159",
"@types/mocha": "^8.0.1",
"@types/sinon": "^9.0.4",
"@typescript-eslint/eslint-plugin": "^3.8.0",
"@typescript-eslint/parser": "^3.8.0",
"cross-env": "^7.0.2",
"eslint": "^7.5.0",
"eslint": "^7.6.0",
"eslint-config-airbnb-base": "^14.2.0",

@@ -48,4 +49,5 @@ "eslint-plugin-import": "^2.22.0",

"lodash": "^4.17.19",
"mocha": "^8.0.1",
"mocha": "^8.1.1",
"postcss": "^7.0.32",
"sinon": "^9.0.2",
"source-map": "^0.7.3",

@@ -52,0 +54,0 @@ "ts-node": "^8.10.2",

@@ -1,7 +0,18 @@

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.
# 🌗 Tailwind CSS Theme Variants
**This Tailwind CSS plugin registers variants for theming beyond just light and dark modes *without needing custom properties***. It has support for
* Controlling themes with
* **Media queries**, like [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme), `print`, or anything you want
* **CSS selectors**, like classes and data attributes
* Or both at the same time!
* **Responsive** variants
* **Stacking** on extra **variants**, like `hover` so you can change a link's hover color depending on the theme
* **Falling back** to a certain theme when no other one could become active, like if a visitor's browser doesn't support JavaScript or the new `prefers-` media queries
* As many themes and groups of themes as you want: light theme, dark theme, red theme, blue theme—just bring your own definitions!
You are recommended to check out [the comparison table of all Tailwind CSS theming plugins below](#alternatives) before committing to one.
You are recommended to check out [the comparison table of all Tailwind CSS theming plugins below](#alternatives) before committing to any one. By the way, you might have noticed this plugin's documentation / `README` is *very* long—don't let that frighten you! I designed it to be *overdocumented* and as exhaustive as possible, and since most of that length is made up of long code snippets, it's shorter than it looks *and* you don't need to go through it all to do well!
# Installation
However, if you want your site to have a very large number of themes (say, 4 or more) or potentially infinite themes (such as could be configured by your users), then **this plugin is not for you**. You will probably be better off using a custom properties setup; refer back to [that table 👇](#alternatives).
# ⬇️ Installation
```sh

@@ -11,3 +22,3 @@ npm install --save-dev tailwindcss-theme-variants

# Basic usage
# 🛠 Basic usage

@@ -54,2 +65,6 @@ ## Using selectors to choose the active theme

/* If you're having trouble understanding,
imagine it said html instead of :root,
like in the example HTML below */
:root.light-theme .light\:bg-gray-900 {

@@ -64,4 +79,2 @@ background-color: #1A202C;

💡 You can choose more than just classes for your selectors. Other, good options include data attributes, like `[data-padding=compact]`. You *can* go as crazy as `.class[data-theme=light]:dir(rtl)`, for example, but at that point you need to be careful with specificity!
After also enabling `"light"` and `"dark"` variants for `textColor` and bringing in more colors from the [default palette](https://tailwindcss.com/docs/customizing-colors/#default-color-palette), we can implement a simple themed button in HTML like this:

@@ -77,4 +90,7 @@

This will result in dark text on a light background in the light theme, and light text on a dark background in the dark theme.
This will result in dark blue text on a light blue background in the light theme, and light blue text on a dark blue background in the dark theme.
💡 You can choose more than just classes for your selectors. Other, good options include data attributes, like `[data-padding=compact]`. You *can* go as crazy as `.class[data-theme=light]:dir(rtl)`, for example, but I think that's a bad idea!
## Using media queries to choose the active theme

@@ -133,5 +149,5 @@

💡 Keep the `variants` listed in the same order as in `themes` in this plugin's configuration for consistency and the most expected behavior. In `backgroundColor`'s `variants`, `light` came first, then `dark`, so we also list `light` before `dark` in `tailwindcssThemeVariants`'s `themes` option.
💡 Keep the `variants` listed in the same order as in `themes` in this plugin's configuration for consistency and the most expected behavior. In `backgroundColor`'s `variants`, `light` came first, then `dark`, so we also list `light` before `dark` in `tailwindcssThemeVariants`'s `themes` option. There is a planned feature that should make it unnecessary to remember this information, but until then, please follow this advice.
# Full configuration
# ⚙️ Full configuration

@@ -154,3 +170,2 @@ This plugin expects configuration of the form

variants?: {
// The name of the variant -> what has to be done to the selector for the variant to be active
[name: string]: (selector: string) => string;

@@ -167,9 +182,9 @@ };

- `mediaQuery`: a media query that has to be active for this theme to be active. For instance, if the `reduced-motion` theme has `mediaQuery` `"@media (prefers-reduced-motion: reduce)"` (importable as `prefersReducedMotion`), then the `reduced-motion` variant(s) will be active.
- `mediaQuery`: a media query that has to be active for this theme to be active. For instance, if the `reduced-motion` theme has `mediaQuery` `"@media (prefers-reduced-motion: reduce)"` (importable as `prefersReducedMotion`), then the `reduced-motion` variant(s) will be active whenever that media query matches: if the visitor's browser reports preferring reduced motion.
- `baseSelector` (default `""` (empty string) if you **only** use media queries to activate your themes, otherwise `":root"`): the selector that each theme's `selector` will be applied to to determine the active theme.
- `baseSelector` (default `":root"` if you use any selectors to activate themes, otherwise `""`): the selector that each theme's `selector` will be applied to to determine the active theme.
- `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`.
- `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`.
⚠️ Passing a string referring to a theme name is deprecated in favor of the `true`/`false` approach, and is planned to be removed.

@@ -228,2 +243,3 @@ - `variants` (default is nothing): an object mapping the name of a variant to a function that gives a selector for when that variant is active.

fallback: "light",
// Because light is the first theme in the list, `true` would've worked too
```

@@ -273,7 +289,9 @@

💡 Even though `background-color` has been used in every example, theme variants are available for *any* utility.
💡 Even though `background-color` has been used in every example so far, theme variants are available for *any* utility.
### Selectors
💡 `fallback` also works for selector-activated themes, which would be useful for visitors without JavaScript enabled—if that's how your themes are selected.
`fallback` also works for selector-activated themes.
💡 If you control themes on your site by adding / removing classes or attributes on the `html` or `body` element with JavaScript, then visitors without JavaScript enabled would see the `fallback` theme!
```js

@@ -341,10 +359,27 @@ themes: {

```js
themes: {
light: {
mediaQuery: prefersHighContrast /* "@media (prefers-contrast: high)" */,
const { tailwindcssThemeVariants, hover, prefersHighContrast } = require("tailwindcss-theme-variants");
module.exports = {
theme: {
// Your Tailwind CSS theme configuration
},
},
variants: {
"hover": hover /* (selector) => `${selector}:hover` */,
},
variants: {
backgroundColor: ["high-contrast"],
textColor: ["high-contrast", "high-contrast:hover"],
},
plugins: [
tailwindcssThemeVariants({
themes: {
"high-contrast": {
mediaQuery: prefersHighContrast /* "@media (prefers-contrast: high)" */,
},
},
variants: {
"hover": hover /* (selector) => `${selector}:hover` */,
},
}),
],
};
```

@@ -364,6 +399,123 @@

#### Writing a custom variant function
You might need to write a variant function yourself if it's not `export`ed with this plugin. It's common to use the same styles on links and buttons when they are hovered over or focused on, so you may want to make things easier for yourself and reduce duplication by creating a `"hocus"` variant that activates for either `:hover` or `:focus`.
```js
const { tailwindcssThemeVariants, hover, odd } = require("tailwindcss-theme-variants");
module.exports = {
theme: {
// Your Tailwind CSS theme configuration
},
variants: {
opacity: [
"transparency-safe", "transparency-reduce",
"transparency-safe:hocus", "transparency-reduce:hocus",
],
},
plugins: [
tailwindcssThemeVariants({
themes: {
"transparency-safe": {
mediaQuery: prefersAnyTransparency /* "@media (prefers-reduced-transparency: no-preference)" */,
},
"transparency-reduce": {
mediaQuery: prefersReducedTransparency /* "@media (prefers-reduced-transparency: reduce)" */,
},
},
fallback: true, // prefers-reduced-transparency is not supported in any browsers yet
variants: {
// The custom variant function, written by you
hocus: (selector) => `${selector}:hover, ${selector}:focus`,
},
}),
],
};
```
With this, let's try making an icon button that's overlaid on top of an image in HTML. This button is generally translucent and becomes more opaque on hover or focus, but now can be made more visually distinct for visitors who need it.
```html
<div>
<button
@click="..."
class="transparency-safe:opacity-25 transparency-safe:hocus:opacity-75
transparency-reduce:opacity-75 transparency-reduce:hocus:opacity-100">
<svg class="fill-current text-white bg-black positioning_classes...">
<!-- Path definitions... -->
</svg>
</button>
<img src="..." class="positioning_classes...">
</div>
```
Another—complex—example: suppose you want to zebra stripe your tables, matching the current theme, and change it on hover:
```js
const { tailwindcssThemeVariants, hover, odd } = require("tailwindcss-theme-variants");
module.exports = {
theme: {
// Your Tailwind CSS theme configuration
},
variants: {
backgroundColor: [
"no-accent", "green-accent", "orange-accent",
"no-accent:hover", "green-accent:hover", "orange-accent:hover",
"no-accent:odd", "green-accent:odd", "orange-accent:odd",
"no-accent:odd:hover", "green-accent:odd:hover", "orange-accent:odd:hover",
],
},
plugins: [
tailwindcssThemeVariants({
baseSelector: "table.themed",
themes: {
"no-accent": { selector: "" },
"green-accent": { selector: ".themed-green" },
"orange-accent": { selector: ".themed-orange" },
},
variants: {
hover /* (selector) => `${selector}:hover` */,
odd /* (selector) => `${selector}:nth-child(odd)` */,
// The custom variant function, written by you
"odd:hover": (selector) => `${selector}:nth-child(odd):hover`,
// By the way, the ordering here doesn't matter
// (as opposed to the ordering of variants above)
},
}),
],
};
```
We can then implement the themeable table in HTML (Svelte) like so:
```html
<table class="themed themed-green"> <!-- Try changing themed-green to themed-orange or removing it -->
{#each people as person}
<tr class="no-accent:bg-white green-accent:bg-green-50 orange-accent:bg-orange-50
no-accent:hover:bg-gray-100 green-accent:hover:bg-green-100 orange-accent:hover:bg-orange-100
no-accent:odd:bg-gray-100 green-accent:odd:bg-green-100 orange-accent:orange-accent:odd:bg-orange-100
no-accent:odd:hover:bg-gray-200 green-accent:odd:hover:bg-green-200 orange-accent:odd:hover:bg-orange-100
">
<td>{person.firstName} {person.lastName}</td>
<td>{person.responsibility}</td>
<!-- ... -->
</tr>
{/each}
</table>
```
### Responsive variants
Responsive variants let you distinguish the current breakpoint per theme, letting you say `lg:green-theme:border-green-200` to have a `green-200` border only when the breakpoint is `lg` (or larger) and the `green-theme` is active, for instance.
Responsive variants let you distinguish the current breakpoint per theme, letting you say `lg:green-theme:border-green-200` to have a `green-200` border only when the breakpoint is `lg` (or larger) **and** the `green-theme` is active, for instance.
⚠️ Responsive variants are automatically generated whenever `responsive` is listed in the utility's `variants` in the Tailwind CSS configuration, **not** this plugin's configuration. Also, because this feature is provided by Tailwind CSS rather than this plugin, you have to specify `breakpoint:` **before** the `theme-name:` instead of after like in stacked variants).
⚠️ Responsive variants are automatically generated whenever `responsive` is listed in the utility's `variants` in the Tailwind CSS configuration, **not** this plugin's configuration. Also, because this feature is provided by Tailwind CSS rather than this plugin, you have to type `breakpoint:` **before** the `theme-name:` instead of after.

@@ -401,5 +553,5 @@ ```js

We could also make a group of themes for data density, like you can [configure in GMail](https://www.solveyourtech.com/switch-compact-view-gmail/):
```js

@@ -444,4 +596,6 @@ const { tailwindcssThemeVariants } = require("tailwindcss-theme-variants");

## Using both selectors and media queries
TODO
⚠️ If you use both selectors and media queries to activate themes, then **make sure that each specified class is specified as an *all or nothing* approach**. For instance, if you have `winter` and `summer` themes and want to add the `winter:bg-teal-100` class, then you also need to add the `summer:bg-orange-300` class. If you don't do this, then it will look like the values from an theme that's *supposed to be* inactive are "leaking" into the active theme.
Every feature previously discussed still works as you'd expect when you decide to also add selectors or media queries (whichever you weren't using before) to theme control. TODO
TODO: Show active theme tables for every example

@@ -479,5 +633,4 @@ Such as:

⚠️ If you are stacking variants on while using both selectors and media queries to activate themes, then **make sure that each stacked variant is specified as an *all or nothing* approach** on each element. For instance, if you have `normal-motion` and `reduced-motion` themes and want to add the `reduced-motion:hover:transition-none` class, then you also need to add the `normal-motion:hover:transition` class (or any [value of `transitionProperty`](https://tailwindcss.com/docs/transition-property/)). If you don't do this, then it will look like the values from a theme that's *supposed* to be inactive are "leaking" into the active theme.
⚠️ If you are stacking more variants while using both selectors and media queries to define when themes should be active, then TODO:
### Fallback

@@ -493,3 +646,3 @@ TODO

# Alternatives
TODO: theming plugin comparison table
Both because there are many theme plugins for Tailwind CSS, and because *what's the right way to do theming?* is a frequently asked question, we've compiled this table listing every theme plugin to compare their features and ultimately answer that question:

@@ -503,2 +656,3 @@ <table>

<th><a href="https://github.com/danestves/tailwindcss-darkmode">tailwindcss-darkmode</a></th>
<th><a href="https://github.com/estevanmaito/tailwindcss-multi-theme">tailwindcss-multi-theme</a></th>
<th><a href="https://github.com/javifm86/tailwindcss-prefers-dark-mode">tailwindcss-prefers-dark-mode</a></th>

@@ -512,2 +666,13 @@ <th><a href="https://github.com/crswll/tailwindcss-theme-swapper">tailwindcss-theme-swapper</a></th>

<tr>
<th>Classes can be <code>@apply</code>ed</th>
<td>🟡</td>
<td>🟡</td>
<td>🟡</td>
<td>🟡</td>
<td>🟡</td>
<td>✅</td>
<td>❌</td>
<td>✅</td>
</tr>
<tr>
<th>Controllable with selectors (classes or data attributes)</th>

@@ -518,2 +683,3 @@ <td>❌</td>

<td>✅</td>
<td>🟡</td>
<td>✅</td>

@@ -528,6 +694,7 @@ <td>✅</td>

<td>✅</td>
<td></td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>

@@ -540,2 +707,3 @@ <tr>

<td>❌</td>
<td>❌</td>
<td>✅</td>

@@ -548,8 +716,9 @@ <td>❌</td>

<td>✅</td>
<td>With JavaScript</td>
<td>❌</td>
<td>❌</td>
<td>❌</td>
<td>🟡</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>

@@ -559,5 +728,6 @@ <tr>

<td>✅</td>
<td>With JavaScript</td>
<td>❌</td>
<td>❌</td>
<td>❌</td>
<td>❌</td>
<td>✅</td>

@@ -567,17 +737,47 @@ <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>
# License and Contributing
### Legend
TODO: add `@variants` in CSS support? need to research. TODO: support for prefers-reduced-motion now that that's in tailwind core (or does that being available make it less useful for plugins to support?); so then how about prefers-reduced-transparency? arbitrary media queries?
**Classes can be `@apply`ed**:
[Native screens](https://tailwindcss.com/docs/breakpoints/#dark-mode) cannot have their generated classes `@apply`ed, but you can still nest an `@screen` directive within the element, like this:
```css
.btn-blue {
@apply bg-blue-100 text-blue-800;
/* Wouldn't have worked: @apply dark:bg-blue-700 dark:text-white */
@screen dark {
@apply bg-blue-700 text-white;
}
}
```
This may require nesting support, provided by [`postcss-nested`](https://github.com/postcss/postcss-nested) or [`postcss-nesting`](https://github.com/jonathantneal/postcss-nesting) (part of [`postcss-preset-env`](https://github.com/csstools/postcss-preset-env)).
As for theme plugins that are controlled with CSS selectors like classes and data attributes, you can nest whatever selector that may be (in this example `.theme-dark`) inside of the component's block, similarly to `@screen`:
```css
.btn-blue {
@apply bg-blue-100 text-blue-800;
/* Wouldn't have worked: @apply dark:bg-blue-700 dark:text-white */
.theme-dark & {
@apply bg-blue-700 text-white;
}
}
```
**Responsive**: While "inside" of a theme, it must be possible to "activate" classes / variants depending on the current breakpoint. For instance, it has to be possible to change `background-color` when **both** the screen is `sm` **and** the current theme is `dark`.
**Requires <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*">custom properties</a>**: Plugins who meet this description (have a ✅) usually have you write semantically named classes like `bg-primary`, `text-secondary`, etc, and swap out what `primary` and `secondary` mean with custom properties depending on the theme. This means that in IE11, themes cannot be controlled, and in some cases the default theme won't work at all without [preprocessing](https://github.com/postcss/postcss-custom-properties).
**Supports `prefer-color-scheme`**: Because [any media query can be detected in JavaScript](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia), any plugin marked as not supporting [`prefers-color-scheme`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) could "support" it by adding or removing classes or data attributes, like can be seen in the [`prefers-dark.js` script](https://github.com/ChanceArthur/tailwindcss-dark-mode/blob/master/prefers-dark.js) that some theme plugins recommend. This approach still comes with the caveats that
1. JavaScriptless visitors will not have the site's theme reflect their preferred one
2. It could still be possible for a flash of unthemed content to appear before the appropriate theme is activated
3. Your site will immediately jump between light and dark instead of smoothly transitioning with the rest of the screen on macOS
**[`tailwindcss-prefers-dark-mode`](https://github.com/javifm86/tailwindcss-prefers-dark-mode)**: cannot use selectors and media queries at the same time; it's one or the other, so you have to put a ✅ in one row and ❌ in the other.
# 📄 License and Contributing
MIT licensed. There are no contributing guidelines. Just do whatever you want to point out an issue or feature request and I'll work with it.

@@ -584,0 +784,0 @@

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