twirlwind 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +181 -0
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1316,6 +1316,25 @@ const exactUtilities = {
1316
1316
  contain: "overscroll-y-contain",
1317
1317
  none: "overscroll-y-none"
1318
1318
  },
1319
+ "scrollbar-width": {
1320
+ auto: "scrollbar-auto",
1321
+ thin: "scrollbar-thin",
1322
+ none: "scrollbar-none"
1323
+ },
1324
+ "scrollbar-gutter": {
1325
+ stable: "scrollbar-gutter-stable",
1326
+ "stable both-edges": "scrollbar-gutter-both-edges"
1327
+ },
1328
+ "mask-type": {
1329
+ alpha: "mask-type-alpha",
1330
+ luminance: "mask-type-luminance"
1331
+ },
1332
+ "mask-composite": {
1333
+ add: "mask-composite-add",
1334
+ subtract: "mask-composite-subtract",
1335
+ intersect: "mask-composite-intersect",
1336
+ exclude: "mask-composite-exclude"
1337
+ },
1319
1338
  "scroll-behavior": {
1320
1339
  auto: "scroll-auto",
1321
1340
  smooth: "scroll-smooth"
@@ -1419,6 +1438,24 @@ const exactUtilities = {
1419
1438
  "0 0": "origin-top-left",
1420
1439
  "0% 0%": "origin-top-left"
1421
1440
  },
1441
+ "perspective-origin": {
1442
+ center: "perspective-origin-center",
1443
+ top: "perspective-origin-top",
1444
+ "top right": "perspective-origin-top-right",
1445
+ right: "perspective-origin-right",
1446
+ "bottom right": "perspective-origin-bottom-right",
1447
+ bottom: "perspective-origin-bottom",
1448
+ "bottom left": "perspective-origin-bottom-left",
1449
+ left: "perspective-origin-left",
1450
+ "top left": "perspective-origin-top-left",
1451
+ "100% 0": "perspective-origin-top-right",
1452
+ "100% 0%": "perspective-origin-top-right",
1453
+ "100% 100%": "perspective-origin-bottom-right",
1454
+ "0 100%": "perspective-origin-bottom-left",
1455
+ "0% 100%": "perspective-origin-bottom-left",
1456
+ "0 0": "perspective-origin-top-left",
1457
+ "0% 0%": "perspective-origin-top-left"
1458
+ },
1422
1459
  "scroll-snap-align": {
1423
1460
  start: "snap-start",
1424
1461
  end: "snap-end",
@@ -1668,6 +1705,9 @@ const arbitraryPrefixes = {
1668
1705
  "flex-shrink": "shrink",
1669
1706
  "word-spacing": "word-spacing",
1670
1707
  hyphens: "hyphens",
1708
+ "scrollbar-color": "scrollbar-color",
1709
+ "font-feature-settings": "font-feature",
1710
+ "perspective-origin": "perspective-origin",
1671
1711
  "column-rule-color": "column-rule",
1672
1712
  "column-rule-width": "column-rule",
1673
1713
  "column-rule-style": "column-rule",
@@ -2214,6 +2254,15 @@ function convertDeclaration(declaration, options) {
2214
2254
  if (Array.isArray(filterResult)) return filterResult.map((cls) => converted(declaration, cls, "exact"));
2215
2255
  return converted(declaration, filterResult, "exact");
2216
2256
  }
2257
+ const shadowClass = convertShadow(declaration);
2258
+ if (shadowClass) return converted(declaration, shadowClass, "exact");
2259
+ const gradientResult = convertGradient(declaration, options);
2260
+ if (gradientResult) {
2261
+ if (Array.isArray(gradientResult)) return gradientResult.map((cls) => converted(declaration, cls, "exact"));
2262
+ return converted(declaration, gradientResult, "exact");
2263
+ }
2264
+ const varRef = convertVarReference(declaration);
2265
+ if (varRef) return converted(declaration, varRef, "exact");
2217
2266
  const prefix = arbitraryPrefixes[declaration.property];
2218
2267
  if (prefix && options.allowArbitraryValues) return converted(declaration, arbitraryValue(prefix, declaration.value), "arbitrary");
2219
2268
  if (options.allowArbitraryProperties) return converted(declaration, arbitraryProperty(declaration.property, declaration.value), "arbitrary");
@@ -2522,6 +2571,9 @@ function convertTransform(declaration, options) {
2522
2571
  if (declaration.property === "scale-x") return scaleClass(declaration.value, "scale-x");
2523
2572
  if (declaration.property === "scale-y") return scaleClass(declaration.value, "scale-y");
2524
2573
  if (declaration.property === "scale-z") return scaleClass(declaration.value, "scale-z");
2574
+ if (declaration.property === "skew") return angleClass("skew", declaration.value);
2575
+ if (declaration.property === "skew-x") return angleClass("skew-x", declaration.value);
2576
+ if (declaration.property === "skew-y") return angleClass("skew-y", declaration.value);
2525
2577
  if (declaration.property === "translate") return translateClass(declaration.value, options);
2526
2578
  if (declaration.property === "translate-x") return translateAxisClass("translate-x", declaration.value, options);
2527
2579
  if (declaration.property === "translate-y") return translateAxisClass("translate-y", declaration.value, options);
@@ -2623,6 +2675,135 @@ function scaleClass(value, prefix = "scale") {
2623
2675
  if (!Number.isInteger(percent)) return `${prefix}-[${value.trim()}]`;
2624
2676
  return percent < 0 ? `-${prefix}-${Math.abs(percent)}` : `${prefix}-${percent}`;
2625
2677
  }
2678
+ const shadowValues = {
2679
+ "0 1px 2px 0 rgb(0 0 0 / 0.05)": "shadow-xs",
2680
+ "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)": "shadow-sm",
2681
+ "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)": "shadow-md",
2682
+ "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)": "shadow-lg",
2683
+ "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)": "shadow-xl",
2684
+ "0 25px 50px -12px rgb(0 0 0 / 0.25)": "shadow-2xl",
2685
+ "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)": "shadow-inner"
2686
+ };
2687
+ function convertShadow(declaration) {
2688
+ if (declaration.property !== "box-shadow") return void 0;
2689
+ return shadowValues[declaration.value.trim().replace(/\s+/g, " ")];
2690
+ }
2691
+ const varPrefixes = {
2692
+ color: "text",
2693
+ "background-color": "bg",
2694
+ "border-color": "border",
2695
+ "border-top-color": "border-t",
2696
+ "border-right-color": "border-r",
2697
+ "border-bottom-color": "border-b",
2698
+ "border-left-color": "border-l",
2699
+ "outline-color": "outline",
2700
+ fill: "fill",
2701
+ stroke: "stroke",
2702
+ "caret-color": "caret",
2703
+ "accent-color": "accent",
2704
+ "text-decoration-color": "decoration",
2705
+ width: "w",
2706
+ height: "h",
2707
+ "min-width": "min-w",
2708
+ "min-height": "min-h",
2709
+ "max-width": "max-w",
2710
+ "max-height": "max-h",
2711
+ padding: "p",
2712
+ "padding-top": "pt",
2713
+ "padding-right": "pr",
2714
+ "padding-bottom": "pb",
2715
+ "padding-left": "pl",
2716
+ margin: "m",
2717
+ "margin-top": "mt",
2718
+ "margin-right": "mr",
2719
+ "margin-bottom": "mb",
2720
+ "margin-left": "ml",
2721
+ gap: "gap",
2722
+ "row-gap": "gap-y",
2723
+ "column-gap": "gap-x",
2724
+ "font-size": "text",
2725
+ "font-family": "font",
2726
+ "border-radius": "rounded",
2727
+ "border-width": "border",
2728
+ "box-shadow": "shadow",
2729
+ "line-height": "leading",
2730
+ "letter-spacing": "tracking"
2731
+ };
2732
+ function convertVarReference(declaration) {
2733
+ const match = declaration.value.match(/^var\(\s*(--[\w-]+)\s*\)$/);
2734
+ if (!match?.[1]) return void 0;
2735
+ const prefix = varPrefixes[declaration.property];
2736
+ if (prefix) return `${prefix}-(${match[1]})`;
2737
+ }
2738
+ const gradientDirections = {
2739
+ "to right": "bg-linear-to-r",
2740
+ "to left": "bg-linear-to-l",
2741
+ "to top": "bg-linear-to-t",
2742
+ "to bottom": "bg-linear-to-b",
2743
+ "to top right": "bg-linear-to-tr",
2744
+ "to top left": "bg-linear-to-tl",
2745
+ "to bottom right": "bg-linear-to-br",
2746
+ "to bottom left": "bg-linear-to-bl"
2747
+ };
2748
+ function convertGradient(declaration, options) {
2749
+ if (declaration.property !== "background-image" && declaration.property !== "background") return void 0;
2750
+ const linearMatch = declaration.value.trim().match(/^linear-gradient\((.+)\)$/);
2751
+ if (!linearMatch?.[1]) return void 0;
2752
+ const inner = linearMatch[1];
2753
+ const firstComma = findTopLevelComma(inner);
2754
+ if (firstComma === -1) return void 0;
2755
+ const directionPart = inner.slice(0, firstComma).trim();
2756
+ const colorsPart = inner.slice(firstComma + 1).trim();
2757
+ const dirClass = gradientDirections[directionPart] ?? (directionPart.match(/^\d+deg$/) ? `bg-linear-${directionPart.replace("deg", "")}` : void 0);
2758
+ if (!dirClass) return void 0;
2759
+ const colorStops = splitGradientStops(colorsPart);
2760
+ if (colorStops.length < 2 || colorStops.length > 3) return void 0;
2761
+ const classes = [dirClass];
2762
+ const fromColor = matchGradientColor(colorStops[0] ?? "", "from", options);
2763
+ if (!fromColor) return void 0;
2764
+ classes.push(fromColor);
2765
+ if (colorStops.length === 3) {
2766
+ const viaColor = matchGradientColor(colorStops[1] ?? "", "via", options);
2767
+ if (!viaColor) return void 0;
2768
+ classes.push(viaColor);
2769
+ }
2770
+ const toColor = matchGradientColor(colorStops[colorStops.length - 1] ?? "", "to", options);
2771
+ if (!toColor) return void 0;
2772
+ classes.push(toColor);
2773
+ return classes;
2774
+ }
2775
+ function matchGradientColor(stop, prefix, options) {
2776
+ const color = stop.trim().split(/\s+/)[0];
2777
+ if (!color) return void 0;
2778
+ const normalized = normalizeColor(color);
2779
+ const keyword = colorKeywords[normalized];
2780
+ if (keyword) return `${prefix}-${keyword}`;
2781
+ const hexToken = lookupHexToken(normalized);
2782
+ if (hexToken) return `${prefix}-${hexToken}`;
2783
+ const token = Object.entries(options.theme.colors).find(([, c]) => normalizeColor(c) === normalized)?.[0];
2784
+ if (token) return `${prefix}-${token}`;
2785
+ return `${prefix}-[${color}]`;
2786
+ }
2787
+ function findTopLevelComma(value) {
2788
+ let depth = 0;
2789
+ for (let i = 0; i < value.length; i++) if (value[i] === "(") depth++;
2790
+ else if (value[i] === ")") depth--;
2791
+ else if (value[i] === "," && depth === 0) return i;
2792
+ return -1;
2793
+ }
2794
+ function splitGradientStops(value) {
2795
+ const stops = [];
2796
+ let depth = 0;
2797
+ let start = 0;
2798
+ for (let i = 0; i < value.length; i++) if (value[i] === "(") depth++;
2799
+ else if (value[i] === ")") depth--;
2800
+ else if (value[i] === "," && depth === 0) {
2801
+ stops.push(value.slice(start, i).trim());
2802
+ start = i + 1;
2803
+ }
2804
+ stops.push(value.slice(start).trim());
2805
+ return stops.filter(Boolean);
2806
+ }
2626
2807
  function converted(declaration, className, kind) {
2627
2808
  const important = declaration.important ? "!" : "";
2628
2809
  const variants = declaration.variants.length > 0 ? `${declaration.variants.join(":")}:` : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twirlwind",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Tailwind v4-first CSS style object to utility class serializer with lossless arbitrary-property fallback.",
5
5
  "keywords": [
6
6
  "converter",