@itamarshdev/reactwind 0.1.1

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 ADDED
@@ -0,0 +1,106 @@
1
+ # 🚀 ReactWind
2
+
3
+ [![Version](https://img.shields.io/npm/v/reactwind)](https://www.npmjs.com/package/reactwind)
4
+ [![License](https://img.shields.io/npm/l/reactwind)](https://github.com/reactwind/reactwind/blob/main/LICENSE)
5
+ [![Demo](https://img.shields.io/badge/storybook-demo-FF4785?logo=storybook)](https://itamarsharify.github.io/reactwind/storybook/index.html)
6
+ [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
7
+
8
+ **ReactWind** is a JSX runtime wrapper that brings the power of Tailwind CSS shorthands and array-based classNames directly to your React components. No more template literal spaghetti or complex utility merges.
9
+
10
+ ---
11
+
12
+ ## 📦 Installation
13
+
14
+ ```bash
15
+ npm install reactwind
16
+ # or
17
+ bun add reactwind
18
+ # or
19
+ yarn add reactwind
20
+ ```
21
+
22
+
23
+ ## ✨ Features
24
+
25
+ - 🎯 **Prop-based Styling**: Use Tailwind utilities as props: `<div flex bg="blue-500" p={4} />`.
26
+ - 🧬 **Array ClassNames**: Pass classes as clean arrays: `classNames={['text-center', isActive && 'font-bold']}`.
27
+ - 💨 **Zero Runtime (Concept)**: Designed for minimal overhead. Most transformations happen at the JSX level.
28
+ - 📘 **TypeScript First**: Automatic types for nearly all Tailwind utilities.
29
+ - 🔌 **Framework Agnostic**: Works with Vite, Next.js, and any stack supporting custom JSX runtimes.
30
+
31
+ ---
32
+
33
+
34
+ ## 🛠 Setup
35
+
36
+ Configure your build tool to use `reactwind` as your JSX import source.
37
+
38
+ ### Vite
39
+
40
+ ```typescript
41
+ // vite.config.ts
42
+ export default defineConfig({
43
+ esbuild: {
44
+ jsxImportSource: 'reactwind',
45
+ },
46
+ });
47
+ ```
48
+
49
+ ### TypeScript
50
+
51
+ ```json
52
+ // tsconfig.json
53
+ {
54
+ "compilerOptions": {
55
+ "jsx": "react-jsx",
56
+ "jsxImportSource": "reactwind"
57
+ }
58
+ }
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 📖 Usage Examples
64
+
65
+ ### 1. Shorthand Props & Booleans
66
+
67
+ ```tsx
68
+ // Instead of <div className="flex items-center justify-between p-4">
69
+ <div flex items-center justify-between p={4}>
70
+ <span>Header</span>
71
+ <button bg="blue-600" text="white" px={3} py={1} rounded="md">Click Me</button>
72
+ </div>
73
+ ```
74
+
75
+ ### 2. Array-based ClassNames
76
+
77
+ ```tsx
78
+ <div
79
+ classNames={[
80
+ 'transition-all duration-300',
81
+ isHovered ? 'scale-105 shadow-lg' : 'scale-100 shadow-sm',
82
+ customClass && customClass
83
+ ]}
84
+ >
85
+ Card Content
86
+ </div>
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 🎯 Goals
92
+
93
+ ReactWind aims to improve the developer experience of styling with Tailwind CSS by:
94
+ 1. **Removing syntactic noise**: Replacing long `className` strings with structured props.
95
+ 2. **Improving modifiability**: Making it easier to toggle styles based on props without complex string manipulation.
96
+ 3. **Enhancing discoverability**: leveraging TypeScript to provide autocompletion for styling props.
97
+
98
+ ---
99
+
100
+ ## 🤝 Contributing
101
+
102
+ Contributions are welcome! Please feel free to submit a Pull Request.
103
+
104
+ ## 📄 License
105
+
106
+ MIT © [reactwind](https://github.com/reactwind/reactwind)
@@ -0,0 +1,161 @@
1
+ // src/runtime.ts
2
+ var LAYOUT_PROPS = [
3
+ "flex",
4
+ "grid",
5
+ "hidden",
6
+ "block",
7
+ "inline",
8
+ "inline-block",
9
+ "inline-flex",
10
+ "inline-grid",
11
+ "relative",
12
+ "absolute",
13
+ "fixed",
14
+ "sticky",
15
+ "static",
16
+ "flex-row",
17
+ "flex-col",
18
+ "flex-wrap",
19
+ "flex-nowrap",
20
+ "items-center",
21
+ "items-start",
22
+ "items-end",
23
+ "justify-center",
24
+ "justify-between",
25
+ "justify-start",
26
+ "justify-end",
27
+ "grow",
28
+ "shrink",
29
+ "italic",
30
+ "not-italic",
31
+ "underline",
32
+ "uppercase",
33
+ "lowercase",
34
+ "capitalize",
35
+ "truncate",
36
+ "visible",
37
+ "invisible",
38
+ "collapse",
39
+ "pointer-events-none",
40
+ "pointer-events-auto",
41
+ "sr-only",
42
+ "not-sr-only"
43
+ ];
44
+ var VALUE_PROPS_MAP = {
45
+ bg: "bg",
46
+ text: "text",
47
+ border: "border",
48
+ fill: "fill",
49
+ stroke: "stroke",
50
+ p: "p",
51
+ m: "m",
52
+ px: "px",
53
+ py: "py",
54
+ mx: "mx",
55
+ my: "my",
56
+ gap: "gap",
57
+ w: "w",
58
+ h: "h",
59
+ rounded: "rounded",
60
+ shadow: "shadow",
61
+ font: "font",
62
+ z: "z",
63
+ mb: "mb",
64
+ mt: "mt",
65
+ ml: "ml",
66
+ mr: "mr",
67
+ pb: "pb",
68
+ pt: "pt",
69
+ pl: "pl",
70
+ pr: "pr",
71
+ tracking: "tracking",
72
+ leading: "leading",
73
+ "max-w": "max-w",
74
+ "min-w": "min-w",
75
+ "min-h": "min-h",
76
+ "max-h": "max-h",
77
+ overflow: "overflow",
78
+ decoration: "decoration",
79
+ whitespace: "whitespace",
80
+ break: "break",
81
+ content: "content",
82
+ opacity: "opacity",
83
+ "bg-opacity": "bg-opacity",
84
+ ring: "ring",
85
+ "ring-offset": "ring-offset",
86
+ outline: "outline",
87
+ divide: "divide",
88
+ "mix-blend": "mix-blend",
89
+ "backdrop-blur": "backdrop-blur",
90
+ blur: "blur",
91
+ brightness: "brightness",
92
+ contrast: "contrast",
93
+ grayscale: "grayscale",
94
+ "hue-rotate": "hue-rotate",
95
+ invert: "invert",
96
+ saturate: "saturate",
97
+ sepia: "sepia",
98
+ "drop-shadow": "drop-shadow",
99
+ transition: "transition",
100
+ duration: "duration",
101
+ ease: "ease",
102
+ delay: "delay",
103
+ animate: "animate",
104
+ cursor: "cursor",
105
+ "pointer-events": "pointer-events",
106
+ resize: "resize",
107
+ select: "select",
108
+ scale: "scale",
109
+ rotate: "rotate",
110
+ translate: "translate",
111
+ skew: "skew",
112
+ origin: "origin"
113
+ };
114
+ var joinClassNames = (classNames) => {
115
+ if (!classNames || classNames.length === 0) {
116
+ return "";
117
+ }
118
+ return classNames.filter(Boolean).join(" ");
119
+ };
120
+ var withClassNames = (props) => {
121
+ if (!props) {
122
+ return props;
123
+ }
124
+ const hasClassNames = "classNames" in props;
125
+ const hasLayoutProps = LAYOUT_PROPS.some((k) => k in props);
126
+ const hasValueProps = Object.keys(VALUE_PROPS_MAP).some((k) => k in props);
127
+ if (!hasClassNames && !hasLayoutProps && !hasValueProps) {
128
+ return props;
129
+ }
130
+ const { classNames, className, ...rest } = props;
131
+ const generatedClasses = [];
132
+ const cleanRest = { ...rest };
133
+ for (const prop of LAYOUT_PROPS) {
134
+ if (prop in cleanRest && cleanRest[prop] === true) {
135
+ generatedClasses.push(prop);
136
+ delete cleanRest[prop];
137
+ }
138
+ }
139
+ for (const [prop, prefix] of Object.entries(VALUE_PROPS_MAP)) {
140
+ if (prop in cleanRest) {
141
+ const value = cleanRest[prop];
142
+ if (typeof value === "string" || typeof value === "number") {
143
+ generatedClasses.push(`${prefix}-${value}`);
144
+ delete cleanRest[prop];
145
+ } else if (value === true && (prop === "shadow" || prop === "rounded")) {
146
+ generatedClasses.push(prop);
147
+ delete cleanRest[prop];
148
+ }
149
+ }
150
+ }
151
+ const joined = joinClassNames(classNames || []);
152
+ const merged = [className, ...generatedClasses, joined].filter(Boolean).join(" ");
153
+ return {
154
+ ...cleanRest,
155
+ ...merged ? { className: merged } : {}
156
+ };
157
+ };
158
+
159
+ export {
160
+ withClassNames
161
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ withClassNames: () => withClassNames
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/runtime.ts
28
+ var LAYOUT_PROPS = [
29
+ "flex",
30
+ "grid",
31
+ "hidden",
32
+ "block",
33
+ "inline",
34
+ "inline-block",
35
+ "inline-flex",
36
+ "inline-grid",
37
+ "relative",
38
+ "absolute",
39
+ "fixed",
40
+ "sticky",
41
+ "static",
42
+ "flex-row",
43
+ "flex-col",
44
+ "flex-wrap",
45
+ "flex-nowrap",
46
+ "items-center",
47
+ "items-start",
48
+ "items-end",
49
+ "justify-center",
50
+ "justify-between",
51
+ "justify-start",
52
+ "justify-end",
53
+ "grow",
54
+ "shrink",
55
+ "italic",
56
+ "not-italic",
57
+ "underline",
58
+ "uppercase",
59
+ "lowercase",
60
+ "capitalize",
61
+ "truncate",
62
+ "visible",
63
+ "invisible",
64
+ "collapse",
65
+ "pointer-events-none",
66
+ "pointer-events-auto",
67
+ "sr-only",
68
+ "not-sr-only"
69
+ ];
70
+ var VALUE_PROPS_MAP = {
71
+ bg: "bg",
72
+ text: "text",
73
+ border: "border",
74
+ fill: "fill",
75
+ stroke: "stroke",
76
+ p: "p",
77
+ m: "m",
78
+ px: "px",
79
+ py: "py",
80
+ mx: "mx",
81
+ my: "my",
82
+ gap: "gap",
83
+ w: "w",
84
+ h: "h",
85
+ rounded: "rounded",
86
+ shadow: "shadow",
87
+ font: "font",
88
+ z: "z",
89
+ mb: "mb",
90
+ mt: "mt",
91
+ ml: "ml",
92
+ mr: "mr",
93
+ pb: "pb",
94
+ pt: "pt",
95
+ pl: "pl",
96
+ pr: "pr",
97
+ tracking: "tracking",
98
+ leading: "leading",
99
+ "max-w": "max-w",
100
+ "min-w": "min-w",
101
+ "min-h": "min-h",
102
+ "max-h": "max-h",
103
+ overflow: "overflow",
104
+ decoration: "decoration",
105
+ whitespace: "whitespace",
106
+ break: "break",
107
+ content: "content",
108
+ opacity: "opacity",
109
+ "bg-opacity": "bg-opacity",
110
+ ring: "ring",
111
+ "ring-offset": "ring-offset",
112
+ outline: "outline",
113
+ divide: "divide",
114
+ "mix-blend": "mix-blend",
115
+ "backdrop-blur": "backdrop-blur",
116
+ blur: "blur",
117
+ brightness: "brightness",
118
+ contrast: "contrast",
119
+ grayscale: "grayscale",
120
+ "hue-rotate": "hue-rotate",
121
+ invert: "invert",
122
+ saturate: "saturate",
123
+ sepia: "sepia",
124
+ "drop-shadow": "drop-shadow",
125
+ transition: "transition",
126
+ duration: "duration",
127
+ ease: "ease",
128
+ delay: "delay",
129
+ animate: "animate",
130
+ cursor: "cursor",
131
+ "pointer-events": "pointer-events",
132
+ resize: "resize",
133
+ select: "select",
134
+ scale: "scale",
135
+ rotate: "rotate",
136
+ translate: "translate",
137
+ skew: "skew",
138
+ origin: "origin"
139
+ };
140
+ var joinClassNames = (classNames) => {
141
+ if (!classNames || classNames.length === 0) {
142
+ return "";
143
+ }
144
+ return classNames.filter(Boolean).join(" ");
145
+ };
146
+ var withClassNames = (props) => {
147
+ if (!props) {
148
+ return props;
149
+ }
150
+ const hasClassNames = "classNames" in props;
151
+ const hasLayoutProps = LAYOUT_PROPS.some((k) => k in props);
152
+ const hasValueProps = Object.keys(VALUE_PROPS_MAP).some((k) => k in props);
153
+ if (!hasClassNames && !hasLayoutProps && !hasValueProps) {
154
+ return props;
155
+ }
156
+ const { classNames, className, ...rest } = props;
157
+ const generatedClasses = [];
158
+ const cleanRest = { ...rest };
159
+ for (const prop of LAYOUT_PROPS) {
160
+ if (prop in cleanRest && cleanRest[prop] === true) {
161
+ generatedClasses.push(prop);
162
+ delete cleanRest[prop];
163
+ }
164
+ }
165
+ for (const [prop, prefix] of Object.entries(VALUE_PROPS_MAP)) {
166
+ if (prop in cleanRest) {
167
+ const value = cleanRest[prop];
168
+ if (typeof value === "string" || typeof value === "number") {
169
+ generatedClasses.push(`${prefix}-${value}`);
170
+ delete cleanRest[prop];
171
+ } else if (value === true && (prop === "shadow" || prop === "rounded")) {
172
+ generatedClasses.push(prop);
173
+ delete cleanRest[prop];
174
+ }
175
+ }
176
+ }
177
+ const joined = joinClassNames(classNames || []);
178
+ const merged = [className, ...generatedClasses, joined].filter(Boolean).join(" ");
179
+ return {
180
+ ...cleanRest,
181
+ ...merged ? { className: merged } : {}
182
+ };
183
+ };
184
+ // Annotate the CommonJS export names for ESM import in node:
185
+ 0 && (module.exports = {
186
+ withClassNames
187
+ });
@@ -0,0 +1,61 @@
1
+ import { T as TailwindColor, a as TailwindSpacing, b as TailwindRadius, c as TailwindShadow, d as TailwindClass } from './tailwind.types-BSQudz76.cjs';
2
+
3
+ interface ValueProps {
4
+ bg?: TailwindColor | string;
5
+ text?: TailwindColor | string;
6
+ border?: TailwindColor | string;
7
+ fill?: TailwindColor | string;
8
+ stroke?: TailwindColor | string;
9
+ font?: string;
10
+ p?: TailwindSpacing | string;
11
+ m?: TailwindSpacing | string;
12
+ px?: TailwindSpacing | string;
13
+ py?: TailwindSpacing | string;
14
+ mx?: TailwindSpacing | string;
15
+ my?: TailwindSpacing | string;
16
+ gap?: TailwindSpacing | string;
17
+ w?: TailwindSpacing | string;
18
+ h?: TailwindSpacing | string;
19
+ rounded?: TailwindRadius | string;
20
+ shadow?: TailwindShadow | boolean | string;
21
+ }
22
+
23
+ interface LayoutProps {
24
+ flex?: boolean;
25
+ grid?: boolean;
26
+ hidden?: boolean;
27
+ block?: boolean;
28
+ inline?: boolean;
29
+ "inline-block"?: boolean;
30
+ "inline-flex"?: boolean;
31
+ "inline-grid"?: boolean;
32
+ relative?: boolean;
33
+ absolute?: boolean;
34
+ fixed?: boolean;
35
+ sticky?: boolean;
36
+ static?: boolean;
37
+ "flex-row"?: boolean;
38
+ "flex-col"?: boolean;
39
+ "flex-wrap"?: boolean;
40
+ "flex-nowrap"?: boolean;
41
+ "items-center"?: boolean;
42
+ "items-start"?: boolean;
43
+ "items-end"?: boolean;
44
+ "justify-center"?: boolean;
45
+ "justify-between"?: boolean;
46
+ "justify-start"?: boolean;
47
+ "justify-end"?: boolean;
48
+ grow?: boolean;
49
+ shrink?: boolean;
50
+ }
51
+
52
+ declare module "react" {
53
+ interface HTMLAttributes<T> extends LayoutProps, ValueProps {
54
+ classNames?: (TailwindClass | string)[];
55
+ }
56
+ interface SVGAttributes<T> extends LayoutProps, ValueProps {
57
+ classNames?: (TailwindClass | string)[];
58
+ }
59
+ }
60
+
61
+ export type { LayoutProps, ValueProps };
@@ -0,0 +1,61 @@
1
+ import { T as TailwindColor, a as TailwindSpacing, b as TailwindRadius, c as TailwindShadow, d as TailwindClass } from './tailwind.types-BSQudz76.js';
2
+
3
+ interface ValueProps {
4
+ bg?: TailwindColor | string;
5
+ text?: TailwindColor | string;
6
+ border?: TailwindColor | string;
7
+ fill?: TailwindColor | string;
8
+ stroke?: TailwindColor | string;
9
+ font?: string;
10
+ p?: TailwindSpacing | string;
11
+ m?: TailwindSpacing | string;
12
+ px?: TailwindSpacing | string;
13
+ py?: TailwindSpacing | string;
14
+ mx?: TailwindSpacing | string;
15
+ my?: TailwindSpacing | string;
16
+ gap?: TailwindSpacing | string;
17
+ w?: TailwindSpacing | string;
18
+ h?: TailwindSpacing | string;
19
+ rounded?: TailwindRadius | string;
20
+ shadow?: TailwindShadow | boolean | string;
21
+ }
22
+
23
+ interface LayoutProps {
24
+ flex?: boolean;
25
+ grid?: boolean;
26
+ hidden?: boolean;
27
+ block?: boolean;
28
+ inline?: boolean;
29
+ "inline-block"?: boolean;
30
+ "inline-flex"?: boolean;
31
+ "inline-grid"?: boolean;
32
+ relative?: boolean;
33
+ absolute?: boolean;
34
+ fixed?: boolean;
35
+ sticky?: boolean;
36
+ static?: boolean;
37
+ "flex-row"?: boolean;
38
+ "flex-col"?: boolean;
39
+ "flex-wrap"?: boolean;
40
+ "flex-nowrap"?: boolean;
41
+ "items-center"?: boolean;
42
+ "items-start"?: boolean;
43
+ "items-end"?: boolean;
44
+ "justify-center"?: boolean;
45
+ "justify-between"?: boolean;
46
+ "justify-start"?: boolean;
47
+ "justify-end"?: boolean;
48
+ grow?: boolean;
49
+ shrink?: boolean;
50
+ }
51
+
52
+ declare module "react" {
53
+ interface HTMLAttributes<T> extends LayoutProps, ValueProps {
54
+ classNames?: (TailwindClass | string)[];
55
+ }
56
+ interface SVGAttributes<T> extends LayoutProps, ValueProps {
57
+ classNames?: (TailwindClass | string)[];
58
+ }
59
+ }
60
+
61
+ export type { LayoutProps, ValueProps };
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import {
2
+ withClassNames
3
+ } from "./chunk-WXTVOZ4W.js";
4
+ export {
5
+ withClassNames
6
+ };