🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

twirlwind

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

twirlwind - npm Package Compare versions

Comparing version
0.1.0
to
0.2.0
+16
-29
dist/index.d.mts

@@ -7,25 +7,17 @@ //#region src/types.d.ts

type StyleInput = string | StyleObject | CSSStyleDeclaration | Iterable<[string, StylePrimitive]>;
type ConversionMode = 'pretty' | 'lossless' | 'strict';
type SortMode = 'input' | 'tailwind' | 'grouped';
type CompressionMode = 'none' | 'safe' | 'aggressive';
type ColorMatchMode = 'exact' | 'nearest' | 'none';
type NumericMultiplierMode = 'all' | 'integer' | 'never';
type TwirlwindTheme = {
type Theme = {
spacing?: Record<string, string>;
colors?: Record<string, string>;
};
type StyleToTailwindOptions = {
mode?: ConversionMode;
tailwindVersion?: '4';
theme?: TwirlwindTheme;
type Options = {
theme?: Theme;
allowArbitraryValues?: boolean;
allowArbitraryProperties?: boolean;
preferThemeTokens?: boolean;
compression?: CompressionMode;
sort?: SortMode;
compression?: 'none' | 'safe' | 'aggressive';
sort?: 'input' | 'tailwind' | 'grouped';
important?: boolean;
colorMatch?: ColorMatchMode;
numericMultipliers?: NumericMultiplierMode;
colorMatch?: 'exact' | 'nearest' | 'none';
numericMultipliers?: 'all' | 'integer' | 'never';
};
type CssDeclaration = {
type Declaration = {
property: string;

@@ -36,11 +28,7 @@ value: string;

};
type ConvertedDeclaration = CssDeclaration & {
type ConvertedDeclaration = Declaration & {
className: string;
kind: 'exact' | 'arbitrary';
};
type ConversionWarning = {
declaration: CssDeclaration;
message: string;
};
type StyleToTailwindResult = {
type Result = {
className: string;

@@ -50,12 +38,11 @@ classes: string[];

arbitrary: ConvertedDeclaration[];
unmatched: CssDeclaration[];
warnings: ConversionWarning[];
unmatched: Declaration[];
};
//#endregion
//#region src/index.d.ts
declare function styleToTailwind(input: StyleInput, options?: StyleToTailwindOptions): StyleToTailwindResult;
declare function styleToClassName(input: StyleInput, options?: StyleToTailwindOptions): string;
declare function styleToClasses(input: StyleInput, options?: StyleToTailwindOptions): string[];
declare function cssTextToTailwind(cssText: string, options?: StyleToTailwindOptions): StyleToTailwindResult;
declare function twirl(input: StyleInput, options?: Options): string;
declare namespace twirl {
var convert: (input: StyleInput, options?: Options) => Result;
}
//#endregion
export { type ConvertedDeclaration, type CssDeclaration, type StyleInput, type StyleObject, type StylePrimitive, type StyleToTailwindOptions, type StyleToTailwindResult, type TwirlwindTheme, cssTextToTailwind, styleToClassName, styleToClasses, styleToTailwind };
export { type ConvertedDeclaration, type Declaration, type Options, type Result, type StyleInput, type StyleObject, type StylePrimitive, type Theme, twirl };
{
"name": "twirlwind",
"version": "0.1.0",
"version": "0.2.0",
"description": "Tailwind v4-first CSS style object to utility class serializer with lossless arbitrary-property fallback.",

@@ -5,0 +5,0 @@ "keywords": [

+49
-124

@@ -13,83 +13,43 @@ # Twirlwind

## Quick start
## Usage
```ts
import { styleToClassName } from 'twirlwind'
import { twirl } from 'twirlwind'
styleToClassName({
display: 'flex',
justifyContent: 'center',
padding: '16px 8px',
backgroundColor: 'oklch(62.3% 0.214 259.815)'
})
// → "flex py-4 px-2 justify-center bg-blue-500"
twirl({ display: 'flex', padding: '16px 8px', color: '#ef4444' })
// → "flex py-4 px-2 text-red-500"
```
## API
### Inputs
### `styleToTailwind(input, options?)`
`twirl()` accepts any of these and returns a class string:
Full conversion result with metadata.
```ts
import { styleToTailwind } from 'twirlwind'
// Style object
twirl({ backgroundColor: 'white', fontSize: '16px' })
const result = styleToTailwind({ display: 'flex', width: '37px' })
// CSS string
twirl('display: flex; padding: 16px')
result.className // "flex w-[37px]"
result.classes // ["flex", "w-[37px]"]
result.exact // ConvertedDeclaration[] — exact utility matches
result.arbitrary // ConvertedDeclaration[] — arbitrary value/property fallbacks
result.unmatched // CssDeclaration[] — declarations that couldn't be converted
result.warnings // ConversionWarning[]
```
// CSSStyleDeclaration (browser)
twirl(element.style)
### `styleToClassName(input, options?)`
Returns just the class string.
```ts
styleToClassName({ padding: '16px', color: 'white' })
// → "p-4 text-white"
// Computed styles
twirl(getComputedStyle(element))
```
### `styleToClasses(input, options?)`
### Detailed result
Returns an array of class strings.
Use `twirl.convert()` when you need metadata:
```ts
styleToClasses({ margin: '8px 16px' })
// → ["my-2", "mx-4"]
```
const result = twirl.convert({ display: 'flex', width: '37px' })
### `cssTextToTailwind(cssText, options?)`
Parses a CSS declaration string.
```ts
cssTextToTailwind('display: flex; gap: 16px; padding: 8px')
// → { className: "flex p-2 gap-4", ... }
result.className // "flex w-[37px]"
result.classes // ["flex", "w-[37px]"]
result.exact // exact utility matches
result.arbitrary // arbitrary value/property fallbacks
result.unmatched // declarations that couldn't be converted
```
## Input formats
```ts
// Style object (camelCase or kebab-case)
styleToClassName({ backgroundColor: 'white', 'font-size': '16px' })
// CSS declaration string
styleToClassName('display: flex; padding: 16px')
// CSSStyleDeclaration (browser)
styleToClassName(element.style)
// Iterable of [property, value] pairs
styleToClassName(
new Map([
['display', 'flex'],
['padding', '16px']
])
)
```
## Features

@@ -99,11 +59,9 @@

Matches colors across formats to Tailwind's palette — OKLCH (v4), hex (v3), `rgb()`, keywords, and opacity modifiers.
Matches across formats — OKLCH, hex, `rgb()`, keywords, opacity modifiers.
```ts
styleToClassName({ color: '#ef4444' }) // "text-red-500"
styleToClassName({ color: 'rgb(59 130 246)' }) // "text-blue-500"
styleToClassName({ color: 'oklch(62.3% 0.214 259.815)' }) // "text-blue-500"
styleToClassName({ color: 'oklch(62.3% 0.214 259.815 / 50%)' }) // "text-blue-500/50"
styleToClassName({ color: 'inherit' }) // "text-inherit"
styleToClassName({ color: 'currentColor' }) // "text-current"
twirl({ color: '#ef4444' }) // "text-red-500"
twirl({ color: 'rgb(59 130 246)' }) // "text-blue-500"
twirl({ color: 'oklch(62.3% 0.214 259.815 / 50%)' }) // "text-blue-500/50"
twirl({ color: 'currentColor' }) // "text-current"
```

@@ -116,25 +74,15 @@

```ts
styleToClassName({ border: '2px solid #ef4444' })
// → "border-2 border-red-500 border-solid"
styleToClassName({ font: 'bold 16px/1.5 sans-serif' })
// → "font-bold text-base leading-normal font-sans"
styleToClassName({ background: 'white center no-repeat' })
// → "bg-white bg-center bg-no-repeat"
styleToClassName({ transition: 'all 200ms ease-in' })
// → "transition-all duration-200 ease-in"
twirl({ border: '2px solid #ef4444' }) // "border-2 border-red-500 border-solid"
twirl({ font: 'bold 16px/1.5 sans-serif' }) // "font-bold text-base leading-normal font-sans"
twirl({ background: 'white center no-repeat' }) // "bg-white bg-center bg-no-repeat"
```
### Multi-value transforms and filters
### Multi-value parsing
Compound `transform` and `filter` declarations decompose into individual utility classes.
Compound `transform` and `filter` declarations decompose into individual classes.
```ts
styleToClassName({ transform: 'translateX(8px) rotate(45deg)' })
// → "rotate-45 translate-x-2"
styleToClassName({ filter: 'blur(8px) brightness(0.75)' })
// → "blur brightness-75"
twirl({ transform: 'translateX(8px) rotate(45deg)' }) // "rotate-45 translate-x-2"
twirl({ filter: 'blur(8px) brightness(0.75)' }) // "blur brightness-75"
twirl({ scrollSnapType: 'x mandatory' }) // "snap-x snap-mandatory"
```

@@ -144,10 +92,10 @@

Expanded longhands compress to shorthand utilities when values match.
Expanded longhands compress to shorthand utilities.
```ts
styleToClassName({ margin: '8px' }) // "m-2" (not "mt-2 mr-2 mb-2 ml-2")
styleToClassName({ inset: '0' }) // "inset-0"
styleToClassName({ padding: '8px 16px' }) // "py-2 px-4"
styleToClassName({ borderRadius: '8px' }) // "rounded-lg"
styleToClassName({ gap: '12px 12px' }) // "gap-3"
twirl({ margin: '8px' }) // "m-2"
twirl({ inset: '0' }) // "inset-0"
twirl({ padding: '8px 16px' }) // "py-2 px-4"
twirl({ borderRadius: '8px' }) // "rounded-lg"
twirl({ gap: '12px 12px' }) // "gap-3"
```

@@ -157,6 +105,6 @@

Nested objects map to Tailwind variants — pseudo-classes, media queries, and container queries.
Nested objects map to Tailwind variants.
```ts
styleToClassName({
twirl({
color: 'white',

@@ -171,19 +119,9 @@ ':hover': { color: '#3b82f6' },

### Scroll snap decomposition
```ts
styleToClassName({ scrollSnapType: 'x mandatory' })
// → "snap-x snap-mandatory"
```
### Arbitrary fallback
Every CSS property produces valid output. Unknown properties use `[property:value]` syntax.
Every CSS property produces valid output.
```ts
styleToClassName({ scrollTimelineName: '--main' })
// → "[scroll-timeline-name:--main]"
styleToClassName({ width: '37px' })
// → "w-[37px]"
twirl({ scrollTimelineName: '--main' }) // "[scroll-timeline-name:--main]"
twirl({ width: '37px' }) // "w-[37px]"
```

@@ -194,22 +132,9 @@

```ts
styleToTailwind(input, {
// Allow arbitrary value utilities like w-[37px]
twirl(input, {
allowArbitraryValues: true, // default: true
// Allow arbitrary property fallbacks like [scroll-timeline-name:--x]
allowArbitraryProperties: true, // default: true
// Compress matching longhands to shorthands
compression: 'safe', // "none" | "safe" | "aggressive"
// Sort output classes
sort: 'grouped', // "input" | "tailwind" | "grouped"
// Color matching strategy
colorMatch: 'exact', // "exact" | "nearest" | "none"
// Spacing token multiplier mode
numericMultipliers: 'integer', // "all" | "integer" | "never"
// Custom theme colors/spacing
theme: {

@@ -225,5 +150,5 @@ colors: { brand: '#ff6600' },

1. **Normalize** — camelCase → kebab-case, numeric → px, vendor prefixes, `!important`
2. **Expand shorthands** — `margin`, `border`, `font`, `background`, `transition`, `overflow`, `gap`, etc.
2. **Expand** — `margin`, `border`, `font`, `background`, `transition`, `overflow`, `gap`, etc.
3. **Convert** — exact utility → value alias → spacing token → color match → arbitrary value → arbitrary property
4. **Compress** — merge matching longhands back to axis/all shorthand utilities
4. **Compress** — merge longhands back to shorthand utilities
5. **Sort** — deterministic output ordering

@@ -230,0 +155,0 @@

Sorry, the diff of this file is too big to display