@bookklik/senangstart-css 0.1.0 → 0.1.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.
Files changed (137) hide show
  1. package/.github/workflows/deploy-docs.yml +55 -0
  2. package/dist/senangstart-css.js +503 -0
  3. package/dist/senangstart-css.min.js +375 -0
  4. package/docs/.vitepress/cache/deps/_metadata.json +52 -0
  5. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js +9719 -0
  6. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js.map +7 -0
  7. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js +12824 -0
  8. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js.map +7 -0
  9. package/docs/.vitepress/cache/deps/package.json +3 -0
  10. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
  11. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  12. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +583 -0
  13. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  14. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1333 -0
  15. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  16. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1665 -0
  17. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  18. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1813 -0
  19. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  20. package/docs/.vitepress/cache/deps/vue.js +347 -0
  21. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  22. package/docs/.vitepress/config.js +108 -0
  23. package/docs/.vitepress/dist/404.html +22 -0
  24. package/docs/.vitepress/dist/assets/app.BTYj1wZj.js +1 -0
  25. package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.DmMP4oUp.js +1 -0
  26. package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.jxQ0k_uL.js +9 -0
  27. package/docs/.vitepress/dist/assets/chunks/framework.qISVh_QZ.js +19 -0
  28. package/docs/.vitepress/dist/assets/chunks/theme.B9Wtbwgj.js +2 -0
  29. package/docs/.vitepress/dist/assets/examples_cards.md.D4i0phvj.js +84 -0
  30. package/docs/.vitepress/dist/assets/examples_cards.md.D4i0phvj.lean.js +1 -0
  31. package/docs/.vitepress/dist/assets/examples_forms.md.BnsjqHST.js +169 -0
  32. package/docs/.vitepress/dist/assets/examples_forms.md.BnsjqHST.lean.js +1 -0
  33. package/docs/.vitepress/dist/assets/examples_hero.md.CCcb2x8Y.js +118 -0
  34. package/docs/.vitepress/dist/assets/examples_hero.md.CCcb2x8Y.lean.js +1 -0
  35. package/docs/.vitepress/dist/assets/examples_index.md.CcyXbirn.js +52 -0
  36. package/docs/.vitepress/dist/assets/examples_index.md.CcyXbirn.lean.js +1 -0
  37. package/docs/.vitepress/dist/assets/examples_navigation.md.CppyHbnP.js +106 -0
  38. package/docs/.vitepress/dist/assets/examples_navigation.md.CppyHbnP.lean.js +1 -0
  39. package/docs/.vitepress/dist/assets/guide_cdn.md.CANCjnm5.js +30 -0
  40. package/docs/.vitepress/dist/assets/guide_cdn.md.CANCjnm5.lean.js +1 -0
  41. package/docs/.vitepress/dist/assets/guide_cli.md.zXEKk-bu.js +44 -0
  42. package/docs/.vitepress/dist/assets/guide_cli.md.zXEKk-bu.lean.js +1 -0
  43. package/docs/.vitepress/dist/assets/guide_configuration.md.D2JZzhKm.js +79 -0
  44. package/docs/.vitepress/dist/assets/guide_configuration.md.D2JZzhKm.lean.js +1 -0
  45. package/docs/.vitepress/dist/assets/guide_getting-started.md.tO7bvmZd.js +47 -0
  46. package/docs/.vitepress/dist/assets/guide_getting-started.md.tO7bvmZd.lean.js +1 -0
  47. package/docs/.vitepress/dist/assets/guide_index.md.C1xk2lBl.js +3 -0
  48. package/docs/.vitepress/dist/assets/guide_index.md.C1xk2lBl.lean.js +1 -0
  49. package/docs/.vitepress/dist/assets/guide_natural-scale.md.D1oVRN5V.js +22 -0
  50. package/docs/.vitepress/dist/assets/guide_natural-scale.md.D1oVRN5V.lean.js +1 -0
  51. package/docs/.vitepress/dist/assets/guide_philosophy.md.DPyyMH8d.js +7 -0
  52. package/docs/.vitepress/dist/assets/guide_philosophy.md.DPyyMH8d.lean.js +1 -0
  53. package/docs/.vitepress/dist/assets/guide_responsive.md.wksOAMT5.js +57 -0
  54. package/docs/.vitepress/dist/assets/guide_responsive.md.wksOAMT5.lean.js +1 -0
  55. package/docs/.vitepress/dist/assets/guide_states.md.DRjYOZDJ.js +77 -0
  56. package/docs/.vitepress/dist/assets/guide_states.md.DRjYOZDJ.lean.js +1 -0
  57. package/docs/.vitepress/dist/assets/guide_tri-attribute.md.CoFqfmPZ.js +45 -0
  58. package/docs/.vitepress/dist/assets/guide_tri-attribute.md.CoFqfmPZ.lean.js +1 -0
  59. package/docs/.vitepress/dist/assets/index.md.CUZJzNzP.js +7 -0
  60. package/docs/.vitepress/dist/assets/index.md.CUZJzNzP.lean.js +1 -0
  61. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  62. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  63. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  64. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  65. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  66. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  67. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  68. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  69. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  70. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  71. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  72. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  73. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  74. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  75. package/docs/.vitepress/dist/assets/reference_breakpoints.md.BEhuwXBS.js +48 -0
  76. package/docs/.vitepress/dist/assets/reference_breakpoints.md.BEhuwXBS.lean.js +1 -0
  77. package/docs/.vitepress/dist/assets/reference_colors.md.Do4abjs1.js +29 -0
  78. package/docs/.vitepress/dist/assets/reference_colors.md.Do4abjs1.lean.js +1 -0
  79. package/docs/.vitepress/dist/assets/reference_layout.md.DqSoofMZ.js +13 -0
  80. package/docs/.vitepress/dist/assets/reference_layout.md.DqSoofMZ.lean.js +1 -0
  81. package/docs/.vitepress/dist/assets/reference_space.md.luOYAfQg.js +24 -0
  82. package/docs/.vitepress/dist/assets/reference_space.md.luOYAfQg.lean.js +1 -0
  83. package/docs/.vitepress/dist/assets/reference_spacing.md.DdsDhDhS.js +32 -0
  84. package/docs/.vitepress/dist/assets/reference_spacing.md.DdsDhDhS.lean.js +1 -0
  85. package/docs/.vitepress/dist/assets/reference_visual.md.DZFvxgPk.js +22 -0
  86. package/docs/.vitepress/dist/assets/reference_visual.md.DZFvxgPk.lean.js +1 -0
  87. package/docs/.vitepress/dist/assets/style.BuMqNgkb.css +1 -0
  88. package/docs/.vitepress/dist/examples/cards.html +108 -0
  89. package/docs/.vitepress/dist/examples/forms.html +193 -0
  90. package/docs/.vitepress/dist/examples/hero.html +142 -0
  91. package/docs/.vitepress/dist/examples/index.html +76 -0
  92. package/docs/.vitepress/dist/examples/navigation.html +130 -0
  93. package/docs/.vitepress/dist/guide/cdn.html +54 -0
  94. package/docs/.vitepress/dist/guide/cli.html +68 -0
  95. package/docs/.vitepress/dist/guide/configuration.html +103 -0
  96. package/docs/.vitepress/dist/guide/getting-started.html +71 -0
  97. package/docs/.vitepress/dist/guide/index.html +27 -0
  98. package/docs/.vitepress/dist/guide/natural-scale.html +46 -0
  99. package/docs/.vitepress/dist/guide/philosophy.html +31 -0
  100. package/docs/.vitepress/dist/guide/responsive.html +81 -0
  101. package/docs/.vitepress/dist/guide/states.html +101 -0
  102. package/docs/.vitepress/dist/guide/tri-attribute.html +69 -0
  103. package/docs/.vitepress/dist/hashmap.json +1 -0
  104. package/docs/.vitepress/dist/index.html +31 -0
  105. package/docs/.vitepress/dist/reference/breakpoints.html +72 -0
  106. package/docs/.vitepress/dist/reference/colors.html +53 -0
  107. package/docs/.vitepress/dist/reference/layout.html +37 -0
  108. package/docs/.vitepress/dist/reference/space.html +48 -0
  109. package/docs/.vitepress/dist/reference/spacing.html +56 -0
  110. package/docs/.vitepress/dist/reference/visual.html +46 -0
  111. package/docs/.vitepress/dist/vp-icons.css +1 -0
  112. package/docs/.vitepress/theme/custom.css +65 -0
  113. package/docs/.vitepress/theme/index.js +4 -0
  114. package/docs/examples/cards.md +116 -0
  115. package/docs/examples/forms.md +207 -0
  116. package/docs/examples/hero.md +150 -0
  117. package/docs/examples/index.md +87 -0
  118. package/docs/examples/navigation.md +144 -0
  119. package/docs/guide/cdn.md +110 -0
  120. package/docs/guide/cli.md +174 -0
  121. package/docs/guide/configuration.md +152 -0
  122. package/docs/guide/getting-started.md +130 -0
  123. package/docs/guide/index.md +64 -0
  124. package/docs/guide/natural-scale.md +123 -0
  125. package/docs/guide/philosophy.md +103 -0
  126. package/docs/guide/responsive.md +129 -0
  127. package/docs/guide/states.md +162 -0
  128. package/docs/guide/tri-attribute.md +187 -0
  129. package/docs/index.md +64 -0
  130. package/docs/reference/breakpoints.md +131 -0
  131. package/docs/reference/colors.md +106 -0
  132. package/docs/reference/layout.md +115 -0
  133. package/docs/reference/space.md +121 -0
  134. package/docs/reference/spacing.md +74 -0
  135. package/docs/reference/visual.md +160 -0
  136. package/package.json +7 -13
  137. package/scripts/build-dist.js +49 -0
