@formepdf/tailwind 0.7.10 → 0.7.11
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/README.md +78 -0
- package/dist/parsers.js +32 -6
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @formepdf/tailwind
|
|
2
|
+
|
|
3
|
+
Style [Forme](https://formepdf.com) PDF components with Tailwind CSS utility classes.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @formepdf/tailwind
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { tw } from '@formepdf/tailwind';
|
|
11
|
+
import { Document, Page, View, Text } from '@formepdf/react';
|
|
12
|
+
|
|
13
|
+
<Document>
|
|
14
|
+
<Page size="Letter" margin={54}>
|
|
15
|
+
<View style={tw("flex-row items-center justify-between p-6 bg-slate-100 rounded-lg")}>
|
|
16
|
+
<Text style={tw("text-2xl font-bold text-slate-900")}>Invoice #001</Text>
|
|
17
|
+
<Text style={tw("text-sm text-slate-500")}>March 2026</Text>
|
|
18
|
+
</View>
|
|
19
|
+
</Page>
|
|
20
|
+
</Document>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`tw()` parses a space-separated string of Tailwind classes and returns a plain style object. Unknown classes are silently ignored. When classes conflict, the last one wins.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
tw("p-4 text-lg font-bold text-blue-500")
|
|
27
|
+
// → { padding: 16, fontSize: 18, fontWeight: 700, color: '#3b82f6' }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Supported classes
|
|
31
|
+
|
|
32
|
+
**Spacing** — `p-{n}`, `px-{n}`, `py-{n}`, `pt-{n}`, `m-{n}`, `mx-{n}`, `mx-auto`, `space-y-{n}`, `space-x-{n}`, negative values (`-mt-4`), `p-px`
|
|
33
|
+
|
|
34
|
+
**Typography** — `text-xs` through `text-9xl`, `font-thin` through `font-black`, `italic`, `text-left/center/right/justify`, `leading-*`, `tracking-*`, `underline`, `line-through`, `uppercase`, `lowercase`, `capitalize`
|
|
35
|
+
|
|
36
|
+
**Colors** — Full Tailwind palette (slate, gray, red, blue, etc.) with shades 50–950: `text-{color}-{shade}`, `bg-{color}-{shade}`, `border-{color}-{shade}`
|
|
37
|
+
|
|
38
|
+
**Layout** — `flex-row`, `flex-col`, `items-*`, `justify-*`, `self-*`, `flex-1`, `flex-wrap`, `gap-{n}`
|
|
39
|
+
|
|
40
|
+
**Dimensions** — `w-{n}`, `h-{n}`, `w-full`, `w-auto`, `w-1/2`, `min-w-{n}`, `max-w-{n}`
|
|
41
|
+
|
|
42
|
+
**Grid** — `grid`, `grid-cols-{n}`, `col-span-{n}`, `col-start-{n}`, `row-span-{n}`
|
|
43
|
+
|
|
44
|
+
**Borders** — `border`, `border-{n}`, `border-t`, `rounded`, `rounded-lg`, `rounded-full`
|
|
45
|
+
|
|
46
|
+
**Other** — `relative`, `absolute`, `top-{n}`, `overflow-hidden`, `opacity-{n}`
|
|
47
|
+
|
|
48
|
+
**Arbitrary values** — `w-[200]`, `text-[14px]`, `p-[20]`, `text-[#333]`, `bg-[#ff0000]`
|
|
49
|
+
|
|
50
|
+
## Auto margins
|
|
51
|
+
|
|
52
|
+
Horizontal centering with `mx-auto`:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<View style={tw("mx-auto w-64")}>
|
|
56
|
+
<Text>Centered content</Text>
|
|
57
|
+
</View>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Also supports `my-auto`, `mt-auto`, `mr-auto`, `mb-auto`, `ml-auto`, `m-auto`.
|
|
61
|
+
|
|
62
|
+
## TypeScript
|
|
63
|
+
|
|
64
|
+
`tw()` returns a `FormeStyle` compatible with Forme component `style` props — no type casting needed:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { tw, type FormeStyle } from '@formepdf/tailwind';
|
|
68
|
+
|
|
69
|
+
const style: FormeStyle = tw("p-4 bg-white rounded-lg");
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## What's not supported
|
|
73
|
+
|
|
74
|
+
Tailwind features that don't apply to PDF rendering: responsive prefixes (`sm:`, `md:`), state variants (`hover:`, `focus:`), dark mode, `z-index`, `aspect-ratio`.
|
|
75
|
+
|
|
76
|
+
## Docs
|
|
77
|
+
|
|
78
|
+
Full documentation: [docs.formepdf.com/tailwind](https://docs.formepdf.com/tailwind)
|
package/dist/parsers.js
CHANGED
|
@@ -45,9 +45,20 @@ function parseSpacing(cls) {
|
|
|
45
45
|
return null;
|
|
46
46
|
}
|
|
47
47
|
// ── Typography ───────────────────────────────────────────────────────
|
|
48
|
-
const
|
|
49
|
-
xs:
|
|
50
|
-
|
|
48
|
+
const textSizeDefaults = {
|
|
49
|
+
xs: { fontSize: 12, lineHeight: 16 },
|
|
50
|
+
sm: { fontSize: 14, lineHeight: 20 },
|
|
51
|
+
base: { fontSize: 16, lineHeight: 24 },
|
|
52
|
+
lg: { fontSize: 18, lineHeight: 28 },
|
|
53
|
+
xl: { fontSize: 20, lineHeight: 28 },
|
|
54
|
+
"2xl": { fontSize: 24, lineHeight: 32 },
|
|
55
|
+
"3xl": { fontSize: 30, lineHeight: 36 },
|
|
56
|
+
"4xl": { fontSize: 36, lineHeight: 40 },
|
|
57
|
+
"5xl": { fontSize: 48, lineHeight: 48 },
|
|
58
|
+
"6xl": { fontSize: 60, lineHeight: 60 },
|
|
59
|
+
"7xl": { fontSize: 72, lineHeight: 72 },
|
|
60
|
+
"8xl": { fontSize: 96, lineHeight: 96 },
|
|
61
|
+
"9xl": { fontSize: 128, lineHeight: 128 },
|
|
51
62
|
};
|
|
52
63
|
const fontWeights = {
|
|
53
64
|
thin: 100, extralight: 200, light: 300, normal: 400, medium: 500,
|
|
@@ -63,8 +74,9 @@ function parseTypography(cls) {
|
|
|
63
74
|
// text-{size}
|
|
64
75
|
if (cls.startsWith("text-")) {
|
|
65
76
|
const rest = cls.substring(5);
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
const def = textSizeDefaults[rest];
|
|
78
|
+
if (def)
|
|
79
|
+
return { fontSize: def.fontSize, lineHeight: def.lineHeight };
|
|
68
80
|
// text-left/center/right/justify
|
|
69
81
|
if (rest === "left" || rest === "center" || rest === "right" || rest === "justify") {
|
|
70
82
|
return { textAlign: rest };
|
|
@@ -123,7 +135,7 @@ function parseColorClass(cls) {
|
|
|
123
135
|
if (cls.startsWith("text-")) {
|
|
124
136
|
const rest = cls.substring(5);
|
|
125
137
|
// Skip size and alignment keywords
|
|
126
|
-
if (
|
|
138
|
+
if (textSizeDefaults[rest] !== undefined)
|
|
127
139
|
return null;
|
|
128
140
|
if (rest === "left" || rest === "center" || rest === "right" || rest === "justify")
|
|
129
141
|
return null;
|
|
@@ -226,6 +238,19 @@ function parseLayout(cls) {
|
|
|
226
238
|
return { flexWrap: "wrap" };
|
|
227
239
|
if (cls === "flex-nowrap")
|
|
228
240
|
return { flexWrap: "nowrap" };
|
|
241
|
+
// space-y-{n} / space-x-{n} → map to gap (flex container spacing)
|
|
242
|
+
if (cls.startsWith("space-y-")) {
|
|
243
|
+
const n = parseFloat(cls.substring(8));
|
|
244
|
+
if (!isNaN(n))
|
|
245
|
+
return { rowGap: n * 4 };
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
if (cls.startsWith("space-x-")) {
|
|
249
|
+
const n = parseFloat(cls.substring(8));
|
|
250
|
+
if (!isNaN(n))
|
|
251
|
+
return { columnGap: n * 4 };
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
229
254
|
// gap
|
|
230
255
|
if (cls.startsWith("gap-x-")) {
|
|
231
256
|
const n = parseFloat(cls.substring(6));
|
|
@@ -460,6 +485,7 @@ const arbitraryPrefixMap = {
|
|
|
460
485
|
m: "margin", mx: "marginHorizontal", my: "marginVertical",
|
|
461
486
|
mt: "marginTop", mr: "marginRight", mb: "marginBottom", ml: "marginLeft",
|
|
462
487
|
gap: "gap", "gap-x": "columnGap", "gap-y": "rowGap",
|
|
488
|
+
"space-x": "columnGap", "space-y": "rowGap",
|
|
463
489
|
top: "top", right: "right", bottom: "bottom", left: "left",
|
|
464
490
|
rounded: "borderRadius",
|
|
465
491
|
opacity: "opacity",
|