@formepdf/tailwind 0.7.10
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.
- package/dist/colors.d.ts +1 -0
- package/dist/colors.js +126 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +32 -0
- package/dist/parsers.d.ts +2 -0
- package/dist/parsers.js +526 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.js +1 -0
- package/package.json +32 -0
package/dist/colors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveColor(name: string): string | undefined;
|
package/dist/colors.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const palette = {
|
|
2
|
+
slate: {
|
|
3
|
+
"50": "#f8fafc", "100": "#f1f5f9", "200": "#e2e8f0", "300": "#cbd5e1",
|
|
4
|
+
"400": "#94a3b8", "500": "#64748b", "600": "#475569", "700": "#334155",
|
|
5
|
+
"800": "#1e293b", "900": "#0f172a", "950": "#020617",
|
|
6
|
+
},
|
|
7
|
+
gray: {
|
|
8
|
+
"50": "#f9fafb", "100": "#f3f4f6", "200": "#e5e7eb", "300": "#d1d5db",
|
|
9
|
+
"400": "#9ca3af", "500": "#6b7280", "600": "#4b5563", "700": "#374151",
|
|
10
|
+
"800": "#1f2937", "900": "#111827", "950": "#030712",
|
|
11
|
+
},
|
|
12
|
+
zinc: {
|
|
13
|
+
"50": "#fafafa", "100": "#f4f4f5", "200": "#e4e4e7", "300": "#d4d4d8",
|
|
14
|
+
"400": "#a1a1aa", "500": "#71717a", "600": "#52525b", "700": "#3f3f46",
|
|
15
|
+
"800": "#27272a", "900": "#18181b", "950": "#09090b",
|
|
16
|
+
},
|
|
17
|
+
neutral: {
|
|
18
|
+
"50": "#fafafa", "100": "#f5f5f5", "200": "#e5e5e5", "300": "#d4d4d4",
|
|
19
|
+
"400": "#a3a3a3", "500": "#737373", "600": "#525252", "700": "#404040",
|
|
20
|
+
"800": "#262626", "900": "#171717", "950": "#0a0a0a",
|
|
21
|
+
},
|
|
22
|
+
stone: {
|
|
23
|
+
"50": "#fafaf9", "100": "#f5f5f4", "200": "#e7e5e4", "300": "#d6d3d1",
|
|
24
|
+
"400": "#a8a29e", "500": "#78716c", "600": "#57534e", "700": "#44403c",
|
|
25
|
+
"800": "#292524", "900": "#1c1917", "950": "#0c0a09",
|
|
26
|
+
},
|
|
27
|
+
red: {
|
|
28
|
+
"50": "#fef2f2", "100": "#fee2e2", "200": "#fecaca", "300": "#fca5a5",
|
|
29
|
+
"400": "#f87171", "500": "#ef4444", "600": "#dc2626", "700": "#b91c1c",
|
|
30
|
+
"800": "#991b1b", "900": "#7f1d1d", "950": "#450a0a",
|
|
31
|
+
},
|
|
32
|
+
orange: {
|
|
33
|
+
"50": "#fff7ed", "100": "#ffedd5", "200": "#fed7aa", "300": "#fdba74",
|
|
34
|
+
"400": "#fb923c", "500": "#f97316", "600": "#ea580c", "700": "#c2410c",
|
|
35
|
+
"800": "#9a3412", "900": "#7c2d12", "950": "#431407",
|
|
36
|
+
},
|
|
37
|
+
amber: {
|
|
38
|
+
"50": "#fffbeb", "100": "#fef3c7", "200": "#fde68a", "300": "#fcd34d",
|
|
39
|
+
"400": "#fbbf24", "500": "#f59e0b", "600": "#d97706", "700": "#b45309",
|
|
40
|
+
"800": "#92400e", "900": "#78350f", "950": "#451a03",
|
|
41
|
+
},
|
|
42
|
+
yellow: {
|
|
43
|
+
"50": "#fefce8", "100": "#fef9c3", "200": "#fef08a", "300": "#fde047",
|
|
44
|
+
"400": "#facc15", "500": "#eab308", "600": "#ca8a04", "700": "#a16207",
|
|
45
|
+
"800": "#854d0e", "900": "#713f12", "950": "#422006",
|
|
46
|
+
},
|
|
47
|
+
lime: {
|
|
48
|
+
"50": "#f7fee7", "100": "#ecfccb", "200": "#d9f99d", "300": "#bef264",
|
|
49
|
+
"400": "#a3e635", "500": "#84cc16", "600": "#65a30d", "700": "#4d7c0f",
|
|
50
|
+
"800": "#3f6212", "900": "#365314", "950": "#1a2e05",
|
|
51
|
+
},
|
|
52
|
+
green: {
|
|
53
|
+
"50": "#f0fdf4", "100": "#dcfce7", "200": "#bbf7d0", "300": "#86efac",
|
|
54
|
+
"400": "#4ade80", "500": "#22c55e", "600": "#16a34a", "700": "#15803d",
|
|
55
|
+
"800": "#166534", "900": "#14532d", "950": "#052e16",
|
|
56
|
+
},
|
|
57
|
+
emerald: {
|
|
58
|
+
"50": "#ecfdf5", "100": "#d1fae5", "200": "#a7f3d0", "300": "#6ee7b7",
|
|
59
|
+
"400": "#34d399", "500": "#10b981", "600": "#059669", "700": "#047857",
|
|
60
|
+
"800": "#065f46", "900": "#064e3b", "950": "#022c22",
|
|
61
|
+
},
|
|
62
|
+
teal: {
|
|
63
|
+
"50": "#f0fdfa", "100": "#ccfbf1", "200": "#99f6e4", "300": "#5eead4",
|
|
64
|
+
"400": "#2dd4bf", "500": "#14b8a6", "600": "#0d9488", "700": "#0f766e",
|
|
65
|
+
"800": "#115e59", "900": "#134e4a", "950": "#042f2e",
|
|
66
|
+
},
|
|
67
|
+
cyan: {
|
|
68
|
+
"50": "#ecfeff", "100": "#cffafe", "200": "#a5f3fc", "300": "#67e8f9",
|
|
69
|
+
"400": "#22d3ee", "500": "#06b6d4", "600": "#0891b2", "700": "#0e7490",
|
|
70
|
+
"800": "#155e75", "900": "#164e63", "950": "#083344",
|
|
71
|
+
},
|
|
72
|
+
sky: {
|
|
73
|
+
"50": "#f0f9ff", "100": "#e0f2fe", "200": "#bae6fd", "300": "#7dd3fc",
|
|
74
|
+
"400": "#38bdf8", "500": "#0ea5e9", "600": "#0284c7", "700": "#0369a1",
|
|
75
|
+
"800": "#075985", "900": "#0c4a6e", "950": "#082f49",
|
|
76
|
+
},
|
|
77
|
+
blue: {
|
|
78
|
+
"50": "#eff6ff", "100": "#dbeafe", "200": "#bfdbfe", "300": "#93c5fd",
|
|
79
|
+
"400": "#60a5fa", "500": "#3b82f6", "600": "#2563eb", "700": "#1d4ed8",
|
|
80
|
+
"800": "#1e40af", "900": "#1e3a8a", "950": "#172554",
|
|
81
|
+
},
|
|
82
|
+
indigo: {
|
|
83
|
+
"50": "#eef2ff", "100": "#e0e7ff", "200": "#c7d2fe", "300": "#a5b4fc",
|
|
84
|
+
"400": "#818cf8", "500": "#6366f1", "600": "#4f46e5", "700": "#4338ca",
|
|
85
|
+
"800": "#3730a3", "900": "#312e81", "950": "#1e1b4e",
|
|
86
|
+
},
|
|
87
|
+
violet: {
|
|
88
|
+
"50": "#f5f3ff", "100": "#ede9fe", "200": "#ddd6fe", "300": "#c4b5fd",
|
|
89
|
+
"400": "#a78bfa", "500": "#8b5cf6", "600": "#7c3aed", "700": "#6d28d9",
|
|
90
|
+
"800": "#5b21b6", "900": "#4c1d95", "950": "#2e1065",
|
|
91
|
+
},
|
|
92
|
+
purple: {
|
|
93
|
+
"50": "#faf5ff", "100": "#f3e8ff", "200": "#e9d5ff", "300": "#d8b4fe",
|
|
94
|
+
"400": "#c084fc", "500": "#a855f7", "600": "#9333ea", "700": "#7e22ce",
|
|
95
|
+
"800": "#6b21a8", "900": "#581c87", "950": "#3b0764",
|
|
96
|
+
},
|
|
97
|
+
fuchsia: {
|
|
98
|
+
"50": "#fdf4ff", "100": "#fae8ff", "200": "#f5d0fe", "300": "#f0abfc",
|
|
99
|
+
"400": "#e879f9", "500": "#d946ef", "600": "#c026d3", "700": "#a21caf",
|
|
100
|
+
"800": "#86198f", "900": "#701a75", "950": "#4a044e",
|
|
101
|
+
},
|
|
102
|
+
pink: {
|
|
103
|
+
"50": "#fdf2f8", "100": "#fce7f3", "200": "#fbcfe8", "300": "#f9a8d4",
|
|
104
|
+
"400": "#f472b6", "500": "#ec4899", "600": "#db2777", "700": "#be185d",
|
|
105
|
+
"800": "#9d174d", "900": "#831843", "950": "#500724",
|
|
106
|
+
},
|
|
107
|
+
rose: {
|
|
108
|
+
"50": "#fff1f2", "100": "#ffe4e6", "200": "#fecdd3", "300": "#fda4af",
|
|
109
|
+
"400": "#fb7185", "500": "#f43f5e", "600": "#e11d48", "700": "#be123c",
|
|
110
|
+
"800": "#9f1239", "900": "#881337", "950": "#4c0519",
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
export function resolveColor(name) {
|
|
114
|
+
if (name === "black")
|
|
115
|
+
return "#000000";
|
|
116
|
+
if (name === "white")
|
|
117
|
+
return "#ffffff";
|
|
118
|
+
if (name === "transparent")
|
|
119
|
+
return "transparent";
|
|
120
|
+
const dashIndex = name.lastIndexOf("-");
|
|
121
|
+
if (dashIndex === -1)
|
|
122
|
+
return undefined;
|
|
123
|
+
const colorName = name.substring(0, dashIndex);
|
|
124
|
+
const shade = name.substring(dashIndex + 1);
|
|
125
|
+
return palette[colorName]?.[shade];
|
|
126
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FormeStyle } from "./types.js";
|
|
2
|
+
export type { FormeStyle } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Convert Tailwind CSS class names to a Forme style object.
|
|
5
|
+
*
|
|
6
|
+
* Unknown classes are silently ignored. When classes conflict,
|
|
7
|
+
* the last one wins (natural Object.assign behavior).
|
|
8
|
+
*/
|
|
9
|
+
export declare function tw(classes: string): FormeStyle;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { parseClass } from "./parsers.js";
|
|
2
|
+
/**
|
|
3
|
+
* Convert Tailwind CSS class names to a Forme style object.
|
|
4
|
+
*
|
|
5
|
+
* Unknown classes are silently ignored. When classes conflict,
|
|
6
|
+
* the last one wins (natural Object.assign behavior).
|
|
7
|
+
*/
|
|
8
|
+
export function tw(classes) {
|
|
9
|
+
const result = {};
|
|
10
|
+
if (!classes)
|
|
11
|
+
return result;
|
|
12
|
+
for (const cls of classes.trim().split(/\s+/)) {
|
|
13
|
+
if (!cls)
|
|
14
|
+
continue;
|
|
15
|
+
// Negative values: -mt-4, -top-2, etc.
|
|
16
|
+
if (cls.startsWith("-") && !cls.startsWith("-[")) {
|
|
17
|
+
const parsed = parseClass(cls.substring(1));
|
|
18
|
+
if (parsed) {
|
|
19
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
20
|
+
if (typeof v === "number")
|
|
21
|
+
parsed[k] = -v;
|
|
22
|
+
}
|
|
23
|
+
Object.assign(result, parsed);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const parsed = parseClass(cls);
|
|
28
|
+
if (parsed)
|
|
29
|
+
Object.assign(result, parsed);
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
package/dist/parsers.js
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
import { resolveColor } from "./colors.js";
|
|
2
|
+
// ── Spacing ──────────────────────────────────────────────────────────
|
|
3
|
+
function parseSpacingValue(val) {
|
|
4
|
+
if (val === "px")
|
|
5
|
+
return 1;
|
|
6
|
+
const n = parseFloat(val);
|
|
7
|
+
if (isNaN(n))
|
|
8
|
+
return undefined;
|
|
9
|
+
return n * 4;
|
|
10
|
+
}
|
|
11
|
+
const spacingMap = {
|
|
12
|
+
pt: "paddingTop", pr: "paddingRight", pb: "paddingBottom", pl: "paddingLeft",
|
|
13
|
+
px: "paddingHorizontal", py: "paddingVertical",
|
|
14
|
+
mt: "marginTop", mr: "marginRight", mb: "marginBottom", ml: "marginLeft",
|
|
15
|
+
mx: "marginHorizontal", my: "marginVertical",
|
|
16
|
+
};
|
|
17
|
+
function parseSpacing(cls) {
|
|
18
|
+
// p-{n} / m-{n}
|
|
19
|
+
const pMatch = cls.match(/^(p|m)-(.+)$/);
|
|
20
|
+
if (pMatch) {
|
|
21
|
+
const prop = pMatch[1] === "p" ? "padding" : "margin";
|
|
22
|
+
if (pMatch[2] === "auto" && prop === "margin")
|
|
23
|
+
return { margin: "auto" };
|
|
24
|
+
const val = parseSpacingValue(pMatch[2]);
|
|
25
|
+
if (val !== undefined)
|
|
26
|
+
return { [prop]: val };
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
// pt-{n}, px-{n}, mx-auto, etc.
|
|
30
|
+
const sideMatch = cls.match(/^(pt|pr|pb|pl|px|py|mt|mr|mb|ml|mx|my)-(.+)$/);
|
|
31
|
+
if (sideMatch) {
|
|
32
|
+
const key = spacingMap[sideMatch[1]];
|
|
33
|
+
if (!key)
|
|
34
|
+
return null;
|
|
35
|
+
// Margin sides and axes support "auto" for centering
|
|
36
|
+
if (sideMatch[2] === "auto") {
|
|
37
|
+
if (sideMatch[1].startsWith("m"))
|
|
38
|
+
return { [key]: "auto" };
|
|
39
|
+
return null; // padding doesn't support auto
|
|
40
|
+
}
|
|
41
|
+
const val = parseSpacingValue(sideMatch[2]);
|
|
42
|
+
if (val !== undefined)
|
|
43
|
+
return { [key]: val };
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
// ── Typography ───────────────────────────────────────────────────────
|
|
48
|
+
const textSizes = {
|
|
49
|
+
xs: 12, sm: 14, base: 16, lg: 18, xl: 20,
|
|
50
|
+
"2xl": 24, "3xl": 30, "4xl": 36, "5xl": 48, "6xl": 60, "7xl": 72, "8xl": 96, "9xl": 128,
|
|
51
|
+
};
|
|
52
|
+
const fontWeights = {
|
|
53
|
+
thin: 100, extralight: 200, light: 300, normal: 400, medium: 500,
|
|
54
|
+
semibold: 600, bold: 700, extrabold: 800, black: 900,
|
|
55
|
+
};
|
|
56
|
+
const namedLeading = {
|
|
57
|
+
none: 1, tight: 1.25, snug: 1.375, normal: 1.5, relaxed: 1.625, loose: 2,
|
|
58
|
+
};
|
|
59
|
+
const trackingValues = {
|
|
60
|
+
tighter: -0.05, tight: -0.025, normal: 0, wide: 0.025, wider: 0.05, widest: 0.1,
|
|
61
|
+
};
|
|
62
|
+
function parseTypography(cls) {
|
|
63
|
+
// text-{size}
|
|
64
|
+
if (cls.startsWith("text-")) {
|
|
65
|
+
const rest = cls.substring(5);
|
|
66
|
+
if (textSizes[rest] !== undefined)
|
|
67
|
+
return { fontSize: textSizes[rest] };
|
|
68
|
+
// text-left/center/right/justify
|
|
69
|
+
if (rest === "left" || rest === "center" || rest === "right" || rest === "justify") {
|
|
70
|
+
return { textAlign: rest };
|
|
71
|
+
}
|
|
72
|
+
// text-{color}-{shade} or text-black/white — handled in parseColor
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
// font-{weight}
|
|
76
|
+
if (cls.startsWith("font-")) {
|
|
77
|
+
const weight = fontWeights[cls.substring(5)];
|
|
78
|
+
if (weight !== undefined)
|
|
79
|
+
return { fontWeight: weight };
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
// italic
|
|
83
|
+
if (cls === "italic")
|
|
84
|
+
return { fontStyle: "italic" };
|
|
85
|
+
// leading-{value}
|
|
86
|
+
if (cls.startsWith("leading-")) {
|
|
87
|
+
const rest = cls.substring(8);
|
|
88
|
+
if (namedLeading[rest] !== undefined)
|
|
89
|
+
return { lineHeight: namedLeading[rest] };
|
|
90
|
+
const n = parseFloat(rest);
|
|
91
|
+
if (!isNaN(n))
|
|
92
|
+
return { lineHeight: n * 4 };
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
// tracking-{value}
|
|
96
|
+
if (cls.startsWith("tracking-")) {
|
|
97
|
+
const val = trackingValues[cls.substring(9)];
|
|
98
|
+
if (val !== undefined)
|
|
99
|
+
return { letterSpacing: val };
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
// text decorations
|
|
103
|
+
if (cls === "underline")
|
|
104
|
+
return { textDecoration: "underline" };
|
|
105
|
+
if (cls === "line-through")
|
|
106
|
+
return { textDecoration: "line-through" };
|
|
107
|
+
if (cls === "no-underline")
|
|
108
|
+
return { textDecoration: "none" };
|
|
109
|
+
// text transforms
|
|
110
|
+
if (cls === "uppercase")
|
|
111
|
+
return { textTransform: "uppercase" };
|
|
112
|
+
if (cls === "lowercase")
|
|
113
|
+
return { textTransform: "lowercase" };
|
|
114
|
+
if (cls === "capitalize")
|
|
115
|
+
return { textTransform: "capitalize" };
|
|
116
|
+
if (cls === "normal-case")
|
|
117
|
+
return { textTransform: "none" };
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
// ── Colors ───────────────────────────────────────────────────────────
|
|
121
|
+
function parseColorClass(cls) {
|
|
122
|
+
// text-{color}-{shade} or text-black/white/transparent
|
|
123
|
+
if (cls.startsWith("text-")) {
|
|
124
|
+
const rest = cls.substring(5);
|
|
125
|
+
// Skip size and alignment keywords
|
|
126
|
+
if (textSizes[rest] !== undefined)
|
|
127
|
+
return null;
|
|
128
|
+
if (rest === "left" || rest === "center" || rest === "right" || rest === "justify")
|
|
129
|
+
return null;
|
|
130
|
+
const color = resolveColor(rest);
|
|
131
|
+
if (color)
|
|
132
|
+
return { color };
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
// bg-{color}-{shade}
|
|
136
|
+
if (cls.startsWith("bg-")) {
|
|
137
|
+
const color = resolveColor(cls.substring(3));
|
|
138
|
+
if (color)
|
|
139
|
+
return { backgroundColor: color };
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
// border-{color}-{shade} — only when it looks like a color, not a width or side
|
|
143
|
+
if (cls.startsWith("border-")) {
|
|
144
|
+
const rest = cls.substring(7);
|
|
145
|
+
// Skip width values and sides
|
|
146
|
+
if (/^\d+$/.test(rest))
|
|
147
|
+
return null;
|
|
148
|
+
if (["t", "r", "b", "l"].includes(rest))
|
|
149
|
+
return null;
|
|
150
|
+
if (rest.startsWith("t-") || rest.startsWith("r-") || rest.startsWith("b-") || rest.startsWith("l-"))
|
|
151
|
+
return null;
|
|
152
|
+
const color = resolveColor(rest);
|
|
153
|
+
if (color)
|
|
154
|
+
return { borderColor: color };
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
// ── Layout ───────────────────────────────────────────────────────────
|
|
160
|
+
const alignItemsMap = {
|
|
161
|
+
start: "flex-start", end: "flex-end", center: "center", stretch: "stretch", baseline: "baseline",
|
|
162
|
+
};
|
|
163
|
+
const justifyContentMap = {
|
|
164
|
+
start: "flex-start", end: "flex-end", center: "center",
|
|
165
|
+
between: "space-between", around: "space-around", evenly: "space-evenly",
|
|
166
|
+
};
|
|
167
|
+
function parseDimension(val) {
|
|
168
|
+
if (val === "full")
|
|
169
|
+
return "100%";
|
|
170
|
+
if (val === "auto")
|
|
171
|
+
return "auto";
|
|
172
|
+
if (val === "screen")
|
|
173
|
+
return "100%";
|
|
174
|
+
// Fractional like 1/2, 1/3, etc. — check before numeric parse since parseFloat("1/2") === 1
|
|
175
|
+
const fracMatch = val.match(/^(\d+)\/(\d+)$/);
|
|
176
|
+
if (fracMatch)
|
|
177
|
+
return `${(parseInt(fracMatch[1]) / parseInt(fracMatch[2]) * 100).toFixed(6)}%`;
|
|
178
|
+
const n = parseFloat(val);
|
|
179
|
+
if (!isNaN(n))
|
|
180
|
+
return n * 4;
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
function parseLayout(cls) {
|
|
184
|
+
// flex direction
|
|
185
|
+
if (cls === "flex")
|
|
186
|
+
return {}; // no-op, flex is default in Forme
|
|
187
|
+
if (cls === "flex-row")
|
|
188
|
+
return { flexDirection: "row" };
|
|
189
|
+
if (cls === "flex-col")
|
|
190
|
+
return { flexDirection: "column" };
|
|
191
|
+
if (cls === "flex-row-reverse")
|
|
192
|
+
return { flexDirection: "row-reverse" };
|
|
193
|
+
if (cls === "flex-col-reverse")
|
|
194
|
+
return { flexDirection: "column-reverse" };
|
|
195
|
+
// align/justify
|
|
196
|
+
if (cls.startsWith("items-")) {
|
|
197
|
+
const val = alignItemsMap[cls.substring(6)];
|
|
198
|
+
if (val)
|
|
199
|
+
return { alignItems: val };
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
if (cls.startsWith("justify-")) {
|
|
203
|
+
const val = justifyContentMap[cls.substring(8)];
|
|
204
|
+
if (val)
|
|
205
|
+
return { justifyContent: val };
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
// flex shorthand
|
|
209
|
+
if (cls === "flex-1")
|
|
210
|
+
return { flex: 1 };
|
|
211
|
+
if (cls === "flex-auto")
|
|
212
|
+
return { flexGrow: 1, flexShrink: 1, flexBasis: "auto" };
|
|
213
|
+
if (cls === "flex-initial")
|
|
214
|
+
return { flexGrow: 0, flexShrink: 1, flexBasis: "auto" };
|
|
215
|
+
if (cls === "flex-none")
|
|
216
|
+
return { flex: 0 };
|
|
217
|
+
if (cls === "flex-grow")
|
|
218
|
+
return { flexGrow: 1 };
|
|
219
|
+
if (cls === "flex-grow-0")
|
|
220
|
+
return { flexGrow: 0 };
|
|
221
|
+
if (cls === "flex-shrink")
|
|
222
|
+
return { flexShrink: 1 };
|
|
223
|
+
if (cls === "flex-shrink-0")
|
|
224
|
+
return { flexShrink: 0 };
|
|
225
|
+
if (cls === "flex-wrap")
|
|
226
|
+
return { flexWrap: "wrap" };
|
|
227
|
+
if (cls === "flex-nowrap")
|
|
228
|
+
return { flexWrap: "nowrap" };
|
|
229
|
+
// gap
|
|
230
|
+
if (cls.startsWith("gap-x-")) {
|
|
231
|
+
const n = parseFloat(cls.substring(6));
|
|
232
|
+
if (!isNaN(n))
|
|
233
|
+
return { columnGap: n * 4 };
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
if (cls.startsWith("gap-y-")) {
|
|
237
|
+
const n = parseFloat(cls.substring(6));
|
|
238
|
+
if (!isNaN(n))
|
|
239
|
+
return { rowGap: n * 4 };
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
if (cls.startsWith("gap-")) {
|
|
243
|
+
const n = parseFloat(cls.substring(4));
|
|
244
|
+
if (!isNaN(n))
|
|
245
|
+
return { gap: n * 4 };
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
// dimensions
|
|
249
|
+
if (cls.startsWith("w-")) {
|
|
250
|
+
const val = parseDimension(cls.substring(2));
|
|
251
|
+
if (val !== undefined)
|
|
252
|
+
return { width: val };
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
if (cls.startsWith("h-")) {
|
|
256
|
+
const val = parseDimension(cls.substring(2));
|
|
257
|
+
if (val !== undefined)
|
|
258
|
+
return { height: val };
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
if (cls.startsWith("min-w-")) {
|
|
262
|
+
const n = parseFloat(cls.substring(6));
|
|
263
|
+
if (!isNaN(n))
|
|
264
|
+
return { minWidth: n * 4 };
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
if (cls.startsWith("max-w-")) {
|
|
268
|
+
const n = parseFloat(cls.substring(6));
|
|
269
|
+
if (!isNaN(n))
|
|
270
|
+
return { maxWidth: n * 4 };
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
if (cls.startsWith("min-h-")) {
|
|
274
|
+
const n = parseFloat(cls.substring(6));
|
|
275
|
+
if (!isNaN(n))
|
|
276
|
+
return { minHeight: n * 4 };
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
if (cls.startsWith("max-h-")) {
|
|
280
|
+
const n = parseFloat(cls.substring(6));
|
|
281
|
+
if (!isNaN(n))
|
|
282
|
+
return { maxHeight: n * 4 };
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
// position
|
|
286
|
+
if (cls === "relative")
|
|
287
|
+
return { position: "relative" };
|
|
288
|
+
if (cls === "absolute")
|
|
289
|
+
return { position: "absolute" };
|
|
290
|
+
// positional offsets
|
|
291
|
+
if (cls.startsWith("top-")) {
|
|
292
|
+
const n = parseFloat(cls.substring(4));
|
|
293
|
+
if (!isNaN(n))
|
|
294
|
+
return { top: n * 4 };
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
if (cls.startsWith("right-")) {
|
|
298
|
+
const n = parseFloat(cls.substring(6));
|
|
299
|
+
if (!isNaN(n))
|
|
300
|
+
return { right: n * 4 };
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
if (cls.startsWith("bottom-")) {
|
|
304
|
+
const n = parseFloat(cls.substring(7));
|
|
305
|
+
if (!isNaN(n))
|
|
306
|
+
return { bottom: n * 4 };
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
if (cls.startsWith("left-")) {
|
|
310
|
+
const n = parseFloat(cls.substring(5));
|
|
311
|
+
if (!isNaN(n))
|
|
312
|
+
return { left: n * 4 };
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
// overflow
|
|
316
|
+
if (cls === "overflow-hidden")
|
|
317
|
+
return { overflow: "hidden" };
|
|
318
|
+
if (cls === "overflow-visible")
|
|
319
|
+
return { overflow: "visible" };
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
// ── Borders ──────────────────────────────────────────────────────────
|
|
323
|
+
const roundedValues = {
|
|
324
|
+
"": 4, sm: 2, md: 6, lg: 8, xl: 12, "2xl": 16, "3xl": 24, full: 9999, none: 0,
|
|
325
|
+
};
|
|
326
|
+
function parseBorder(cls) {
|
|
327
|
+
// border width
|
|
328
|
+
if (cls === "border")
|
|
329
|
+
return { borderWidth: 1 };
|
|
330
|
+
if (cls.match(/^border-[0248]$/)) {
|
|
331
|
+
return { borderWidth: parseInt(cls.substring(7)) };
|
|
332
|
+
}
|
|
333
|
+
// per-side border width
|
|
334
|
+
const sideMap = {
|
|
335
|
+
t: "borderTopWidth", r: "borderRightWidth", b: "borderBottomWidth", l: "borderLeftWidth",
|
|
336
|
+
};
|
|
337
|
+
if (cls.match(/^border-[trbl]$/)) {
|
|
338
|
+
return { [sideMap[cls.substring(7)]]: 1 };
|
|
339
|
+
}
|
|
340
|
+
const sideWidthMatch = cls.match(/^border-([trbl])-(\d+)$/);
|
|
341
|
+
if (sideWidthMatch) {
|
|
342
|
+
return { [sideMap[sideWidthMatch[1]]]: parseInt(sideWidthMatch[2]) };
|
|
343
|
+
}
|
|
344
|
+
// rounded
|
|
345
|
+
if (cls === "rounded")
|
|
346
|
+
return { borderRadius: roundedValues[""] };
|
|
347
|
+
if (cls.startsWith("rounded-")) {
|
|
348
|
+
const val = roundedValues[cls.substring(8)];
|
|
349
|
+
if (val !== undefined)
|
|
350
|
+
return { borderRadius: val };
|
|
351
|
+
// rounded-{n} for arbitrary numeric
|
|
352
|
+
const n = parseFloat(cls.substring(8));
|
|
353
|
+
if (!isNaN(n))
|
|
354
|
+
return { borderRadius: n };
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
// ── Opacity ──────────────────────────────────────────────────────────
|
|
360
|
+
function parseOpacity(cls) {
|
|
361
|
+
if (cls.startsWith("opacity-")) {
|
|
362
|
+
const n = parseInt(cls.substring(8));
|
|
363
|
+
if (!isNaN(n))
|
|
364
|
+
return { opacity: n / 100 };
|
|
365
|
+
}
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
// ── Grid ────────────────────────────────────────────────────────────
|
|
369
|
+
function parseGrid(cls) {
|
|
370
|
+
if (cls === "grid")
|
|
371
|
+
return { display: "grid" };
|
|
372
|
+
// grid-cols-{n} / grid-cols-none
|
|
373
|
+
if (cls.startsWith("grid-cols-")) {
|
|
374
|
+
const rest = cls.substring(10);
|
|
375
|
+
if (rest === "none")
|
|
376
|
+
return { gridTemplateColumns: "none" };
|
|
377
|
+
const n = parseInt(rest);
|
|
378
|
+
if (!isNaN(n) && n >= 1 && n <= 12)
|
|
379
|
+
return { gridTemplateColumns: `repeat(${n}, 1fr)` };
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
// grid-rows-{n} / grid-rows-none
|
|
383
|
+
if (cls.startsWith("grid-rows-")) {
|
|
384
|
+
const rest = cls.substring(10);
|
|
385
|
+
if (rest === "none")
|
|
386
|
+
return { gridTemplateRows: "none" };
|
|
387
|
+
const n = parseInt(rest);
|
|
388
|
+
if (!isNaN(n) && n >= 1 && n <= 6)
|
|
389
|
+
return { gridTemplateRows: `repeat(${n}, 1fr)` };
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
// col-span-{n} / col-span-full
|
|
393
|
+
if (cls.startsWith("col-span-")) {
|
|
394
|
+
const rest = cls.substring(9);
|
|
395
|
+
if (rest === "full")
|
|
396
|
+
return { gridColumnStart: 1, gridColumnEnd: -1 };
|
|
397
|
+
const n = parseInt(rest);
|
|
398
|
+
if (!isNaN(n) && n >= 1 && n <= 12)
|
|
399
|
+
return { gridColumnSpan: n };
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
// col-start-{n}
|
|
403
|
+
if (cls.startsWith("col-start-")) {
|
|
404
|
+
const n = parseInt(cls.substring(10));
|
|
405
|
+
if (!isNaN(n) && n >= 1 && n <= 13)
|
|
406
|
+
return { gridColumnStart: n };
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
// col-end-{n}
|
|
410
|
+
if (cls.startsWith("col-end-")) {
|
|
411
|
+
const n = parseInt(cls.substring(8));
|
|
412
|
+
if (!isNaN(n) && n >= 1 && n <= 13)
|
|
413
|
+
return { gridColumnEnd: n };
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
// row-span-{n} / row-span-full
|
|
417
|
+
if (cls.startsWith("row-span-")) {
|
|
418
|
+
const rest = cls.substring(9);
|
|
419
|
+
if (rest === "full")
|
|
420
|
+
return { gridRowStart: 1, gridRowEnd: -1 };
|
|
421
|
+
const n = parseInt(rest);
|
|
422
|
+
if (!isNaN(n) && n >= 1 && n <= 6)
|
|
423
|
+
return { gridRowSpan: n };
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
// row-start-{n}
|
|
427
|
+
if (cls.startsWith("row-start-")) {
|
|
428
|
+
const n = parseInt(cls.substring(10));
|
|
429
|
+
if (!isNaN(n) && n >= 1 && n <= 7)
|
|
430
|
+
return { gridRowStart: n };
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
// row-end-{n}
|
|
434
|
+
if (cls.startsWith("row-end-")) {
|
|
435
|
+
const n = parseInt(cls.substring(8));
|
|
436
|
+
if (!isNaN(n) && n >= 1 && n <= 7)
|
|
437
|
+
return { gridRowEnd: n };
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
// ── Self Alignment ──────────────────────────────────────────────────
|
|
443
|
+
const alignSelfMap = {
|
|
444
|
+
start: "flex-start", end: "flex-end", center: "center", stretch: "stretch", baseline: "baseline",
|
|
445
|
+
};
|
|
446
|
+
function parseSelf(cls) {
|
|
447
|
+
if (cls.startsWith("self-")) {
|
|
448
|
+
const val = alignSelfMap[cls.substring(5)];
|
|
449
|
+
if (val)
|
|
450
|
+
return { alignSelf: val };
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
// ── Arbitrary Values ────────────────────────────────────────────────
|
|
455
|
+
const arbitraryPrefixMap = {
|
|
456
|
+
w: "width", h: "height",
|
|
457
|
+
"min-w": "minWidth", "max-w": "maxWidth", "min-h": "minHeight", "max-h": "maxHeight",
|
|
458
|
+
p: "padding", px: "paddingHorizontal", py: "paddingVertical",
|
|
459
|
+
pt: "paddingTop", pr: "paddingRight", pb: "paddingBottom", pl: "paddingLeft",
|
|
460
|
+
m: "margin", mx: "marginHorizontal", my: "marginVertical",
|
|
461
|
+
mt: "marginTop", mr: "marginRight", mb: "marginBottom", ml: "marginLeft",
|
|
462
|
+
gap: "gap", "gap-x": "columnGap", "gap-y": "rowGap",
|
|
463
|
+
top: "top", right: "right", bottom: "bottom", left: "left",
|
|
464
|
+
rounded: "borderRadius",
|
|
465
|
+
opacity: "opacity",
|
|
466
|
+
leading: "lineHeight",
|
|
467
|
+
text: "special",
|
|
468
|
+
bg: "special",
|
|
469
|
+
border: "special",
|
|
470
|
+
};
|
|
471
|
+
function parseArbitrary(cls) {
|
|
472
|
+
const bracketIdx = cls.indexOf("[");
|
|
473
|
+
if (bracketIdx === -1 || !cls.endsWith("]"))
|
|
474
|
+
return null;
|
|
475
|
+
const prefix = cls.substring(0, bracketIdx - 1); // strip trailing '-'
|
|
476
|
+
const raw = cls.substring(bracketIdx + 1, cls.length - 1); // content inside brackets
|
|
477
|
+
const prop = arbitraryPrefixMap[prefix];
|
|
478
|
+
if (!prop)
|
|
479
|
+
return null;
|
|
480
|
+
if (prop === "special") {
|
|
481
|
+
// text-[...]: numeric → fontSize, color → color
|
|
482
|
+
if (prefix === "text") {
|
|
483
|
+
if (raw.startsWith("#"))
|
|
484
|
+
return { color: raw };
|
|
485
|
+
const n = parseFloat(raw.replace(/px$/, ""));
|
|
486
|
+
if (!isNaN(n))
|
|
487
|
+
return { fontSize: n };
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
// bg-[...]: color only
|
|
491
|
+
if (prefix === "bg") {
|
|
492
|
+
if (raw.startsWith("#"))
|
|
493
|
+
return { backgroundColor: raw };
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
// border-[...]: numeric → borderWidth, color → borderColor
|
|
497
|
+
if (prefix === "border") {
|
|
498
|
+
if (raw.startsWith("#"))
|
|
499
|
+
return { borderColor: raw };
|
|
500
|
+
const n = parseFloat(raw.replace(/px$/, ""));
|
|
501
|
+
if (!isNaN(n))
|
|
502
|
+
return { borderWidth: n };
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
// Numeric value (strip px suffix)
|
|
508
|
+
const n = parseFloat(raw.replace(/px$/, ""));
|
|
509
|
+
if (!isNaN(n))
|
|
510
|
+
return { [prop]: n };
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
// ── Main dispatcher ──────────────────────────────────────────────────
|
|
514
|
+
export function parseClass(cls) {
|
|
515
|
+
// Check for arbitrary bracket values first
|
|
516
|
+
if (cls.includes("["))
|
|
517
|
+
return parseArbitrary(cls);
|
|
518
|
+
return (parseSpacing(cls) ??
|
|
519
|
+
parseTypography(cls) ??
|
|
520
|
+
parseColorClass(cls) ??
|
|
521
|
+
parseLayout(cls) ??
|
|
522
|
+
parseGrid(cls) ??
|
|
523
|
+
parseSelf(cls) ??
|
|
524
|
+
parseBorder(cls) ??
|
|
525
|
+
parseOpacity(cls));
|
|
526
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export interface FormeStyle {
|
|
2
|
+
flexDirection?: "row" | "column" | "row-reverse" | "column-reverse";
|
|
3
|
+
alignItems?: "flex-start" | "flex-end" | "center" | "stretch" | "baseline";
|
|
4
|
+
justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
|
|
5
|
+
flex?: number;
|
|
6
|
+
flexGrow?: number;
|
|
7
|
+
flexShrink?: number;
|
|
8
|
+
flexBasis?: number | string;
|
|
9
|
+
flexWrap?: "nowrap" | "wrap" | "wrap-reverse";
|
|
10
|
+
gap?: number;
|
|
11
|
+
columnGap?: number;
|
|
12
|
+
rowGap?: number;
|
|
13
|
+
position?: "relative" | "absolute";
|
|
14
|
+
top?: number;
|
|
15
|
+
right?: number;
|
|
16
|
+
bottom?: number;
|
|
17
|
+
left?: number;
|
|
18
|
+
overflow?: "hidden" | "visible";
|
|
19
|
+
display?: "flex" | "grid";
|
|
20
|
+
alignSelf?: "flex-start" | "flex-end" | "center" | "stretch" | "baseline";
|
|
21
|
+
gridTemplateColumns?: string;
|
|
22
|
+
gridTemplateRows?: string;
|
|
23
|
+
gridColumnStart?: number;
|
|
24
|
+
gridColumnEnd?: number;
|
|
25
|
+
gridRowStart?: number;
|
|
26
|
+
gridRowEnd?: number;
|
|
27
|
+
gridColumnSpan?: number;
|
|
28
|
+
gridRowSpan?: number;
|
|
29
|
+
width?: number | string;
|
|
30
|
+
height?: number | string;
|
|
31
|
+
minWidth?: number | string;
|
|
32
|
+
maxWidth?: number | string;
|
|
33
|
+
minHeight?: number | string;
|
|
34
|
+
maxHeight?: number | string;
|
|
35
|
+
padding?: number | string;
|
|
36
|
+
paddingTop?: number;
|
|
37
|
+
paddingRight?: number;
|
|
38
|
+
paddingBottom?: number;
|
|
39
|
+
paddingLeft?: number;
|
|
40
|
+
paddingHorizontal?: number;
|
|
41
|
+
paddingVertical?: number;
|
|
42
|
+
margin?: number | string;
|
|
43
|
+
marginTop?: number | "auto";
|
|
44
|
+
marginRight?: number | "auto";
|
|
45
|
+
marginBottom?: number | "auto";
|
|
46
|
+
marginLeft?: number | "auto";
|
|
47
|
+
marginHorizontal?: number | "auto";
|
|
48
|
+
marginVertical?: number | "auto";
|
|
49
|
+
fontSize?: number;
|
|
50
|
+
fontWeight?: number | "normal" | "bold";
|
|
51
|
+
fontStyle?: "normal" | "italic" | "oblique";
|
|
52
|
+
textAlign?: "left" | "center" | "right" | "justify";
|
|
53
|
+
lineHeight?: number;
|
|
54
|
+
letterSpacing?: number;
|
|
55
|
+
textDecoration?: "none" | "underline" | "line-through";
|
|
56
|
+
textTransform?: "none" | "uppercase" | "lowercase" | "capitalize";
|
|
57
|
+
color?: string;
|
|
58
|
+
backgroundColor?: string;
|
|
59
|
+
borderWidth?: number;
|
|
60
|
+
borderTopWidth?: number;
|
|
61
|
+
borderRightWidth?: number;
|
|
62
|
+
borderBottomWidth?: number;
|
|
63
|
+
borderLeftWidth?: number;
|
|
64
|
+
borderColor?: string;
|
|
65
|
+
borderRadius?: number;
|
|
66
|
+
borderTopLeftRadius?: number;
|
|
67
|
+
borderTopRightRadius?: number;
|
|
68
|
+
borderBottomRightRadius?: number;
|
|
69
|
+
borderBottomLeftRadius?: number;
|
|
70
|
+
opacity?: number;
|
|
71
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@formepdf/tailwind",
|
|
3
|
+
"version": "0.7.10",
|
|
4
|
+
"description": "Tailwind CSS class support for Forme PDF templates",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"typescript": "^5.7.0",
|
|
21
|
+
"vitest": "^3.0.0"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/formepdf/forme",
|
|
30
|
+
"directory": "packages/tailwind"
|
|
31
|
+
}
|
|
32
|
+
}
|