@@ -0,0 +1,55 @@
1
+ name: Deploy VitePress to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: pages
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@v4
23
+ with:
24
+ fetch-depth: 0
25
+
26
+ - name: Setup Node
27
+ uses: actions/setup-node@v4
28
+ with:
29
+ node-version: 20
30
+ cache: npm
31
+
32
+ - name: Setup Pages
33
+ uses: actions/configure-pages@v4
34
+
35
+ - name: Install dependencies
36
+ run: npm ci
37
+
38
+ - name: Build with VitePress
39
+ run: npm run docs:build
40
+
41
+ - name: Upload artifact
42
+ uses: actions/upload-pages-artifact@v3
43
+ with:
44
+ path: docs/.vitepress/dist
45
+
46
+ deploy:
47
+ environment:
48
+ name: github-pages
49
+ url: ${{ steps.deployment.outputs.page_url }}
50
+ needs: build
51
+ runs-on: ubuntu-latest
52
+ steps:
53
+ - name: Deploy to GitHub Pages
54
+ id: deployment
55
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,503 @@
1
+ /**
2
+ * SenangStart CSS - Browser JIT Runtime
3
+ * Zero-config, browser-based CSS compilation
4
+ *
5
+ * Usage:
6
+ * <script src="https://cdn.senangstart.dev/jit.js"></script>
7
+ *
8
+ * Or with custom config:
9
+ * <script type="senangstart/config">{ "theme": { "colors": { "brand": "#8B5CF6" } } }</script>
10
+ * <script src="https://cdn.senangstart.dev/jit.js"></script>
11
+ */
12
+
13
+ (function() {
14
+ 'use strict';
15
+
16
+ // ============================================
17
+ // DEFAULT CONFIGURATION
18
+ // ============================================
19
+
20
+ const defaultConfig = {
21
+ theme: {
22
+ spacing: {
23
+ 'none': '0px',
24
+ 'tiny': '4px',
25
+ 'small': '8px',
26
+ 'medium': '16px',
27
+ 'big': '32px',
28
+ 'giant': '64px',
29
+ 'vast': '128px'
30
+ },
31
+ radius: {
32
+ 'none': '0px',
33
+ 'small': '4px',
34
+ 'medium': '8px',
35
+ 'big': '16px',
36
+ 'round': '9999px'
37
+ },
38
+ shadow: {
39
+ 'none': 'none',
40
+ 'small': '0 1px 2px rgba(0,0,0,0.05)',
41
+ 'medium': '0 4px 6px rgba(0,0,0,0.1)',
42
+ 'big': '0 10px 15px rgba(0,0,0,0.15)',
43
+ 'giant': '0 25px 50px rgba(0,0,0,0.25)'
44
+ },
45
+ fontSize: {
46
+ 'tiny': '12px',
47
+ 'small': '14px',
48
+ 'medium': '16px',
49
+ 'big': '20px',
50
+ 'giant': '32px',
51
+ 'vast': '48px'
52
+ },
53
+ fontWeight: {
54
+ 'normal': '400',
55
+ 'medium': '500',
56
+ 'bold': '700'
57
+ },
58
+ screens: {
59
+ 'mob': '480px',
60
+ 'tab': '768px',
61
+ 'lap': '1024px',
62
+ 'desk': '1280px'
63
+ },
64
+ colors: {
65
+ 'white': '#FFFFFF',
66
+ 'black': '#000000',
67
+ 'grey': '#6B7280',
68
+ 'dark': '#3E4A5D', // Brand dark
69
+ 'light': '#DBEAFE', // Brand light/secondary
70
+ 'primary': '#2563EB', // Brand primary
71
+ 'secondary': '#DBEAFE', // Brand secondary
72
+ 'success': '#10B981',
73
+ 'warning': '#F59E0B',
74
+ 'danger': '#EF4444'
75
+ },
76
+ zIndex: {
77
+ 'base': '0',
78
+ 'low': '10',
79
+ 'mid': '50',
80
+ 'high': '100',
81
+ 'top': '9999'
82
+ }
83
+ }
84
+ };
85
+
86
+ // ============================================
87
+ // CONFIG LOADER
88
+ // ============================================
89
+
90
+ function loadInlineConfig() {
91
+ const configEl = document.querySelector('script[type="senangstart/config"]');
92
+ if (!configEl) return {};
93
+
94
+ try {
95
+ return JSON.parse(configEl.textContent);
96
+ } catch (e) {
97
+ console.error('[SenangStart] Invalid config JSON:', e);
98
+ return {};
99
+ }
100
+ }
101
+
102
+ function mergeConfig(user) {
103
+ const merged = JSON.parse(JSON.stringify(defaultConfig));
104
+
105
+ if (user.theme) {
106
+ for (const key of Object.keys(merged.theme)) {
107
+ if (user.theme[key]) {
108
+ merged.theme[key] = { ...merged.theme[key], ...user.theme[key] };
109
+ }
110
+ }
111
+ }
112
+
113
+ return merged;
114
+ }
115
+
116
+ // ============================================
117
+ // CSS VARIABLE GENERATOR
118
+ // ============================================
119
+
120
+ function generateCSSVariables(config) {
121
+ const { theme } = config;
122
+ let css = ':root {\n';
123
+
124
+ // Spacing
125
+ for (const [key, value] of Object.entries(theme.spacing)) {
126
+ css += ` --s-${key}: ${value};\n`;
127
+ }
128
+
129
+ // Radius
130
+ for (const [key, value] of Object.entries(theme.radius)) {
131
+ css += ` --r-${key}: ${value};\n`;
132
+ }
133
+
134
+ // Shadow
135
+ for (const [key, value] of Object.entries(theme.shadow)) {
136
+ css += ` --shadow-${key}: ${value};\n`;
137
+ }
138
+
139
+ // Font size
140
+ for (const [key, value] of Object.entries(theme.fontSize)) {
141
+ css += ` --font-${key}: ${value};\n`;
142
+ }
143
+
144
+ // Font weight
145
+ for (const [key, value] of Object.entries(theme.fontWeight)) {
146
+ css += ` --fw-${key}: ${value};\n`;
147
+ }
148
+
149
+ // Colors
150
+ for (const [key, value] of Object.entries(theme.colors)) {
151
+ css += ` --c-${key}: ${value};\n`;
152
+ }
153
+
154
+ // Z-index
155
+ for (const [key, value] of Object.entries(theme.zIndex)) {
156
+ css += ` --z-${key}: ${value};\n`;
157
+ }
158
+
159
+ css += '}\n\n';
160
+ css += '*, *::before, *::after { box-sizing: border-box; }\n\n';
161
+
162
+ return css;
163
+ }
164
+
165
+ // ============================================
166
+ // LAYOUT KEYWORDS
167
+ // ============================================
168
+
169
+ const layoutKeywords = {
170
+ 'flex': 'display: flex;',
171
+ 'grid': 'display: grid;',
172
+ 'block': 'display: block;',
173
+ 'inline': 'display: inline-block;',
174
+ 'hidden': 'display: none;',
175
+ 'row': 'flex-direction: row;',
176
+ 'col': 'flex-direction: column;',
177
+ 'row-reverse': 'flex-direction: row-reverse;',
178
+ 'col-reverse': 'flex-direction: column-reverse;',
179
+ 'center': 'justify-content: center; align-items: center;',
180
+ 'start': 'justify-content: flex-start; align-items: flex-start;',
181
+ 'end': 'justify-content: flex-end; align-items: flex-end;',
182
+ 'between': 'justify-content: space-between;',
183
+ 'around': 'justify-content: space-around;',
184
+ 'evenly': 'justify-content: space-evenly;',
185
+ 'wrap': 'flex-wrap: wrap;',
186
+ 'nowrap': 'flex-wrap: nowrap;',
187
+ 'absolute': 'position: absolute;',
188
+ 'relative': 'position: relative;',
189
+ 'fixed': 'position: fixed;',
190
+ 'sticky': 'position: sticky;'
191
+ };
192
+
193
+ // ============================================
194
+ // RULE GENERATORS
195
+ // ============================================
196
+
197
+ const breakpoints = ['mob', 'tab', 'lap', 'desk'];
198
+ const states = ['hover', 'focus', 'active', 'disabled'];
199
+
200
+ function parseToken(raw) {
201
+ const token = {
202
+ raw,
203
+ breakpoint: null,
204
+ state: null,
205
+ property: null,
206
+ value: null,
207
+ isArbitrary: false
208
+ };
209
+
210
+ const parts = raw.split(':');
211
+ let idx = 0;
212
+
213
+ // Check for breakpoint
214
+ if (breakpoints.includes(parts[0])) {
215
+ token.breakpoint = parts[0];
216
+ idx++;
217
+ }
218
+
219
+ // Check for state
220
+ if (states.includes(parts[idx])) {
221
+ token.state = parts[idx];
222
+ idx++;
223
+ }
224
+
225
+ // Property
226
+ if (idx < parts.length) {
227
+ token.property = parts[idx];
228
+ idx++;
229
+ }
230
+
231
+ // Value
232
+ if (idx < parts.length) {
233
+ let value = parts.slice(idx).join(':');
234
+ const arbitraryMatch = value.match(/^\[(.+)\]$/);
235
+ if (arbitraryMatch) {
236
+ token.value = arbitraryMatch[1].replace(/_/g, ' ');
237
+ token.isArbitrary = true;
238
+ } else {
239
+ token.value = value;
240
+ }
241
+ }
242
+
243
+ return token;
244
+ }
245
+
246
+ function generateLayoutRule(token) {
247
+ const { property, value } = token;
248
+
249
+ // Z-index
250
+ if (property === 'z') {
251
+ return `z-index: var(--z-${value});`;
252
+ }
253
+
254
+ // Overflow
255
+ if (property === 'overflow') {
256
+ return `overflow: ${value};`;
257
+ }
258
+
259
+ return layoutKeywords[property] || '';
260
+ }
261
+
262
+ function generateSpaceRule(token) {
263
+ const { property, value, isArbitrary } = token;
264
+
265
+ if (value === 'auto') {
266
+ const autoMap = {
267
+ 'm': 'margin: auto;',
268
+ 'm-x': 'margin-left: auto; margin-right: auto;',
269
+ 'm-y': 'margin-top: auto; margin-bottom: auto;',
270
+ 'm-t': 'margin-top: auto;',
271
+ 'm-r': 'margin-right: auto;',
272
+ 'm-b': 'margin-bottom: auto;',
273
+ 'm-l': 'margin-left: auto;'
274
+ };
275
+ return autoMap[property] || '';
276
+ }
277
+
278
+ const cssValue = isArbitrary ? value : `var(--s-${value})`;
279
+
280
+ const map = {
281
+ 'p': `padding: ${cssValue};`,
282
+ 'p-t': `padding-top: ${cssValue};`,
283
+ 'p-r': `padding-right: ${cssValue};`,
284
+ 'p-b': `padding-bottom: ${cssValue};`,
285
+ 'p-l': `padding-left: ${cssValue};`,
286
+ 'p-x': `padding-left: ${cssValue}; padding-right: ${cssValue};`,
287
+ 'p-y': `padding-top: ${cssValue}; padding-bottom: ${cssValue};`,
288
+ 'm': `margin: ${cssValue};`,
289
+ 'm-t': `margin-top: ${cssValue};`,
290
+ 'm-r': `margin-right: ${cssValue};`,
291
+ 'm-b': `margin-bottom: ${cssValue};`,
292
+ 'm-l': `margin-left: ${cssValue};`,
293
+ 'm-x': `margin-left: ${cssValue}; margin-right: ${cssValue};`,
294
+ 'm-y': `margin-top: ${cssValue}; margin-bottom: ${cssValue};`,
295
+ 'g': `gap: ${cssValue};`,
296
+ 'g-x': `column-gap: ${cssValue};`,
297
+ 'g-y': `row-gap: ${cssValue};`,
298
+ 'w': `width: ${cssValue};`,
299
+ 'h': `height: ${cssValue};`,
300
+ 'min-w': `min-width: ${cssValue};`,
301
+ 'max-w': `max-width: ${cssValue};`,
302
+ 'min-h': `min-height: ${cssValue};`,
303
+ 'max-h': `max-height: ${cssValue};`
304
+ };
305
+
306
+ return map[property] || '';
307
+ }
308
+
309
+ function generateVisualRule(token) {
310
+ const { property, value, isArbitrary } = token;
311
+
312
+ const rules = {
313
+ 'bg': () => {
314
+ const cssValue = isArbitrary ? value : `var(--c-${value})`;
315
+ return `background-color: ${cssValue};`;
316
+ },
317
+ 'text': () => {
318
+ if (['left', 'center', 'right'].includes(value)) {
319
+ return `text-align: ${value};`;
320
+ }
321
+ const cssValue = isArbitrary ? value : `var(--c-${value})`;
322
+ return `color: ${cssValue};`;
323
+ },
324
+ 'text-size': () => {
325
+ const cssValue = isArbitrary ? value : `var(--font-${value})`;
326
+ return `font-size: ${cssValue};`;
327
+ },
328
+ 'font': () => `font-weight: var(--fw-${value});`,
329
+ 'border': () => {
330
+ const cssValue = isArbitrary ? value : `var(--c-${value})`;
331
+ return `border-color: ${cssValue}; border-style: solid;`;
332
+ },
333
+ 'border-w': () => {
334
+ const cssValue = isArbitrary ? value : `var(--s-${value})`;
335
+ return `border-width: ${cssValue}; border-style: solid;`;
336
+ },
337
+ 'rounded': () => `border-radius: var(--r-${value});`,
338
+ 'shadow': () => `box-shadow: var(--shadow-${value});`,
339
+ 'opacity': () => `opacity: ${value};`
340
+ };
341
+
342
+ const gen = rules[property];
343
+ return gen ? gen() : '';
344
+ }
345
+
346
+ function generateRule(raw, attrType) {
347
+ // Handle simple layout keywords
348
+ if (attrType === 'layout' && layoutKeywords[raw]) {
349
+ return `[layout~="${raw}"] { ${layoutKeywords[raw]} }\n`;
350
+ }
351
+
352
+ const token = parseToken(raw);
353
+ let cssDeclaration = '';
354
+
355
+ switch (attrType) {
356
+ case 'layout':
357
+ cssDeclaration = generateLayoutRule(token);
358
+ break;
359
+ case 'space':
360
+ cssDeclaration = generateSpaceRule(token);
361
+ break;
362
+ case 'visual':
363
+ cssDeclaration = generateVisualRule(token);
364
+ break;
365
+ }
366
+
367
+ if (!cssDeclaration) return '';
368
+
369
+ let selector = `[${attrType}~="${raw}"]`;
370
+ if (token.state) {
371
+ selector += `:${token.state}`;
372
+ }
373
+
374
+ return `${selector} { ${cssDeclaration} }\n`;
375
+ }
376
+
377
+ // ============================================
378
+ // DOM SCANNER
379
+ // ============================================
380
+
381
+ function scanDOM() {
382
+ const tokens = {
383
+ layout: new Set(),
384
+ space: new Set(),
385
+ visual: new Set()
386
+ };
387
+
388
+ const elements = document.querySelectorAll('[layout], [space], [visual]');
389
+
390
+ elements.forEach(el => {
391
+ ['layout', 'space', 'visual'].forEach(attr => {
392
+ const value = el.getAttribute(attr);
393
+ if (value) {
394
+ value.split(/\s+/).forEach(token => {
395
+ if (token) tokens[attr].add(token);
396
+ });
397
+ }
398
+ });
399
+ });
400
+
401
+ return tokens;
402
+ }
403
+
404
+ // ============================================
405
+ // CSS COMPILER
406
+ // ============================================
407
+
408
+ function compileCSS(tokens, config) {
409
+ let css = generateCSSVariables(config);
410
+
411
+ const baseRules = [];
412
+ const mediaRules = {
413
+ mob: [],
414
+ tab: [],
415
+ lap: [],
416
+ desk: []
417
+ };
418
+
419
+ for (const [attrType, values] of Object.entries(tokens)) {
420
+ for (const raw of values) {
421
+ const rule = generateRule(raw, attrType);
422
+ if (rule) {
423
+ // Check for breakpoint prefix
424
+ const bpMatch = raw.match(/^(mob|tab|lap|desk):/);
425
+ if (bpMatch) {
426
+ mediaRules[bpMatch[1]].push(rule);
427
+ } else {
428
+ baseRules.push(rule);
429
+ }
430
+ }
431
+ }
432
+ }
433
+
434
+ // Add base rules
435
+ css += baseRules.join('');
436
+
437
+ // Add media queries
438
+ const { screens } = config.theme;
439
+ for (const [bp, rules] of Object.entries(mediaRules)) {
440
+ if (rules.length > 0) {
441
+ css += `\n@media (min-width: ${screens[bp]}) {\n`;
442
+ css += rules.map(r => ' ' + r).join('');
443
+ css += '}\n';
444
+ }
445
+ }
446
+
447
+ return css;
448
+ }
449
+
450
+ // ============================================
451
+ // STYLE INJECTION
452
+ // ============================================
453
+
454
+ function injectStyles(css) {
455
+ let styleEl = document.getElementById('senangstart-jit');
456
+ if (!styleEl) {
457
+ styleEl = document.createElement('style');
458
+ styleEl.id = 'senangstart-jit';
459
+ document.head.appendChild(styleEl);
460
+ }
461
+ styleEl.textContent = css;
462
+ }
463
+
464
+ // ============================================
465
+ // INITIALIZATION
466
+ // ============================================
467
+
468
+ function init() {
469
+ const userConfig = loadInlineConfig();
470
+ const config = mergeConfig(userConfig);
471
+
472
+ const tokens = scanDOM();
473
+ const css = compileCSS(tokens, config);
474
+ injectStyles(css);
475
+
476
+ // Watch for DOM changes
477
+ const observer = new MutationObserver(() => {
478
+ const newTokens = scanDOM();
479
+ const newCSS = compileCSS(newTokens, config);
480
+ injectStyles(newCSS);
481
+ });
482
+
483
+ observer.observe(document.body, {
484
+ childList: true,
485
+ subtree: true,
486
+ attributes: true,
487
+ attributeFilter: ['layout', 'space', 'visual']
488
+ });
489
+
490
+ console.log('%c[SenangStart CSS]%c JIT runtime initialized ✓',
491
+ 'color: #2563EB; font-weight: bold;',
492
+ 'color: #10B981;'
493
+ );
494
+ }
495
+
496
+ // Run on DOMContentLoaded or immediately if already loaded
497
+ if (document.readyState === 'loading') {
498
+ document.addEventListener('DOMContentLoaded', init);
499
+ } else {
500
+ init();
501
+ }
502
+
503
+ })();