teawind-engine 1.0.0 → 1.0.2
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 +206 -62
- package/demo.html +395 -0
- package/package.json +32 -37
- package/src/core/observer.js +170 -0
- package/src/index.js +98 -125
- package/vitest.config.js +10 -0
- package/src/core/style.css +0 -0
package/README.md
CHANGED
|
@@ -2,28 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
A lightweight utility-first CSS engine. Build UIs using `chai-*` classes without writing CSS!
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
* 🚀 **Zero Configuration** - Just add classes and they work
|
|
8
|
+
|
|
9
|
+
* 📦 **Lightweight** - No CSS files to manage, pure JavaScript
|
|
10
|
+
|
|
11
|
+
* 🎨 **Utility-First** - Build complex UIs with simple classes
|
|
12
|
+
|
|
13
|
+
* 🔄 **Dynamic** - Works with dynamically added elements
|
|
14
|
+
|
|
15
|
+
* 🎯 **No Dependencies** - Pure vanilla JavaScript
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## 📦 Installation
|
|
19
|
+
|
|
20
|
+
### NPM
|
|
6
21
|
|
|
7
22
|
```bash
|
|
8
|
-
npm install teawind
|
|
23
|
+
npm install teawind-engine
|
|
24
|
+
```
|
|
9
25
|
|
|
10
|
-
|
|
26
|
+
### **CDN**
|
|
11
27
|
|
|
28
|
+
```plaintext
|
|
12
29
|
<script type="module">
|
|
13
|
-
import { initTeawind } from 'https://cdn.jsdelivr.net/npm/teawind@1.0.0/src/index.js';
|
|
30
|
+
import { initTeawind } from 'https://cdn.jsdelivr.net/npm/teawind-engine@1.0.0/src/index.js';
|
|
14
31
|
initTeawind();
|
|
15
32
|
</script>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### **GitHub**
|
|
16
36
|
|
|
17
|
-
|
|
37
|
+
```plaintext
|
|
38
|
+
git clone https://github.com/ravi8555/teawind-engine.git
|
|
39
|
+
```
|
|
18
40
|
|
|
19
|
-
|
|
41
|
+
### **🚀 Usage**
|
|
20
42
|
|
|
43
|
+
**Basic Setup**
|
|
44
|
+
|
|
45
|
+
```plaintext
|
|
21
46
|
<!DOCTYPE html>
|
|
22
47
|
<html>
|
|
23
48
|
<head>
|
|
24
49
|
<title>Teawind Demo</title>
|
|
25
50
|
<script type="module">
|
|
26
|
-
import { initTeawind } from 'teawind';
|
|
51
|
+
import { initTeawind } from 'teawind-engine';
|
|
27
52
|
|
|
28
53
|
// Initialize the engine
|
|
29
54
|
initTeawind();
|
|
@@ -35,83 +60,202 @@ Basic Setup
|
|
|
35
60
|
</div>
|
|
36
61
|
</body>
|
|
37
62
|
</html>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### **🎨 Available Classes**
|
|
66
|
+
|
|
67
|
+
**Colors**
|
|
68
|
+
|
|
69
|
+
| **Class** | **Effect** |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `chai-bg-red` | Background: red |
|
|
72
|
+
| `chai-bg-blue` | Background: blue |
|
|
73
|
+
| `chai-bg-green` | Background: green |
|
|
74
|
+
| `chai-bg-yellow` | Background: yellow |
|
|
75
|
+
| `chai-bg-gray` | Background: gray |
|
|
76
|
+
| `chai-bg-black` | Background: black |
|
|
77
|
+
| `chai-bg-white` | Background: white |
|
|
78
|
+
| `chai-text-red` | Text: red |
|
|
79
|
+
| `chai-text-blue` | Text: blue |
|
|
80
|
+
| `chai-text-green` | Text: green |
|
|
81
|
+
| `chai-text-yellow` | Text: yellow |
|
|
82
|
+
| `chai-text-gray` | Text: gray |
|
|
83
|
+
| `chai-text-black` | Text: black |
|
|
84
|
+
| `chai-text-white` | Text: white |
|
|
85
|
+
|
|
86
|
+
### **Spacing (1 unit = 4px)**
|
|
87
|
+
|
|
88
|
+
| **Class** | **CSS Output** |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `chai-p-10` | `padding: 40px` |
|
|
91
|
+
| `chai-p-20` | `padding: 80px` |
|
|
92
|
+
| `chai-p-50` | `padding: 200px` |
|
|
93
|
+
| `chai-m-10` | `margin: 40px` |
|
|
94
|
+
| `chai-m-20` | `margin: 80px` |
|
|
95
|
+
| `chai-px-30` | `padding-left/right: 120px` |
|
|
96
|
+
| `chai-py-15` | `padding-top/bottom: 60px` |
|
|
97
|
+
| `chai-mt-10` | `margin-top: 40px` |
|
|
98
|
+
| `chai-mb-20` | `margin-bottom: 80px` |
|
|
99
|
+
| `chai-ml-10` | `margin-left: 40px` |
|
|
100
|
+
| `chai-mr-20` | `margin-right: 80px` |
|
|
101
|
+
|
|
102
|
+
### **Typography**
|
|
103
|
+
|
|
104
|
+
| **Class** | **Effect** |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `chai-text-16` | `font-size: 16px` |
|
|
107
|
+
| `chai-text-24` | `font-size: 24px` |
|
|
108
|
+
| `chai-font-bold` | `font-weight: bold` |
|
|
109
|
+
| `chai-text-center` | `text-align: center` |
|
|
110
|
+
| `chai-text-left` | `text-align: left` |
|
|
111
|
+
| `chai-text-right` | `text-align: right` |
|
|
112
|
+
|
|
113
|
+
### **Layout & Flexbox**
|
|
114
|
+
|
|
115
|
+
| **Class** | **Effect** |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| `chai-flex` | `display: flex` |
|
|
118
|
+
| `chai-flex-col` | `flex-direction: column` |
|
|
119
|
+
| `chai-flex-center` | Centered flex items |
|
|
120
|
+
| `chai-justify-between` | `justify-content: space-between` |
|
|
121
|
+
| `chai-gap-10` | `gap: 10px` |
|
|
122
|
+
|
|
123
|
+
### **Borders & Radius**
|
|
124
|
+
|
|
125
|
+
| **Class** | **Effect** |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `chai-border-2` | `border-width: 2px` |
|
|
128
|
+
| `chai-border-4` | `border-width: 4px` |
|
|
129
|
+
| `chai-rounded-10` | `border-radius: 10px` |
|
|
130
|
+
| `chai-rounded-20` | `border-radius: 20px` |
|
|
131
|
+
| `chai-border-red` | `border-color: red` |
|
|
132
|
+
|
|
133
|
+
### **Transforms**
|
|
134
|
+
|
|
135
|
+
| **Class** | **Effect** |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| `chai-scale-2` | `transform: scale(2)` |
|
|
138
|
+
| `chai-scale-3` | `transform: scale(3)` |
|
|
139
|
+
| `chai-scale-1` | `transform: scale(1)` |
|
|
140
|
+
| `chai-rotate-45` | `transform: rotate(45deg)` |
|
|
141
|
+
| `chai-rotate-90` | `transform: rotate(90deg)` |
|
|
142
|
+
|
|
143
|
+
### **Hover Effects**
|
|
144
|
+
|
|
145
|
+
| **Class** | **Effect on Hover** |
|
|
146
|
+
| --- | --- |
|
|
147
|
+
| `chai-hover-scale` | Zoom effect (scale 1.05) |
|
|
148
|
+
| `chai-hover-bg-red` | Background changes to red |
|
|
149
|
+
| `chai-hover-text-white` | Text color changes to white |
|
|
150
|
+
| `chai-hover-shadow` | Box shadow appears |
|
|
151
|
+
| `chai-hover-border` | Border becomes red |
|
|
152
|
+
|
|
153
|
+
## **📖 API**
|
|
154
|
+
|
|
155
|
+
### `initTeawind(container)`
|
|
38
156
|
|
|
39
|
-
|
|
40
|
-
Colors
|
|
41
|
-
chai-bg-red, chai-bg-blue, chai-bg-green, chai-bg-yellow, chai-bg-gray, chai-bg-black, chai-bg-white
|
|
157
|
+
Initializes Teawind on the specified container (defaults to document.body).
|
|
42
158
|
|
|
43
|
-
|
|
159
|
+
```plaintext
|
|
160
|
+
import { initTeawind } from 'teawind-engine';
|
|
44
161
|
|
|
45
|
-
|
|
46
|
-
|
|
162
|
+
// Initialize on entire document
|
|
163
|
+
initTeawind();
|
|
47
164
|
|
|
48
|
-
|
|
165
|
+
// Initialize on specific container only
|
|
166
|
+
initTeawind(document.querySelector('#app'));
|
|
167
|
+
```
|
|
49
168
|
|
|
50
|
-
|
|
169
|
+
### `applyStyles(element)`
|
|
51
170
|
|
|
52
|
-
|
|
171
|
+
Manually apply Teawind styles to an element.
|
|
53
172
|
|
|
54
|
-
|
|
55
|
-
|
|
173
|
+
```plaintext
|
|
174
|
+
import { applyStyles } from 'teawind-engine';
|
|
56
175
|
|
|
57
|
-
|
|
176
|
+
const element = document.querySelector('.my-element');
|
|
177
|
+
applyStyles(element);
|
|
178
|
+
```
|
|
58
179
|
|
|
59
|
-
|
|
180
|
+
## **💡 Examples**
|
|
60
181
|
|
|
61
|
-
|
|
62
|
-
chai-flex, chai-flex-col, chai-flex-center
|
|
182
|
+
### **Interactive Card**
|
|
63
183
|
|
|
64
|
-
|
|
184
|
+
```plaintext
|
|
185
|
+
<div class="chai-bg-white chai-rounded-20 chai-p-20 chai-hover-shadow">
|
|
186
|
+
<h2 class="chai-text-24 chai-font-bold">Interactive Card</h2>
|
|
187
|
+
<p class="chai-text-16 chai-mt-10">Hover me for shadow effect!</p>
|
|
188
|
+
<button class="chai-bg-blue chai-text-white chai-rounded-10 chai-p-10 chai-mt-10 chai-hover-scale">
|
|
189
|
+
Click Me
|
|
190
|
+
</button>
|
|
191
|
+
</div>
|
|
192
|
+
```
|
|
65
193
|
|
|
66
|
-
|
|
194
|
+
### **Flex Layout**
|
|
67
195
|
|
|
68
|
-
|
|
69
|
-
chai-
|
|
196
|
+
```plaintext
|
|
197
|
+
<div class="chai-flex chai-justify-between chai-gap-10">
|
|
198
|
+
<div class="chai-bg-red chai-text-white chai-p-20">Item 1</div>
|
|
199
|
+
<div class="chai-bg-green chai-text-white chai-p-20">Item 2</div>
|
|
200
|
+
<div class="chai-bg-blue chai-text-white chai-p-20">Item 3</div>
|
|
201
|
+
</div>
|
|
202
|
+
```
|
|
70
203
|
|
|
71
|
-
|
|
204
|
+
## **🔧 Development**
|
|
72
205
|
|
|
73
|
-
|
|
206
|
+
### **Clone the repository**
|
|
74
207
|
|
|
75
|
-
|
|
76
|
-
chai-scale-2, chai-scale-3, chai-scale-1
|
|
208
|
+
git clone https://github.com/ravi8555/teawind-engine.git
|
|
77
209
|
|
|
78
|
-
|
|
210
|
+
### **Navigate to project**
|
|
79
211
|
|
|
80
|
-
|
|
81
|
-
chai-hover-scale → zoom effect
|
|
212
|
+
cd teawind-engine
|
|
82
213
|
|
|
83
|
-
|
|
214
|
+
### **Install dependencies**
|
|
84
215
|
|
|
85
|
-
|
|
216
|
+
npm install
|
|
86
217
|
|
|
87
|
-
|
|
218
|
+
### **Run tests**
|
|
88
219
|
|
|
89
|
-
|
|
220
|
+
npm test
|
|
90
221
|
|
|
91
|
-
|
|
92
|
-
initTeawind(container)
|
|
93
|
-
Initializes Teawind on the specified container (defaults to document.body).
|
|
222
|
+
### **Run visual demo**
|
|
94
223
|
|
|
95
|
-
|
|
96
|
-
import { initTeawind } from 'teawind';
|
|
97
|
-
initTeawind();
|
|
98
|
-
applyStyles(element)
|
|
99
|
-
Manually apply Teawind styles to an element.
|
|
224
|
+
npx http-server -o demo.html
|
|
100
225
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
226
|
+
## 🤝 Contributing\*\*
|
|
227
|
+
|
|
228
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
229
|
+
|
|
230
|
+
1. Fork the repository
|
|
231
|
+
|
|
232
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
233
|
+
|
|
234
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
235
|
+
|
|
236
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
237
|
+
|
|
238
|
+
5. Open a Pull Request
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
## **📄 License**
|
|
242
|
+
|
|
243
|
+
MIT © [Ravindra Dhadave](https://github.com/ravi8555)
|
|
244
|
+
|
|
245
|
+
* * *
|
|
246
|
+
|
|
247
|
+
Made with ❤️ by [Ravindra Dhadave](https://github.com/ravi8555)
|
|
248
|
+
|
|
249
|
+
## Key Updates in This README
|
|
250
|
+
|
|
251
|
+
| Item | Correct Value |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| **npm package** | `teawind-engine` |
|
|
254
|
+
| **Install command** | `npm install teawind-engine` |
|
|
255
|
+
| **Import statement** | `import { initTeawind } from 'teawind-engine'` |
|
|
256
|
+
| **CDN URL** | `https://cdn.jsdelivr.net/npm/teawind-engine@1.0.0/src/index.js` |
|
|
257
|
+
| **GitHub repo** | `https://github.com/ravi8555/teawind-engine.git` |
|
|
258
|
+
| **Stars badge** | Points to your GitHub repo |
|
|
259
|
+
| **Clone command** | Uses your GitHub URL |
|
|
260
|
+
|
|
261
|
+
Save this as `README.md` in your project root. It's now consistent with both your npm package and GitHub repository! 🚀
|
package/demo.html
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Teawind CSS - Visual Demo</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
padding: 40px 20px;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.container {
|
|
21
|
+
max-width: 1400px;
|
|
22
|
+
margin: 0 auto;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Header */
|
|
26
|
+
.header {
|
|
27
|
+
background: white;
|
|
28
|
+
border-radius: 24px;
|
|
29
|
+
padding: 40px;
|
|
30
|
+
margin-bottom: 40px;
|
|
31
|
+
text-align: center;
|
|
32
|
+
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.header h1 {
|
|
36
|
+
font-size: 3rem;
|
|
37
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
38
|
+
-webkit-background-clip: text;
|
|
39
|
+
-webkit-text-fill-color: transparent;
|
|
40
|
+
margin-bottom: 10px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.header p {
|
|
44
|
+
color: #666;
|
|
45
|
+
font-size: 1.2rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.badge {
|
|
49
|
+
display: inline-block;
|
|
50
|
+
background: #10b981;
|
|
51
|
+
color: white;
|
|
52
|
+
padding: 5px 15px;
|
|
53
|
+
border-radius: 20px;
|
|
54
|
+
font-size: 0.9rem;
|
|
55
|
+
margin-top: 15px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Grid Layout */
|
|
59
|
+
.grid {
|
|
60
|
+
display: grid;
|
|
61
|
+
grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
|
|
62
|
+
gap: 25px;
|
|
63
|
+
margin-bottom: 40px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Cards */
|
|
67
|
+
.card {
|
|
68
|
+
background: white;
|
|
69
|
+
border-radius: 20px;
|
|
70
|
+
padding: 25px;
|
|
71
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
|
72
|
+
transition: transform 0.3s, box-shadow 0.3s;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.card:hover {
|
|
76
|
+
transform: translateY(-5px);
|
|
77
|
+
box-shadow: 0 20px 40px rgba(0,0,0,0.15);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.card h2 {
|
|
81
|
+
font-size: 1.5rem;
|
|
82
|
+
margin-bottom: 20px;
|
|
83
|
+
color: #333;
|
|
84
|
+
border-left: 4px solid #667eea;
|
|
85
|
+
padding-left: 15px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.demo-section {
|
|
89
|
+
margin: 15px 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.demo-box {
|
|
93
|
+
background: #f8f9fa;
|
|
94
|
+
border-radius: 12px;
|
|
95
|
+
padding: 15px;
|
|
96
|
+
margin: 10px 0;
|
|
97
|
+
text-align: center;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
code {
|
|
101
|
+
background: #f0f0f0;
|
|
102
|
+
padding: 4px 8px;
|
|
103
|
+
border-radius: 6px;
|
|
104
|
+
font-family: 'Courier New', monospace;
|
|
105
|
+
font-size: 0.85rem;
|
|
106
|
+
color: #d63384;
|
|
107
|
+
display: inline-block;
|
|
108
|
+
margin: 5px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.flex-demo {
|
|
112
|
+
display: flex;
|
|
113
|
+
gap: 10px;
|
|
114
|
+
margin: 10px 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.color-swatch {
|
|
118
|
+
width: 80px;
|
|
119
|
+
height: 80px;
|
|
120
|
+
border-radius: 12px;
|
|
121
|
+
display: inline-flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
margin: 5px;
|
|
125
|
+
font-size: 12px;
|
|
126
|
+
font-weight: bold;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
button {
|
|
130
|
+
background: #667eea;
|
|
131
|
+
color: white;
|
|
132
|
+
border: none;
|
|
133
|
+
padding: 10px 20px;
|
|
134
|
+
border-radius: 8px;
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
font-size: 14px;
|
|
137
|
+
transition: all 0.3s;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
button:hover {
|
|
141
|
+
background: #764ba2;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.live-tester {
|
|
145
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
146
|
+
border-radius: 24px;
|
|
147
|
+
padding: 30px;
|
|
148
|
+
margin-top: 40px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.live-tester-inner {
|
|
152
|
+
background: white;
|
|
153
|
+
border-radius: 20px;
|
|
154
|
+
padding: 30px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.live-tester input {
|
|
158
|
+
width: 100%;
|
|
159
|
+
padding: 12px 16px;
|
|
160
|
+
border: 2px solid #e0e0e0;
|
|
161
|
+
border-radius: 10px;
|
|
162
|
+
font-family: 'Courier New', monospace;
|
|
163
|
+
font-size: 14px;
|
|
164
|
+
margin-bottom: 20px;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.preview-area {
|
|
168
|
+
background: #f8f9fa;
|
|
169
|
+
border-radius: 12px;
|
|
170
|
+
padding: 40px;
|
|
171
|
+
text-align: center;
|
|
172
|
+
min-height: 150px;
|
|
173
|
+
transition: all 0.3s;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.example-buttons {
|
|
177
|
+
display: flex;
|
|
178
|
+
flex-wrap: wrap;
|
|
179
|
+
gap: 10px;
|
|
180
|
+
margin-top: 20px;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.example-btn {
|
|
184
|
+
background: #e9ecef;
|
|
185
|
+
color: #495057;
|
|
186
|
+
padding: 8px 12px;
|
|
187
|
+
font-size: 12px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.example-btn:hover {
|
|
191
|
+
background: #667eea;
|
|
192
|
+
color: white;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
footer {
|
|
196
|
+
text-align: center;
|
|
197
|
+
color: white;
|
|
198
|
+
margin-top: 40px;
|
|
199
|
+
padding: 20px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
footer a {
|
|
203
|
+
color: white;
|
|
204
|
+
text-decoration: none;
|
|
205
|
+
}
|
|
206
|
+
</style>
|
|
207
|
+
</head>
|
|
208
|
+
<body>
|
|
209
|
+
<div class="container">
|
|
210
|
+
<!-- Header -->
|
|
211
|
+
<div class="header">
|
|
212
|
+
<h1>🍵 Teawind CSS</h1>
|
|
213
|
+
<p>Lightweight utility-first CSS engine - Visual Demo</p>
|
|
214
|
+
<div class="badge">✨ All chai-* classes in action</div>
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
<div class="grid">
|
|
218
|
+
<!-- Colors Card -->
|
|
219
|
+
<div class="card">
|
|
220
|
+
<h2>🎨 Colors</h2>
|
|
221
|
+
<div class="demo-section">
|
|
222
|
+
<div class="chai-bg-red color-swatch">Red</div>
|
|
223
|
+
<div class="chai-bg-blue color-swatch">Blue</div>
|
|
224
|
+
<div class="chai-bg-green color-swatch">Green</div>
|
|
225
|
+
<div class="chai-bg-yellow color-swatch" style="color:black;">Yellow</div>
|
|
226
|
+
<div class="chai-bg-gray color-swatch">Gray</div>
|
|
227
|
+
<div class="chai-bg-black color-swatch">Black</div>
|
|
228
|
+
</div>
|
|
229
|
+
<div class="demo-section">
|
|
230
|
+
<p class="chai-text-red">chai-text-red - Red text</p>
|
|
231
|
+
<p class="chai-text-blue">chai-text-blue - Blue text</p>
|
|
232
|
+
<p class="chai-text-green">chai-text-green - Green text</p>
|
|
233
|
+
</div>
|
|
234
|
+
<code>chai-bg-red</code>
|
|
235
|
+
<code>chai-text-white</code>
|
|
236
|
+
<code>chai-text-blue</code>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<!-- Spacing Card -->
|
|
240
|
+
<div class="card">
|
|
241
|
+
<h2>📏 Spacing (1 unit = 4px)</h2>
|
|
242
|
+
<div class="demo-box chai-bg-red chai-text-white chai-p-10">chai-p-10 (40px padding)</div>
|
|
243
|
+
<div class="demo-box chai-bg-blue chai-text-white chai-p-20">chai-p-20 (80px padding)</div>
|
|
244
|
+
<div class="demo-box chai-bg-green chai-text-white chai-m-10">chai-m-10 (40px margin)</div>
|
|
245
|
+
<div class="demo-box chai-bg-gray chai-text-white chai-px-20 chai-py-10">chai-px-20 chai-py-10</div>
|
|
246
|
+
<code>chai-p-10</code>
|
|
247
|
+
<code>chai-m-20</code>
|
|
248
|
+
<code>chai-px-30</code>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
<!-- Typography Card -->
|
|
252
|
+
<div class="card">
|
|
253
|
+
<h2>✍️ Typography</h2>
|
|
254
|
+
<div class="demo-box chai-text-16">chai-text-16 (16px font)</div>
|
|
255
|
+
<div class="demo-box chai-text-24 chai-font-bold">chai-text-24 + bold</div>
|
|
256
|
+
<div class="demo-box chai-text-center">chai-text-center alignment</div>
|
|
257
|
+
<div class="demo-box chai-text-left">chai-text-left</div>
|
|
258
|
+
<div class="demo-box chai-text-right">chai-text-right</div>
|
|
259
|
+
<code>chai-text-16</code>
|
|
260
|
+
<code>chai-text-24</code>
|
|
261
|
+
<code>chai-font-bold</code>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<!-- Layout & Flex Card -->
|
|
265
|
+
<div class="card">
|
|
266
|
+
<h2>🔲 Layout & Flex</h2>
|
|
267
|
+
<div class="chai-flex chai-gap-10">
|
|
268
|
+
<div class="chai-bg-red chai-text-white chai-p-10 chai-rounded-5">Flex 1</div>
|
|
269
|
+
<div class="chai-bg-blue chai-text-white chai-p-10 chai-rounded-5">Flex 2</div>
|
|
270
|
+
<div class="chai-bg-green chai-text-white chai-p-10 chai-rounded-5">Flex 3</div>
|
|
271
|
+
</div>
|
|
272
|
+
<div class="chai-flex chai-justify-between chai-mt-10 chai-mb-10">
|
|
273
|
+
<span>← Left</span>
|
|
274
|
+
<span>Center</span>
|
|
275
|
+
<span>Right →</span>
|
|
276
|
+
</div>
|
|
277
|
+
<div class="chai-flex chai-flex-col chai-gap-5">
|
|
278
|
+
<div class="chai-bg-gray chai-text-white chai-p-5 chai-rounded-5">Column 1</div>
|
|
279
|
+
<div class="chai-bg-gray chai-text-white chai-p-5 chai-rounded-5">Column 2</div>
|
|
280
|
+
</div>
|
|
281
|
+
<code>chai-flex</code>
|
|
282
|
+
<code>chai-justify-between</code>
|
|
283
|
+
<code>chai-flex-col</code>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<!-- Borders Card -->
|
|
287
|
+
<div class="card">
|
|
288
|
+
<h2>🖌️ Borders & Radius</h2>
|
|
289
|
+
<div class="demo-box chai-border-2 chai-rounded-10">border-2 + rounded-10</div>
|
|
290
|
+
<div class="demo-box chai-border-4 chai-rounded-20 chai-mt-10">border-4 + rounded-20</div>
|
|
291
|
+
<div class="demo-box chai-border-red chai-border-2 chai-mt-10">border-red + border-2</div>
|
|
292
|
+
<code>chai-border-2</code>
|
|
293
|
+
<code>chai-rounded-20</code>
|
|
294
|
+
<code>chai-border-red</code>
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
<!-- Transforms Card -->
|
|
298
|
+
<div class="card">
|
|
299
|
+
<h2>🌀 Transforms</h2>
|
|
300
|
+
<div class="flex-demo">
|
|
301
|
+
<div class="chai-scale-2 chai-bg-red chai-text-white chai-p-10 chai-rounded-5">scale-2</div>
|
|
302
|
+
<div class="chai-scale-3 chai-bg-blue chai-text-white chai-p-10 chai-rounded-5">scale-3</div>
|
|
303
|
+
</div>
|
|
304
|
+
<div class="flex-demo">
|
|
305
|
+
<div class="chai-rotate-45 chai-bg-green chai-text-white chai-p-10 chai-rounded-5">rotate-45°</div>
|
|
306
|
+
<div class="chai-rotate-90 chai-bg-yellow chai-p-10 chai-rounded-5">rotate-90°</div>
|
|
307
|
+
</div>
|
|
308
|
+
<code>chai-scale-2</code>
|
|
309
|
+
<code>chai-rotate-45</code>
|
|
310
|
+
<code>chai-scale-1</code>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<!-- Hover Effects Card -->
|
|
314
|
+
<div class="card">
|
|
315
|
+
<h2>✨ Hover Effects</h2>
|
|
316
|
+
<div class="flex-demo">
|
|
317
|
+
<button class="chai-hover-scale">Hover Scale ↑</button>
|
|
318
|
+
<button class="chai-hover-bg-red">Hover Red BG</button>
|
|
319
|
+
</div>
|
|
320
|
+
<div class="flex-demo">
|
|
321
|
+
<button class="chai-hover-text-white chai-bg-black">Hover White Text</button>
|
|
322
|
+
<div class="chai-hover-shadow chai-bg-gray chai-p-10 chai-rounded-5">Hover Shadow</div>
|
|
323
|
+
</div>
|
|
324
|
+
<div class="chai-hover-border chai-border-2 chai-p-10 chai-text-center chai-rounded-5">Hover Border</div>
|
|
325
|
+
<code>chai-hover-scale</code>
|
|
326
|
+
<code>chai-hover-shadow</code>
|
|
327
|
+
<code>chai-hover-border</code>
|
|
328
|
+
</div>
|
|
329
|
+
|
|
330
|
+
<!-- Width & Height Card -->
|
|
331
|
+
<div class="card">
|
|
332
|
+
<h2>📐 Width & Height</h2>
|
|
333
|
+
<div class="chai-w-full chai-bg-blue chai-text-white chai-p-10 chai-text-center chai-rounded-5">w-full (100%)</div>
|
|
334
|
+
<div class="chai-w-50 chai-bg-green chai-text-white chai-p-10 chai-text-center chai-rounded-5 chai-mt-5">w-50 (200px)</div>
|
|
335
|
+
<div class="chai-h-20 chai-bg-red chai-text-white chai-p-10 chai-text-center chai-rounded-5 chai-mt-5">h-20 (80px)</div>
|
|
336
|
+
<code>chai-w-full</code>
|
|
337
|
+
<code>chai-w-50</code>
|
|
338
|
+
<code>chai-h-20</code>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
|
|
342
|
+
<!-- Live Tester -->
|
|
343
|
+
<div class="live-tester">
|
|
344
|
+
<div class="live-tester-inner">
|
|
345
|
+
<h2 style="margin-bottom: 20px;">🎯 Live Class Tester</h2>
|
|
346
|
+
<input type="text" id="classInput" placeholder="Enter chai-* classes (e.g., chai-bg-red chai-text-white chai-p-20 chai-rounded-10)">
|
|
347
|
+
<div id="preview" class="preview-area">
|
|
348
|
+
<strong>✨ Preview Element</strong><br>
|
|
349
|
+
Try different classes above!
|
|
350
|
+
</div>
|
|
351
|
+
<div class="example-buttons">
|
|
352
|
+
<button class="example-btn" onclick="setClass('chai-bg-red chai-text-white chai-p-20 chai-rounded-10')">Red Card</button>
|
|
353
|
+
<button class="example-btn" onclick="setClass('chai-bg-blue chai-text-white chai-p-20 chai-rounded-20')">Blue Card</button>
|
|
354
|
+
<button class="example-btn" onclick="setClass('chai-bg-green chai-text-white chai-p-30 chai-rounded-10 chai-scale-2')">Green Scale</button>
|
|
355
|
+
<button class="example-btn" onclick="setClass('chai-border-4 chai-border-red chai-rounded-20 chai-p-20')">Border Demo</button>
|
|
356
|
+
<button class="example-btn" onclick="setClass('chai-text-24 chai-font-bold chai-text-center chai-bg-yellow chai-p-20')">Typography</button>
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
</div>
|
|
360
|
+
|
|
361
|
+
<footer>
|
|
362
|
+
<p>🍵 Teawind CSS Engine | All <code style="color:white; background:rgba(255,255,255,0.2);">chai-*</code> classes are processed dynamically</p>
|
|
363
|
+
<p style="margin-top: 10px;">
|
|
364
|
+
<a href="https://www.npmjs.com/package/teawind-engine" target="_blank">📦 npm</a> |
|
|
365
|
+
<a href="https://github.com/ravi8555/teawind-engine" target="_blank">🐙 GitHub</a>
|
|
366
|
+
</p>
|
|
367
|
+
</footer>
|
|
368
|
+
</div>
|
|
369
|
+
|
|
370
|
+
<script type="module">
|
|
371
|
+
import { initTeawind, applyStyles } from './src/index.js';
|
|
372
|
+
console.log("initTeawind");
|
|
373
|
+
|
|
374
|
+
// Initialize Teawind
|
|
375
|
+
initTeawind();
|
|
376
|
+
|
|
377
|
+
// Live tester
|
|
378
|
+
const classInput = document.getElementById('classInput');
|
|
379
|
+
const preview = document.getElementById('preview');
|
|
380
|
+
|
|
381
|
+
window.setClass = (classes) => {
|
|
382
|
+
classInput.value = classes;
|
|
383
|
+
preview.className = classes;
|
|
384
|
+
applyStyles(preview);
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
classInput.addEventListener('input', () => {
|
|
388
|
+
preview.className = classInput.value;
|
|
389
|
+
applyStyles(preview);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
console.log('🍵 Teawind Visual Demo Loaded!');
|
|
393
|
+
</script>
|
|
394
|
+
</body>
|
|
395
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,37 +1,32 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "teawind-engine",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Lightweight utility-first CSS engine
|
|
5
|
-
"main": "src/index.js",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"css
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"license": "MIT",
|
|
34
|
-
"scripts": {
|
|
35
|
-
"test": "echo \"Error: no test specified\" && exit 0"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "teawind-engine",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Lightweight utility-first CSS engine",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "vitest",
|
|
9
|
+
"test:run": "vitest run",
|
|
10
|
+
"test:ui": "vitest --ui"
|
|
11
|
+
},
|
|
12
|
+
"vitest": {
|
|
13
|
+
"environment": "jsdom",
|
|
14
|
+
"globals": true,
|
|
15
|
+
"include": [
|
|
16
|
+
"test/**/*.test.js"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"vitest": "^1.6.0",
|
|
21
|
+
"jsdom": "^23.0.0",
|
|
22
|
+
"@vitest/ui": "^1.6.0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"css",
|
|
26
|
+
"utility",
|
|
27
|
+
"teawind",
|
|
28
|
+
"tailwind"
|
|
29
|
+
],
|
|
30
|
+
"author": "Ravindra Dhadave",
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|
package/src/core/observer.js
CHANGED
|
@@ -1,3 +1,173 @@
|
|
|
1
|
+
// /**
|
|
2
|
+
// * Teawind Observer Module
|
|
3
|
+
// * Handles DOM mutation observation and style application
|
|
4
|
+
// */
|
|
5
|
+
|
|
6
|
+
// import { applyStyles } from '../index.js';
|
|
7
|
+
|
|
8
|
+
// /**
|
|
9
|
+
// * Applies Teawind styles to all elements with class attributes
|
|
10
|
+
// * @param {HTMLElement} container - The container element to scan (default: document.body)
|
|
11
|
+
// */
|
|
12
|
+
// export function applyToExistingElements(container = document.body) {
|
|
13
|
+
// const elements = container.querySelectorAll('[class]');
|
|
14
|
+
// elements.forEach(element => {
|
|
15
|
+
// applyStyles(element);
|
|
16
|
+
// });
|
|
17
|
+
// return elements.length;
|
|
18
|
+
// }
|
|
19
|
+
|
|
20
|
+
// /**
|
|
21
|
+
// * Creates and configures a MutationObserver to watch for new elements
|
|
22
|
+
// * @param {HTMLElement} container - The container to observe
|
|
23
|
+
// * @param {Object} options - Observer options
|
|
24
|
+
// * @returns {MutationObserver} The configured observer instance
|
|
25
|
+
// */
|
|
26
|
+
// export function createObserver(container = document.body, options = {}) {
|
|
27
|
+
// const defaultOptions = {
|
|
28
|
+
// childList: true,
|
|
29
|
+
// subtree: true,
|
|
30
|
+
// attributes: false,
|
|
31
|
+
// characterData: false
|
|
32
|
+
// };
|
|
33
|
+
|
|
34
|
+
// const observerOptions = { ...defaultOptions, ...options };
|
|
35
|
+
|
|
36
|
+
// const observer = new MutationObserver((mutations) => {
|
|
37
|
+
// mutations.forEach((mutation) => {
|
|
38
|
+
// // Handle added nodes
|
|
39
|
+
// if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
|
40
|
+
// mutation.addedNodes.forEach((node) => {
|
|
41
|
+
// // Check if it's an element node
|
|
42
|
+
// if (node.nodeType === Node.ELEMENT_NODE) {
|
|
43
|
+
// // Apply styles to the new element itself
|
|
44
|
+
// if (node.hasAttribute && node.hasAttribute('class')) {
|
|
45
|
+
// applyStyles(node);
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
// // Also apply styles to any child elements with classes
|
|
49
|
+
// const childElements = node.querySelectorAll('[class]');
|
|
50
|
+
// childElements.forEach(child => {
|
|
51
|
+
// applyStyles(child);
|
|
52
|
+
// });
|
|
53
|
+
// }
|
|
54
|
+
// });
|
|
55
|
+
// }
|
|
56
|
+
|
|
57
|
+
// // Handle attribute changes (optional)
|
|
58
|
+
// if (observerOptions.attributes && mutation.type === 'attributes') {
|
|
59
|
+
// if (mutation.attributeName === 'class') {
|
|
60
|
+
// applyStyles(mutation.target);
|
|
61
|
+
// }
|
|
62
|
+
// }
|
|
63
|
+
// });
|
|
64
|
+
// });
|
|
65
|
+
|
|
66
|
+
// observer.observe(container, observerOptions);
|
|
67
|
+
// return observer;
|
|
68
|
+
// }
|
|
69
|
+
|
|
70
|
+
// /**
|
|
71
|
+
// * Initializes the observer and applies styles to existing elements
|
|
72
|
+
// * @param {HTMLElement} container - Container to observe
|
|
73
|
+
// * @param {Object} options - Observer options
|
|
74
|
+
// * @returns {Object} Observer instance and cleanup function
|
|
75
|
+
// */
|
|
76
|
+
// export function initObserver(container = document.body, options = {}) {
|
|
77
|
+
// // Apply to existing elements
|
|
78
|
+
// const elementCount = applyToExistingElements(container);
|
|
79
|
+
// console.log(`🍵 Teawind: Applied styles to ${elementCount} existing elements`);
|
|
80
|
+
|
|
81
|
+
// // Create observer for new elements
|
|
82
|
+
// const observer = createObserver(container, options);
|
|
83
|
+
|
|
84
|
+
// // Return cleanup function
|
|
85
|
+
// return {
|
|
86
|
+
// observer,
|
|
87
|
+
// disconnect: () => {
|
|
88
|
+
// observer.disconnect();
|
|
89
|
+
// console.log('🍵 Teawind: Observer disconnected');
|
|
90
|
+
// }
|
|
91
|
+
// };
|
|
92
|
+
// }
|
|
93
|
+
|
|
94
|
+
// /**
|
|
95
|
+
// * Watches for class changes on specific elements
|
|
96
|
+
// * @param {HTMLElement} element - Element to watch
|
|
97
|
+
// * @returns {MutationObserver} Observer for class changes
|
|
98
|
+
// */
|
|
99
|
+
// export function watchClassChanges(element) {
|
|
100
|
+
// if (!element) return null;
|
|
101
|
+
|
|
102
|
+
// const observer = new MutationObserver((mutations) => {
|
|
103
|
+
// mutations.forEach((mutation) => {
|
|
104
|
+
// if (mutation.attributeName === 'class') {
|
|
105
|
+
// applyStyles(element);
|
|
106
|
+
// }
|
|
107
|
+
// });
|
|
108
|
+
// });
|
|
109
|
+
|
|
110
|
+
// observer.observe(element, { attributes: true, attributeFilter: ['class'] });
|
|
111
|
+
// return observer;
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
// /**
|
|
115
|
+
// * Debounced observer for performance optimization
|
|
116
|
+
// * @param {HTMLElement} container - Container to observe
|
|
117
|
+
// * @param {number} delay - Debounce delay in ms
|
|
118
|
+
// * @returns {Object} Observer with debounced updates
|
|
119
|
+
// */
|
|
120
|
+
// export function createDebouncedObserver(container = document.body, delay = 100) {
|
|
121
|
+
// let timeoutId = null;
|
|
122
|
+
// let pendingElements = new Set();
|
|
123
|
+
|
|
124
|
+
// const processElements = () => {
|
|
125
|
+
// pendingElements.forEach(element => {
|
|
126
|
+
// applyStyles(element);
|
|
127
|
+
// });
|
|
128
|
+
// pendingElements.clear();
|
|
129
|
+
// };
|
|
130
|
+
|
|
131
|
+
// const observer = new MutationObserver((mutations) => {
|
|
132
|
+
// mutations.forEach((mutation) => {
|
|
133
|
+
// mutation.addedNodes.forEach((node) => {
|
|
134
|
+
// if (node.nodeType === Node.ELEMENT_NODE) {
|
|
135
|
+
// pendingElements.add(node);
|
|
136
|
+
|
|
137
|
+
// // Add child elements
|
|
138
|
+
// node.querySelectorAll('[class]').forEach(child => {
|
|
139
|
+
// pendingElements.add(child);
|
|
140
|
+
// });
|
|
141
|
+
// }
|
|
142
|
+
// });
|
|
143
|
+
// });
|
|
144
|
+
|
|
145
|
+
// // Clear previous timeout and set new one
|
|
146
|
+
// if (timeoutId) clearTimeout(timeoutId);
|
|
147
|
+
// timeoutId = setTimeout(processElements, delay);
|
|
148
|
+
// });
|
|
149
|
+
|
|
150
|
+
// observer.observe(container, { childList: true, subtree: true });
|
|
151
|
+
|
|
152
|
+
// return {
|
|
153
|
+
// observer,
|
|
154
|
+
// disconnect: () => {
|
|
155
|
+
// if (timeoutId) clearTimeout(timeoutId);
|
|
156
|
+
// observer.disconnect();
|
|
157
|
+
// }
|
|
158
|
+
// };
|
|
159
|
+
// }
|
|
160
|
+
|
|
161
|
+
// // Export default object with all methods
|
|
162
|
+
// export default {
|
|
163
|
+
// init: initObserver,
|
|
164
|
+
// createObserver,
|
|
165
|
+
// applyToExistingElements,
|
|
166
|
+
// watchClassChanges,
|
|
167
|
+
// createDebouncedObserver
|
|
168
|
+
// };
|
|
169
|
+
|
|
170
|
+
|
|
1
171
|
/**
|
|
2
172
|
* Teawind Observer Module
|
|
3
173
|
* Handles DOM mutation observation and style application
|
package/src/index.js
CHANGED
|
@@ -1,154 +1,127 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// // Store original styles for hover effects
|
|
6
|
-
// let hoverStyles = new Map();
|
|
1
|
+
// src/index.js
|
|
2
|
+
import { styleMap, parseDynamicClass } from './core/parser.js';
|
|
3
|
+
import { injectStyles, keyframes } from './core/styles.js';
|
|
4
|
+
import { initObserver } from './core/observer.js';
|
|
7
5
|
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
6
|
+
// =========================
|
|
7
|
+
// APPLY STYLES FUNCTION
|
|
8
|
+
// =========================
|
|
9
|
+
export function applyStyles(element) {
|
|
10
|
+
if (!element || !element.className) return;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const classNames = element.className.split(/\s+/);
|
|
13
|
+
const styleToApply = {};
|
|
14
|
+
const remainingClasses = [];
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
classNames.forEach((className) => {
|
|
17
|
+
if (className.startsWith("chai-")) {
|
|
18
|
+
const cleanClass = className.replace("chai-", "");
|
|
19
|
+
const style = styleMap[cleanClass];
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
if (style) {
|
|
22
|
+
Object.assign(styleToApply, style);
|
|
23
|
+
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
parseDynamicClass(cleanClass, styleToApply);
|
|
26
|
+
} else {
|
|
27
|
+
remainingClasses.push(className);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
Object.assign(element.style, styleToApply);
|
|
32
|
+
element.className = remainingClasses.join(" ");
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
// Apply hover effects
|
|
35
|
+
applyHoverEffects(element);
|
|
36
|
+
}
|
|
37
37
|
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
38
|
+
// =========================
|
|
39
|
+
// HOVER EFFECTS
|
|
40
|
+
// =========================
|
|
41
|
+
function applyHoverEffects(element) {
|
|
42
|
+
const classNames = element.className.split(/\s+/);
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
classNames.forEach(className => {
|
|
45
|
+
if (className === "chai-hover-scale") {
|
|
46
|
+
element.addEventListener("mouseenter", () => {
|
|
47
|
+
element.style.transform = "scale(1.05)";
|
|
48
|
+
element.style.transition = "transform 0.2s";
|
|
49
|
+
});
|
|
50
|
+
element.addEventListener("mouseleave", () => {
|
|
51
|
+
element.style.transform = "scale(1)";
|
|
52
|
+
});
|
|
53
|
+
}
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
if (className === "chai-hover-bg-red") {
|
|
56
|
+
const originalBg = element.style.backgroundColor;
|
|
57
|
+
element.addEventListener("mouseenter", () => {
|
|
58
|
+
element.style.backgroundColor = "#ef4444";
|
|
59
|
+
});
|
|
60
|
+
element.addEventListener("mouseleave", () => {
|
|
61
|
+
element.style.backgroundColor = originalBg || "";
|
|
62
|
+
});
|
|
63
|
+
}
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
if (className === "chai-hover-text-white") {
|
|
66
|
+
const originalColor = element.style.color;
|
|
67
|
+
element.addEventListener("mouseenter", () => {
|
|
68
|
+
element.style.color = "#ffffff";
|
|
69
|
+
});
|
|
70
|
+
element.addEventListener("mouseleave", () => {
|
|
71
|
+
element.style.color = originalColor || "";
|
|
72
|
+
});
|
|
73
|
+
}
|
|
72
74
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
if (className === "chai-hover-shadow") {
|
|
76
|
+
element.addEventListener("mouseenter", () => {
|
|
77
|
+
element.style.boxShadow = "0 10px 25px rgba(0,0,0,0.15)";
|
|
78
|
+
});
|
|
79
|
+
element.addEventListener("mouseleave", () => {
|
|
80
|
+
element.style.boxShadow = "";
|
|
81
|
+
});
|
|
82
|
+
}
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// // Initialize Teawind
|
|
96
|
-
// export function initTeawind(container = document.body) {
|
|
97
|
-
// // Apply to all existing elements
|
|
98
|
-
// document.querySelectorAll('[class]').forEach(ele => {
|
|
99
|
-
// applyStyles(ele);
|
|
100
|
-
// });
|
|
101
|
-
|
|
102
|
-
// // Watch for new elements
|
|
103
|
-
// const observer = new MutationObserver(mutations => {
|
|
104
|
-
// mutations.forEach(mutation => {
|
|
105
|
-
// mutation.addedNodes.forEach(node => {
|
|
106
|
-
// if (node.nodeType === 1 && node.hasAttribute && node.hasAttribute('class')) {
|
|
107
|
-
// applyStyles(node);
|
|
108
|
-
// }
|
|
109
|
-
// });
|
|
110
|
-
// });
|
|
111
|
-
// });
|
|
112
|
-
|
|
113
|
-
// observer.observe(container, { childList: true, subtree: true });
|
|
114
|
-
|
|
115
|
-
// console.log('🍵 Teawind CSS Engine initialized!');
|
|
116
|
-
// }
|
|
117
|
-
|
|
118
|
-
// // Default export
|
|
119
|
-
// export default {
|
|
120
|
-
// init: initTeawind,
|
|
121
|
-
// applyStyles,
|
|
122
|
-
// version: '1.0.0'
|
|
123
|
-
// };
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Teawind CSS Engine - Main Entry Point
|
|
128
|
-
*/
|
|
129
|
-
|
|
130
|
-
import { styleMap, parseDynamicClass } from './core/parser.js';
|
|
131
|
-
import { injectStyles, keyframes } from './core/styles.js';
|
|
132
|
-
import { initObserver } from './core/observer.js';
|
|
84
|
+
if (className === "chai-hover-border") {
|
|
85
|
+
element.addEventListener("mouseenter", () => {
|
|
86
|
+
element.style.borderColor = "#ef4444";
|
|
87
|
+
element.style.borderWidth = "2px";
|
|
88
|
+
});
|
|
89
|
+
element.addEventListener("mouseleave", () => {
|
|
90
|
+
element.style.borderColor = "";
|
|
91
|
+
element.style.borderWidth = "";
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
133
96
|
|
|
97
|
+
// =========================
|
|
98
|
+
// INITIALIZATION
|
|
99
|
+
// =========================
|
|
134
100
|
// Inject base styles when the engine loads
|
|
135
101
|
if (typeof document !== 'undefined') {
|
|
136
102
|
injectStyles();
|
|
137
103
|
}
|
|
138
104
|
|
|
139
|
-
// Export everything
|
|
140
|
-
export { styleMap, parseDynamicClass };
|
|
141
|
-
export { initObserver };
|
|
142
|
-
export { injectStyles, keyframes };
|
|
143
|
-
|
|
144
105
|
// Main initialization function
|
|
145
106
|
export function initTeawind(container = document.body, options = {}) {
|
|
107
|
+
// First apply styles to all existing elements
|
|
108
|
+
document.querySelectorAll('[class]').forEach(ele => {
|
|
109
|
+
applyStyles(ele);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Then initialize observer for dynamic elements
|
|
146
113
|
return initObserver(container, options);
|
|
147
114
|
}
|
|
148
115
|
|
|
116
|
+
// Export everything
|
|
117
|
+
export { styleMap, parseDynamicClass };
|
|
118
|
+
export { initObserver };
|
|
119
|
+
export { injectStyles, keyframes };
|
|
120
|
+
|
|
149
121
|
// Default export
|
|
150
122
|
export default {
|
|
151
123
|
init: initTeawind,
|
|
124
|
+
applyStyles,
|
|
152
125
|
injectStyles,
|
|
153
126
|
keyframes,
|
|
154
127
|
version: '1.0.0'
|
package/vitest.config.js
ADDED
package/src/core/style.css
DELETED
|
File without changes
|