teawind-engine 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # 🍵 Teawind CSS
2
+
3
+ A lightweight utility-first CSS engine. Build UIs using `chai-*` classes without writing CSS!
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install teawind
9
+
10
+ Or via CDN:
11
+
12
+ <script type="module">
13
+ import { initTeawind } from 'https://cdn.jsdelivr.net/npm/teawind@1.0.0/src/index.js';
14
+ initTeawind();
15
+ </script>
16
+
17
+ Usage
18
+
19
+ Basic Setup
20
+
21
+ <!DOCTYPE html>
22
+ <html>
23
+ <head>
24
+ <title>Teawind Demo</title>
25
+ <script type="module">
26
+ import { initTeawind } from 'teawind';
27
+
28
+ // Initialize the engine
29
+ initTeawind();
30
+ </script>
31
+ </head>
32
+ <body>
33
+ <div class="chai-bg-red chai-text-white chai-p-20 chai-rounded-10">
34
+ Hello Teawind!
35
+ </div>
36
+ </body>
37
+ </html>
38
+
39
+ Available Classes
40
+ Colors
41
+ chai-bg-red, chai-bg-blue, chai-bg-green, chai-bg-yellow, chai-bg-gray, chai-bg-black, chai-bg-white
42
+
43
+ chai-text-red, chai-text-blue, chai-text-green, chai-text-yellow, chai-text-gray, chai-text-black, chai-text-white
44
+
45
+ Spacing (1 unit = 4px)
46
+ chai-p-10 → padding: 40px
47
+
48
+ chai-m-20 → margin: 80px
49
+
50
+ chai-px-30 → padding-left/right: 120px
51
+
52
+ chai-py-15 → padding-top/bottom: 60px
53
+
54
+ Typography
55
+ chai-text-16, chai-text-24 → font size
56
+
57
+ chai-font-bold → bold text
58
+
59
+ chai-text-center, chai-text-left, chai-text-right → text alignment
60
+
61
+ Layout
62
+ chai-flex, chai-flex-col, chai-flex-center
63
+
64
+ chai-justify-between
65
+
66
+ chai-gap-10
67
+
68
+ Borders
69
+ chai-border-2, chai-border-4
70
+
71
+ chai-rounded-10, chai-rounded-20
72
+
73
+ chai-border-red
74
+
75
+ Transforms
76
+ chai-scale-2, chai-scale-3, chai-scale-1
77
+
78
+ chai-rotate-45, chai-rotate-90
79
+
80
+ Hover Effects
81
+ chai-hover-scale → zoom effect
82
+
83
+ chai-hover-bg-red → background change
84
+
85
+ chai-hover-text-white → text color change
86
+
87
+ chai-hover-shadow → shadow effect
88
+
89
+ chai-hover-border → border effect
90
+
91
+ API
92
+ initTeawind(container)
93
+ Initializes Teawind on the specified container (defaults to document.body).
94
+
95
+ javascript
96
+ import { initTeawind } from 'teawind';
97
+ initTeawind();
98
+ applyStyles(element)
99
+ Manually apply Teawind styles to an element.
100
+
101
+ javascript
102
+ import { applyStyles } from 'teawind';
103
+ const element = document.querySelector('.my-element');
104
+ applyStyles(element);
105
+ License
106
+ MIT
107
+
108
+ text
109
+
110
+ ### 3. **Create `.npmignore`**
111
+ node_modules/
112
+ test/
113
+ *.log
114
+ .DS_Store
115
+ .git/
116
+ .github/
117
+ .vscode/
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "teawind-engine",
3
+ "version": "1.0.0",
4
+ "description": "Lightweight utility-first CSS engine - build UIs with chai-* classes without writing CSS",
5
+ "main": "src/index.js",
6
+ "module": "src/index.js",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./src/index.js",
11
+ "require": "./src/index.js",
12
+ "default": "./src/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "src",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "keywords": [
21
+ "css",
22
+ "tailwind",
23
+ "utility",
24
+ "lightweight",
25
+ "css-framework",
26
+ "teawind",
27
+ "chai-classes"
28
+ ],
29
+ "author": {
30
+ "name": "Your Name",
31
+ "email": "your.email@example.com"
32
+ },
33
+ "license": "MIT",
34
+ "scripts": {
35
+ "test": "echo \"Error: no test specified\" && exit 0"
36
+ }
37
+ }
@@ -0,0 +1,168 @@
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
+ };
@@ -0,0 +1,122 @@
1
+ // Style definitions
2
+ export const styleMap = {
3
+ // Flex utilities
4
+ "flex": { display: "flex" },
5
+ "flex-center": { display: "flex", alignItems: "center", justifyContent: "center" },
6
+ "flex-col": { display: "flex", flexDirection: "column" },
7
+ "justify-between": { display: "flex", justifyContent: "space-between" },
8
+ "gap-10": { gap: "10px" },
9
+
10
+ // Border utilities
11
+ "border-2": { borderWidth: "2px", borderStyle: "solid" },
12
+ "border-4": { borderWidth: "4px", borderStyle: "solid" },
13
+ "rounded-10": { borderRadius: "10px" },
14
+ "rounded-20": { borderRadius: "20px" },
15
+ "border-red": { borderColor: "#ef4444" },
16
+
17
+ // Transform utilities
18
+ "scale-2": { transform: "scale(2)" },
19
+ "scale-3": { transform: "scale(3)" },
20
+ "scale-1": { transform: "scale(1)" },
21
+ "rotate-45": { transform: "rotate(45deg)" },
22
+ "rotate-90": { transform: "rotate(90deg)" },
23
+ };
24
+
25
+ const spacingUnit = 4;
26
+ const colors = {
27
+ red: "#ef4444",
28
+ blue: "#3b82f6",
29
+ green: "#22c55e",
30
+ yellow: "#facc15",
31
+ black: "#000",
32
+ white: "#fff",
33
+ gray: "#6b7280"
34
+ };
35
+
36
+ export function parseDynamicClass(className, styles) {
37
+ // Background colors
38
+ if (className.startsWith("bg-")) {
39
+ const color = className.split("-")[1];
40
+ styles.backgroundColor = colors[color] || color;
41
+ }
42
+
43
+ // Text color & size
44
+ if (className.startsWith("text-")) {
45
+ const value = className.split("-")[1];
46
+ if (colors[value]) {
47
+ styles.color = colors[value];
48
+ } else if (!isNaN(value)) {
49
+ styles.fontSize = `${value}px`;
50
+ }
51
+ }
52
+
53
+ // Text align
54
+ if (className === "text-center") styles.textAlign = "center";
55
+ if (className === "text-left") styles.textAlign = "left";
56
+ if (className === "text-right") styles.textAlign = "right";
57
+
58
+ // Width
59
+ if (className.startsWith("w-")) {
60
+ const val = className.split("-")[1];
61
+ if (val === "full") styles.width = "100%";
62
+ else if (val.includes("/")) {
63
+ const [a, b] = val.split("/");
64
+ styles.width = `${(a / b) * 100}%`;
65
+ } else {
66
+ styles.width = `${val * spacingUnit}px`;
67
+ }
68
+ }
69
+
70
+ // Height
71
+ if (className.startsWith("h-")) {
72
+ const val = className.split("-")[1];
73
+ if (val === "full") styles.height = "100%";
74
+ else if (val === "screen") styles.height = "100vh";
75
+ else {
76
+ styles.height = `${val * spacingUnit}px`;
77
+ }
78
+ }
79
+
80
+ // Padding
81
+ if (className.startsWith("p-")) {
82
+ const val = className.split("-")[1];
83
+ styles.padding = `${val * spacingUnit}px`;
84
+ }
85
+ if (className.startsWith("px-")) {
86
+ const val = className.split("-")[1];
87
+ styles.paddingLeft = `${val * spacingUnit}px`;
88
+ styles.paddingRight = `${val * spacingUnit}px`;
89
+ }
90
+ if (className.startsWith("py-")) {
91
+ const val = className.split("-")[1];
92
+ styles.paddingTop = `${val * spacingUnit}px`;
93
+ styles.paddingBottom = `${val * spacingUnit}px`;
94
+ }
95
+
96
+ // Margin
97
+ if (className.startsWith("m-")) {
98
+ const val = className.split("-")[1];
99
+ styles.margin = `${val * spacingUnit}px`;
100
+ }
101
+ if (className.startsWith("mt-")) {
102
+ const val = className.split("-")[1];
103
+ styles.marginTop = `${val * spacingUnit}px`;
104
+ }
105
+ if (className.startsWith("mb-")) {
106
+ const val = className.split("-")[1];
107
+ styles.marginBottom = `${val * spacingUnit}px`;
108
+ }
109
+ if (className.startsWith("ml-")) {
110
+ const val = className.split("-")[1];
111
+ styles.marginLeft = `${val * spacingUnit}px`;
112
+ }
113
+ if (className.startsWith("mr-")) {
114
+ const val = className.split("-")[1];
115
+ styles.marginRight = `${val * spacingUnit}px`;
116
+ }
117
+
118
+ // Font bold
119
+ if (className === "font-bold") {
120
+ styles.fontWeight = "bold";
121
+ }
122
+ }
File without changes
@@ -0,0 +1,528 @@
1
+ /**
2
+ * Teawind Styles Module
3
+ * Contains all style definitions, animations, and utility classes in JavaScript
4
+ */
5
+
6
+ // =========================
7
+ // BASE STYLES (Applied globally)
8
+ // =========================
9
+ export const baseStyles = {
10
+ // Box sizing reset for all elements
11
+ '*': {
12
+ boxSizing: 'border-box',
13
+ margin: 0,
14
+ padding: 0
15
+ },
16
+
17
+ '*::before': {
18
+ boxSizing: 'border-box'
19
+ },
20
+
21
+ '*::after': {
22
+ boxSizing: 'border-box'
23
+ },
24
+
25
+ // Base transition for smooth hover effects
26
+ '[class*="chai-"]': {
27
+ transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)'
28
+ }
29
+ };
30
+
31
+ // =========================
32
+ // HOVER TRANSITIONS
33
+ // =========================
34
+ export const hoverStyles = {
35
+ '.chai-hover-scale': {
36
+ transition: 'transform 0.2s ease'
37
+ },
38
+
39
+ '.chai-hover-bg-red': {
40
+ transition: 'all 0.25s ease'
41
+ },
42
+
43
+ '.chai-hover-text-white': {
44
+ transition: 'all 0.25s ease'
45
+ },
46
+
47
+ '.chai-hover-shadow': {
48
+ transition: 'all 0.25s ease'
49
+ },
50
+
51
+ '.chai-hover-border': {
52
+ transition: 'all 0.25s ease'
53
+ }
54
+ };
55
+
56
+ // =========================
57
+ // DISPLAY UTILITIES
58
+ // =========================
59
+ export const displayStyles = {
60
+ 'chai-flex': { display: 'flex' },
61
+ 'chai-inline-flex': { display: 'inline-flex' },
62
+ 'chai-block': { display: 'block' },
63
+ 'chai-inline-block': { display: 'inline-block' },
64
+ 'chai-inline': { display: 'inline' },
65
+ 'chai-hidden': { display: 'none' },
66
+ 'chai-grid': { display: 'grid' },
67
+ 'chai-inline-grid': { display: 'inline-grid' },
68
+ 'chai-table': { display: 'table' },
69
+ 'chai-table-cell': { display: 'table-cell' }
70
+ };
71
+
72
+ // =========================
73
+ // POSITION UTILITIES
74
+ // =========================
75
+ export const positionStyles = {
76
+ 'chai-relative': { position: 'relative' },
77
+ 'chai-absolute': { position: 'absolute' },
78
+ 'chai-fixed': { position: 'fixed' },
79
+ 'chai-sticky': { position: 'sticky' },
80
+ 'chai-static': { position: 'static' },
81
+
82
+ // Position insets
83
+ 'chai-inset-0': { top: 0, right: 0, bottom: 0, left: 0 },
84
+ 'chai-top-0': { top: 0 },
85
+ 'chai-right-0': { right: 0 },
86
+ 'chai-bottom-0': { bottom: 0 },
87
+ 'chai-left-0': { left: 0 }
88
+ };
89
+
90
+ // =========================
91
+ // Z-INDEX UTILITIES
92
+ // =========================
93
+ export const zIndexStyles = {
94
+ 'chai-z-0': { zIndex: 0 },
95
+ 'chai-z-10': { zIndex: 10 },
96
+ 'chai-z-20': { zIndex: 20 },
97
+ 'chai-z-30': { zIndex: 30 },
98
+ 'chai-z-40': { zIndex: 40 },
99
+ 'chai-z-50': { zIndex: 50 },
100
+ 'chai-z-auto': { zIndex: 'auto' }
101
+ };
102
+
103
+ // =========================
104
+ // CURSOR UTILITIES
105
+ // =========================
106
+ export const cursorStyles = {
107
+ 'chai-cursor-pointer': { cursor: 'pointer' },
108
+ 'chai-cursor-default': { cursor: 'default' },
109
+ 'chai-cursor-not-allowed': { cursor: 'not-allowed' },
110
+ 'chai-cursor-wait': { cursor: 'wait' },
111
+ 'chai-cursor-move': { cursor: 'move' },
112
+ 'chai-cursor-grab': { cursor: 'grab' },
113
+ 'chai-cursor-grabbing': { cursor: 'grabbing' },
114
+ 'chai-cursor-text': { cursor: 'text' }
115
+ };
116
+
117
+ // =========================
118
+ // OPACITY UTILITIES
119
+ // =========================
120
+ export const opacityStyles = {
121
+ 'chai-opacity-0': { opacity: 0 },
122
+ 'chai-opacity-25': { opacity: 0.25 },
123
+ 'chai-opacity-50': { opacity: 0.5 },
124
+ 'chai-opacity-75': { opacity: 0.75 },
125
+ 'chai-opacity-100': { opacity: 1 }
126
+ };
127
+
128
+ // =========================
129
+ // OVERFLOW UTILITIES
130
+ // =========================
131
+ export const overflowStyles = {
132
+ 'chai-overflow-auto': { overflow: 'auto' },
133
+ 'chai-overflow-hidden': { overflow: 'hidden' },
134
+ 'chai-overflow-visible': { overflow: 'visible' },
135
+ 'chai-overflow-scroll': { overflow: 'scroll' },
136
+ 'chai-overflow-x-auto': { overflowX: 'auto' },
137
+ 'chai-overflow-y-auto': { overflowY: 'auto' },
138
+ 'chai-overflow-x-hidden': { overflowX: 'hidden' },
139
+ 'chai-overflow-y-hidden': { overflowY: 'hidden' }
140
+ };
141
+
142
+ // =========================
143
+ // TRANSFORM ORIGIN
144
+ // =========================
145
+ export const transformOriginStyles = {
146
+ 'chai-origin-center': { transformOrigin: 'center' },
147
+ 'chai-origin-top': { transformOrigin: 'top' },
148
+ 'chai-origin-bottom': { transformOrigin: 'bottom' },
149
+ 'chai-origin-left': { transformOrigin: 'left' },
150
+ 'chai-origin-right': { transformOrigin: 'right' },
151
+ 'chai-origin-top-left': { transformOrigin: 'top left' },
152
+ 'chai-origin-top-right': { transformOrigin: 'top right' },
153
+ 'chai-origin-bottom-left': { transformOrigin: 'bottom left' },
154
+ 'chai-origin-bottom-right': { transformOrigin: 'bottom right' }
155
+ };
156
+
157
+ // =========================
158
+ // BOX SIZING
159
+ // =========================
160
+ export const boxSizingStyles = {
161
+ 'chai-border-box': { boxSizing: 'border-box' },
162
+ 'chai-content-box': { boxSizing: 'content-box' }
163
+ };
164
+
165
+ // =========================
166
+ // USER SELECT
167
+ // =========================
168
+ export const userSelectStyles = {
169
+ 'chai-select-none': { userSelect: 'none' },
170
+ 'chai-select-text': { userSelect: 'text' },
171
+ 'chai-select-all': { userSelect: 'all' },
172
+ 'chai-select-auto': { userSelect: 'auto' }
173
+ };
174
+
175
+ // =========================
176
+ // POINTER EVENTS
177
+ // =========================
178
+ export const pointerEventsStyles = {
179
+ 'chai-pointer-events-none': { pointerEvents: 'none' },
180
+ 'chai-pointer-events-auto': { pointerEvents: 'auto' }
181
+ };
182
+
183
+ // =========================
184
+ // RESIZE UTILITIES
185
+ // =========================
186
+ export const resizeStyles = {
187
+ 'chai-resize': { resize: 'both' },
188
+ 'chai-resize-x': { resize: 'horizontal' },
189
+ 'chai-resize-y': { resize: 'vertical' },
190
+ 'chai-resize-none': { resize: 'none' }
191
+ };
192
+
193
+ // =========================
194
+ // SCROLL BEHAVIOR
195
+ // =========================
196
+ export const scrollStyles = {
197
+ 'chai-scroll-smooth': { scrollBehavior: 'smooth' },
198
+ 'chai-scroll-auto': { scrollBehavior: 'auto' }
199
+ };
200
+
201
+ // =========================
202
+ // BACKDROP FILTER
203
+ // =========================
204
+ export const backdropStyles = {
205
+ 'chai-backdrop-blur': { backdropFilter: 'blur(8px)' },
206
+ 'chai-backdrop-blur-sm': { backdropFilter: 'blur(4px)' },
207
+ 'chai-backdrop-blur-lg': { backdropFilter: 'blur(16px)' },
208
+ 'chai-backdrop-blur-none': { backdropFilter: 'none' }
209
+ };
210
+
211
+ // =========================
212
+ // ANIMATION KEYFRAMES
213
+ // =========================
214
+ export const keyframes = {
215
+ 'chai-pulse': {
216
+ '0%, 100%': { opacity: 1 },
217
+ '50%': { opacity: 0.5 }
218
+ },
219
+
220
+ 'chai-spin': {
221
+ from: { transform: 'rotate(0deg)' },
222
+ to: { transform: 'rotate(360deg)' }
223
+ },
224
+
225
+ 'chai-bounce': {
226
+ '0%, 100%': {
227
+ transform: 'translateY(-25%)',
228
+ animationTimingFunction: 'cubic-bezier(0.8, 0, 1, 1)'
229
+ },
230
+ '50%': {
231
+ transform: 'translateY(0)',
232
+ animationTimingFunction: 'cubic-bezier(0, 0, 0.2, 1)'
233
+ }
234
+ },
235
+
236
+ 'chai-fade-in': {
237
+ from: { opacity: 0 },
238
+ to: { opacity: 1 }
239
+ },
240
+
241
+ 'chai-slide-in': {
242
+ from: { transform: 'translateX(-100%)' },
243
+ to: { transform: 'translateX(0)' }
244
+ }
245
+ };
246
+
247
+ // =========================
248
+ // ANIMATION UTILITIES
249
+ // =========================
250
+ export const animationStyles = {
251
+ 'chai-animate-pulse': {
252
+ animation: 'chai-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite'
253
+ },
254
+
255
+ 'chai-animate-spin': {
256
+ animation: 'chai-spin 1s linear infinite'
257
+ },
258
+
259
+ 'chai-animate-bounce': {
260
+ animation: 'chai-bounce 1s infinite'
261
+ },
262
+
263
+ 'chai-animate-fade-in': {
264
+ animation: 'chai-fade-in 0.5s ease-in'
265
+ },
266
+
267
+ 'chai-animate-slide-in': {
268
+ animation: 'chai-slide-in 0.3s ease-out'
269
+ },
270
+
271
+ 'chai-animate-none': {
272
+ animation: 'none'
273
+ }
274
+ };
275
+
276
+ // =========================
277
+ // MEDIA QUERY STYLES (Responsive)
278
+ // =========================
279
+ export const responsiveStyles = {
280
+ // Small screens (max-width: 640px)
281
+ '@media (max-width: 640px)': {
282
+ '.chai-sm-hidden': { display: 'none' },
283
+ '.chai-sm-block': { display: 'block' },
284
+ '.chai-sm-flex': { display: 'flex' },
285
+ '.chai-sm-text-center': { textAlign: 'center' },
286
+ '.chai-sm-p-10': { padding: '40px' },
287
+ '.chai-sm-m-10': { margin: '40px' }
288
+ },
289
+
290
+ // Medium screens (641px - 768px)
291
+ '@media (min-width: 641px) and (max-width: 768px)': {
292
+ '.chai-md-hidden': { display: 'none' },
293
+ '.chai-md-block': { display: 'block' },
294
+ '.chai-md-flex': { display: 'flex' }
295
+ },
296
+
297
+ // Large screens (min-width: 769px)
298
+ '@media (min-width: 769px)': {
299
+ '.chai-lg-hidden': { display: 'none' },
300
+ '.chai-lg-block': { display: 'block' },
301
+ '.chai-lg-flex': { display: 'flex' }
302
+ }
303
+ };
304
+
305
+ // =========================
306
+ // PRINT STYLES
307
+ // =========================
308
+ export const printStyles = {
309
+ '@media print': {
310
+ '.chai-print-hidden': { display: 'none' },
311
+ '.chai-print-block': { display: 'block' },
312
+ '.chai-print-text-black': { color: '#000000' },
313
+ '.chai-print-bg-white': { backgroundColor: '#ffffff' }
314
+ }
315
+ };
316
+
317
+ // =========================
318
+ // ACCESSIBILITY UTILITIES
319
+ // =========================
320
+ export const accessibilityStyles = {
321
+ 'chai-sr-only': {
322
+ position: 'absolute',
323
+ width: '1px',
324
+ height: '1px',
325
+ padding: '0',
326
+ margin: '-1px',
327
+ overflow: 'hidden',
328
+ clip: 'rect(0, 0, 0, 0)',
329
+ whiteSpace: 'nowrap',
330
+ borderWidth: '0'
331
+ },
332
+
333
+ 'chai-not-sr-only': {
334
+ position: 'static',
335
+ width: 'auto',
336
+ height: 'auto',
337
+ padding: '0',
338
+ margin: '0',
339
+ overflow: 'visible',
340
+ clip: 'auto',
341
+ whiteSpace: 'normal'
342
+ },
343
+
344
+ 'chai-focus-ring:focus': {
345
+ outline: '2px solid #3b82f6',
346
+ outlineOffset: '2px'
347
+ },
348
+
349
+ 'chai-focus-ring-offset:focus': {
350
+ outline: '2px solid #3b82f6',
351
+ outlineOffset: '4px'
352
+ }
353
+ };
354
+
355
+ // =========================
356
+ // DARK MODE SUPPORT
357
+ // =========================
358
+ export const darkModeStyles = {
359
+ '@media (prefers-color-scheme: dark)': {
360
+ '.chai-dark-bg-gray-800': { backgroundColor: '#1f2937' },
361
+ '.chai-dark-bg-gray-900': { backgroundColor: '#111827' },
362
+ '.chai-dark-text-white': { color: '#ffffff' },
363
+ '.chai-dark-text-gray-300': { color: '#d1d5db' },
364
+ '.chai-dark-border-gray-700': { borderColor: '#374151' }
365
+ }
366
+ };
367
+
368
+ // =========================
369
+ // CUSTOM SCROLLBAR STYLES
370
+ // =========================
371
+ export const scrollbarStyles = {
372
+ '.chai-scrollbar-thin::-webkit-scrollbar': {
373
+ width: '6px',
374
+ height: '6px'
375
+ },
376
+
377
+ '.chai-scrollbar-thin::-webkit-scrollbar-track': {
378
+ background: '#f1f1f1',
379
+ borderRadius: '3px'
380
+ },
381
+
382
+ '.chai-scrollbar-thin::-webkit-scrollbar-thumb': {
383
+ background: '#888',
384
+ borderRadius: '3px'
385
+ },
386
+
387
+ '.chai-scrollbar-thin::-webkit-scrollbar-thumb:hover': {
388
+ background: '#555'
389
+ },
390
+
391
+ '.chai-scrollbar-hidden::-webkit-scrollbar': {
392
+ display: 'none'
393
+ }
394
+ };
395
+
396
+ // =========================
397
+ // GRID UTILITIES
398
+ // =========================
399
+ export const gridStyles = {
400
+ 'chai-grid-cols-1': { gridTemplateColumns: 'repeat(1, minmax(0, 1fr))' },
401
+ 'chai-grid-cols-2': { gridTemplateColumns: 'repeat(2, minmax(0, 1fr))' },
402
+ 'chai-grid-cols-3': { gridTemplateColumns: 'repeat(3, minmax(0, 1fr))' },
403
+ 'chai-grid-cols-4': { gridTemplateColumns: 'repeat(4, minmax(0, 1fr))' },
404
+ 'chai-grid-cols-5': { gridTemplateColumns: 'repeat(5, minmax(0, 1fr))' },
405
+ 'chai-gap-0': { gap: '0' },
406
+ 'chai-gap-4': { gap: '16px' },
407
+ 'chai-gap-8': { gap: '32px' }
408
+ };
409
+
410
+ // =========================
411
+ // BACKGROUND GRADIENTS
412
+ // =========================
413
+ export const gradientStyles = {
414
+ 'chai-bg-gradient-to-r': {
415
+ backgroundImage: 'linear-gradient(to right, var(--tw-gradient-stops))'
416
+ },
417
+ 'chai-bg-gradient-to-l': {
418
+ backgroundImage: 'linear-gradient(to left, var(--tw-gradient-stops))'
419
+ },
420
+ 'chai-from-red': { '--tw-gradient-from': '#ef4444' },
421
+ 'chai-to-blue': { '--tw-gradient-to': '#3b82f6' },
422
+ 'chai-from-green': { '--tw-gradient-from': '#22c55e' },
423
+ 'chai-to-purple': { '--tw-gradient-to': '#a855f7' }
424
+ };
425
+
426
+ // =========================
427
+ // COMBINE ALL STYLES
428
+ // =========================
429
+ export const allStyles = {
430
+ ...baseStyles,
431
+ ...hoverStyles,
432
+ ...displayStyles,
433
+ ...positionStyles,
434
+ ...zIndexStyles,
435
+ ...cursorStyles,
436
+ ...opacityStyles,
437
+ ...overflowStyles,
438
+ ...transformOriginStyles,
439
+ ...boxSizingStyles,
440
+ ...userSelectStyles,
441
+ ...pointerEventsStyles,
442
+ ...resizeStyles,
443
+ ...scrollStyles,
444
+ ...backdropStyles,
445
+ ...animationStyles,
446
+ ...responsiveStyles,
447
+ ...printStyles,
448
+ ...accessibilityStyles,
449
+ ...darkModeStyles,
450
+ ...scrollbarStyles,
451
+ ...gridStyles,
452
+ ...gradientStyles
453
+ };
454
+
455
+ // =========================
456
+ // FUNCTION TO GENERATE CSS TEXT
457
+ // =========================
458
+ export function generateCSS() {
459
+ let cssString = '';
460
+
461
+ function processStyles(styles, selector = '') {
462
+ Object.entries(styles).forEach(([key, value]) => {
463
+ if (typeof value === 'object' && !Array.isArray(value)) {
464
+ // Handle nested objects (media queries, pseudo-classes)
465
+ if (key.startsWith('@') || key.includes(':')) {
466
+ cssString += `${key} {\n`;
467
+ processStyles(value);
468
+ cssString += `}\n`;
469
+ } else {
470
+ // Handle regular CSS rules
471
+ const formattedKey = selector ? `${selector} ${key}` : key;
472
+ cssString += `${formattedKey} {\n`;
473
+ Object.entries(value).forEach(([prop, val]) => {
474
+ cssString += ` ${prop}: ${val};\n`;
475
+ });
476
+ cssString += `}\n`;
477
+ }
478
+ }
479
+ });
480
+ }
481
+
482
+ processStyles(allStyles);
483
+ return cssString;
484
+ }
485
+
486
+ // =========================
487
+ // FUNCTION TO INJECT STYLES INTO DOM
488
+ // =========================
489
+ export function injectStyles() {
490
+ if (typeof document !== 'undefined') {
491
+ const styleElement = document.createElement('style');
492
+ styleElement.id = 'teawind-styles';
493
+ styleElement.textContent = generateCSS();
494
+ document.head.appendChild(styleElement);
495
+ console.log('🍵 Teawind styles injected successfully');
496
+ }
497
+ }
498
+
499
+ // Export all style groups
500
+ export default {
501
+ base: baseStyles,
502
+ hover: hoverStyles,
503
+ display: displayStyles,
504
+ position: positionStyles,
505
+ zIndex: zIndexStyles,
506
+ cursor: cursorStyles,
507
+ opacity: opacityStyles,
508
+ overflow: overflowStyles,
509
+ transformOrigin: transformOriginStyles,
510
+ boxSizing: boxSizingStyles,
511
+ userSelect: userSelectStyles,
512
+ pointerEvents: pointerEventsStyles,
513
+ resize: resizeStyles,
514
+ scroll: scrollStyles,
515
+ backdrop: backdropStyles,
516
+ animations: animationStyles,
517
+ responsive: responsiveStyles,
518
+ print: printStyles,
519
+ accessibility: accessibilityStyles,
520
+ darkMode: darkModeStyles,
521
+ scrollbar: scrollbarStyles,
522
+ grid: gridStyles,
523
+ gradients: gradientStyles,
524
+ keyframes,
525
+ generateCSS,
526
+ injectStyles,
527
+ all: allStyles
528
+ };
package/src/index.js ADDED
@@ -0,0 +1,155 @@
1
+ // // Main entry point for teawind package
2
+ // import { parseDynamicClass, styleMap } from './core/parser.js';
3
+ // import { observeAndApplyStyles } from './core/observer.js';
4
+
5
+ // // Store original styles for hover effects
6
+ // let hoverStyles = new Map();
7
+
8
+ // // Apply styles to a single element
9
+ // export function applyStyles(element) {
10
+ // if (!element || !element.className) return;
11
+
12
+ // const classNames = element.className.split(/\s+/);
13
+ // const styleToApply = {};
14
+ // const remainingClasses = [];
15
+
16
+ // classNames.forEach((className) => {
17
+ // if (className.startsWith("chai-")) {
18
+ // const cleanClass = className.replace("chai-", "");
19
+ // const style = styleMap[cleanClass];
20
+
21
+ // if (style) {
22
+ // Object.assign(styleToApply, style);
23
+ // }
24
+
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
+
34
+ // // Apply hover effects
35
+ // applyHoverEffects(element);
36
+ // }
37
+
38
+ // // Apply hover effects
39
+ // function applyHoverEffects(element) {
40
+ // const classNames = element.className.split(/\s+/);
41
+
42
+ // classNames.forEach(className => {
43
+ // if (className === "chai-hover-scale") {
44
+ // element.addEventListener("mouseenter", () => {
45
+ // element.style.transform = "scale(1.05)";
46
+ // element.style.transition = "transform 0.2s";
47
+ // });
48
+ // element.addEventListener("mouseleave", () => {
49
+ // element.style.transform = "scale(1)";
50
+ // });
51
+ // }
52
+
53
+ // if (className === "chai-hover-bg-red") {
54
+ // const originalBg = element.style.backgroundColor;
55
+ // element.addEventListener("mouseenter", () => {
56
+ // element.style.backgroundColor = "#ef4444";
57
+ // });
58
+ // element.addEventListener("mouseleave", () => {
59
+ // element.style.backgroundColor = originalBg || "";
60
+ // });
61
+ // }
62
+
63
+ // if (className === "chai-hover-text-white") {
64
+ // const originalColor = element.style.color;
65
+ // element.addEventListener("mouseenter", () => {
66
+ // element.style.color = "#ffffff";
67
+ // });
68
+ // element.addEventListener("mouseleave", () => {
69
+ // element.style.color = originalColor || "";
70
+ // });
71
+ // }
72
+
73
+ // if (className === "chai-hover-shadow") {
74
+ // element.addEventListener("mouseenter", () => {
75
+ // element.style.boxShadow = "0 10px 25px rgba(0,0,0,0.15)";
76
+ // });
77
+ // element.addEventListener("mouseleave", () => {
78
+ // element.style.boxShadow = "";
79
+ // });
80
+ // }
81
+
82
+ // if (className === "chai-hover-border") {
83
+ // element.addEventListener("mouseenter", () => {
84
+ // element.style.borderColor = "#ef4444";
85
+ // element.style.borderWidth = "2px";
86
+ // });
87
+ // element.addEventListener("mouseleave", () => {
88
+ // element.style.borderColor = "";
89
+ // element.style.borderWidth = "";
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';
133
+
134
+ // Inject base styles when the engine loads
135
+ if (typeof document !== 'undefined') {
136
+ injectStyles();
137
+ }
138
+
139
+ // Export everything
140
+ export { styleMap, parseDynamicClass };
141
+ export { initObserver };
142
+ export { injectStyles, keyframes };
143
+
144
+ // Main initialization function
145
+ export function initTeawind(container = document.body, options = {}) {
146
+ return initObserver(container, options);
147
+ }
148
+
149
+ // Default export
150
+ export default {
151
+ init: initTeawind,
152
+ injectStyles,
153
+ keyframes,
154
+ version: '1.0.0'
155
+ };
File without changes