@bookklik/senangstart-css 0.1.1 → 0.1.3

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 (141) hide show
  1. package/.github/workflows/deploy-docs.yml +55 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +17 -189
  4. package/dist/senangstart-css.js +503 -0
  5. package/dist/senangstart-css.min.js +375 -0
  6. package/docs/.vitepress/cache/deps/_metadata.json +52 -0
  7. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js +9719 -0
  8. package/docs/.vitepress/cache/deps/chunk-2CLQ7TTZ.js.map +7 -0
  9. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js +12824 -0
  10. package/docs/.vitepress/cache/deps/chunk-LE5NDSFD.js.map +7 -0
  11. package/docs/.vitepress/cache/deps/package.json +3 -0
  12. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
  13. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  14. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +583 -0
  15. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  16. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1333 -0
  17. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  18. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1665 -0
  19. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  20. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1813 -0
  21. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  22. package/docs/.vitepress/cache/deps/vue.js +347 -0
  23. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  24. package/docs/.vitepress/config.js +108 -0
  25. package/docs/.vitepress/dist/404.html +22 -0
  26. package/docs/.vitepress/dist/assets/app.CwVZm472.js +1 -0
  27. package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.BTWwOmXN.js +1 -0
  28. package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.B-RMQ_ux.js +9 -0
  29. package/docs/.vitepress/dist/assets/chunks/framework.qISVh_QZ.js +19 -0
  30. package/docs/.vitepress/dist/assets/chunks/theme.B37_rtT6.js +2 -0
  31. package/docs/.vitepress/dist/assets/examples_cards.md.D4i0phvj.js +84 -0
  32. package/docs/.vitepress/dist/assets/examples_cards.md.D4i0phvj.lean.js +1 -0
  33. package/docs/.vitepress/dist/assets/examples_forms.md.BnsjqHST.js +169 -0
  34. package/docs/.vitepress/dist/assets/examples_forms.md.BnsjqHST.lean.js +1 -0
  35. package/docs/.vitepress/dist/assets/examples_hero.md.CCcb2x8Y.js +118 -0
  36. package/docs/.vitepress/dist/assets/examples_hero.md.CCcb2x8Y.lean.js +1 -0
  37. package/docs/.vitepress/dist/assets/examples_index.md.Dj7lqhZt.js +52 -0
  38. package/docs/.vitepress/dist/assets/examples_index.md.Dj7lqhZt.lean.js +1 -0
  39. package/docs/.vitepress/dist/assets/examples_navigation.md.CppyHbnP.js +106 -0
  40. package/docs/.vitepress/dist/assets/examples_navigation.md.CppyHbnP.lean.js +1 -0
  41. package/docs/.vitepress/dist/assets/guide_cdn.md.BzsOep2E.js +30 -0
  42. package/docs/.vitepress/dist/assets/guide_cdn.md.BzsOep2E.lean.js +1 -0
  43. package/docs/.vitepress/dist/assets/guide_cli.md.zXEKk-bu.js +44 -0
  44. package/docs/.vitepress/dist/assets/guide_cli.md.zXEKk-bu.lean.js +1 -0
  45. package/docs/.vitepress/dist/assets/guide_configuration.md.D2JZzhKm.js +79 -0
  46. package/docs/.vitepress/dist/assets/guide_configuration.md.D2JZzhKm.lean.js +1 -0
  47. package/docs/.vitepress/dist/assets/guide_getting-started.md.to1dkMR9.js +47 -0
  48. package/docs/.vitepress/dist/assets/guide_getting-started.md.to1dkMR9.lean.js +1 -0
  49. package/docs/.vitepress/dist/assets/guide_index.md.C1xk2lBl.js +3 -0
  50. package/docs/.vitepress/dist/assets/guide_index.md.C1xk2lBl.lean.js +1 -0
  51. package/docs/.vitepress/dist/assets/guide_natural-scale.md.D1oVRN5V.js +22 -0
  52. package/docs/.vitepress/dist/assets/guide_natural-scale.md.D1oVRN5V.lean.js +1 -0
  53. package/docs/.vitepress/dist/assets/guide_philosophy.md.DPyyMH8d.js +7 -0
  54. package/docs/.vitepress/dist/assets/guide_philosophy.md.DPyyMH8d.lean.js +1 -0
  55. package/docs/.vitepress/dist/assets/guide_responsive.md.wksOAMT5.js +57 -0
  56. package/docs/.vitepress/dist/assets/guide_responsive.md.wksOAMT5.lean.js +1 -0
  57. package/docs/.vitepress/dist/assets/guide_states.md.DRjYOZDJ.js +77 -0
  58. package/docs/.vitepress/dist/assets/guide_states.md.DRjYOZDJ.lean.js +1 -0
  59. package/docs/.vitepress/dist/assets/guide_tri-attribute.md.CoFqfmPZ.js +45 -0
  60. package/docs/.vitepress/dist/assets/guide_tri-attribute.md.CoFqfmPZ.lean.js +1 -0
  61. package/docs/.vitepress/dist/assets/index.md.CUZJzNzP.js +7 -0
  62. package/docs/.vitepress/dist/assets/index.md.CUZJzNzP.lean.js +1 -0
  63. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  64. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  65. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  66. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  67. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  68. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  69. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  70. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  71. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  72. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  73. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  74. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  75. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  76. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  77. package/docs/.vitepress/dist/assets/reference_breakpoints.md.BEhuwXBS.js +48 -0
  78. package/docs/.vitepress/dist/assets/reference_breakpoints.md.BEhuwXBS.lean.js +1 -0
  79. package/docs/.vitepress/dist/assets/reference_colors.md.o5ltImYJ.js +17 -0
  80. package/docs/.vitepress/dist/assets/reference_colors.md.o5ltImYJ.lean.js +1 -0
  81. package/docs/.vitepress/dist/assets/reference_layout.md.DqSoofMZ.js +13 -0
  82. package/docs/.vitepress/dist/assets/reference_layout.md.DqSoofMZ.lean.js +1 -0
  83. package/docs/.vitepress/dist/assets/reference_space.md.luOYAfQg.js +24 -0
  84. package/docs/.vitepress/dist/assets/reference_space.md.luOYAfQg.lean.js +1 -0
  85. package/docs/.vitepress/dist/assets/reference_spacing.md.DdsDhDhS.js +32 -0
  86. package/docs/.vitepress/dist/assets/reference_spacing.md.DdsDhDhS.lean.js +1 -0
  87. package/docs/.vitepress/dist/assets/reference_visual.md.DZFvxgPk.js +22 -0
  88. package/docs/.vitepress/dist/assets/reference_visual.md.DZFvxgPk.lean.js +1 -0
  89. package/docs/.vitepress/dist/assets/style.BuMqNgkb.css +1 -0
  90. package/docs/.vitepress/dist/examples/cards.html +108 -0
  91. package/docs/.vitepress/dist/examples/forms.html +193 -0
  92. package/docs/.vitepress/dist/examples/hero.html +142 -0
  93. package/docs/.vitepress/dist/examples/index.html +76 -0
  94. package/docs/.vitepress/dist/examples/navigation.html +130 -0
  95. package/docs/.vitepress/dist/guide/cdn.html +54 -0
  96. package/docs/.vitepress/dist/guide/cli.html +68 -0
  97. package/docs/.vitepress/dist/guide/configuration.html +103 -0
  98. package/docs/.vitepress/dist/guide/getting-started.html +71 -0
  99. package/docs/.vitepress/dist/guide/index.html +27 -0
  100. package/docs/.vitepress/dist/guide/natural-scale.html +46 -0
  101. package/docs/.vitepress/dist/guide/philosophy.html +31 -0
  102. package/docs/.vitepress/dist/guide/responsive.html +81 -0
  103. package/docs/.vitepress/dist/guide/states.html +101 -0
  104. package/docs/.vitepress/dist/guide/tri-attribute.html +69 -0
  105. package/docs/.vitepress/dist/hashmap.json +1 -0
  106. package/docs/.vitepress/dist/index.html +31 -0
  107. package/docs/.vitepress/dist/reference/breakpoints.html +72 -0
  108. package/docs/.vitepress/dist/reference/colors.html +41 -0
  109. package/docs/.vitepress/dist/reference/layout.html +37 -0
  110. package/docs/.vitepress/dist/reference/space.html +48 -0
  111. package/docs/.vitepress/dist/reference/spacing.html +56 -0
  112. package/docs/.vitepress/dist/reference/visual.html +46 -0
  113. package/docs/.vitepress/dist/vp-icons.css +1 -0
  114. package/docs/.vitepress/theme/custom.css +65 -0
  115. package/docs/.vitepress/theme/index.js +4 -0
  116. package/docs/examples/cards.md +116 -0
  117. package/docs/examples/forms.md +207 -0
  118. package/docs/examples/hero.md +150 -0
  119. package/docs/examples/index.md +87 -0
  120. package/docs/examples/navigation.md +144 -0
  121. package/docs/guide/cdn.md +110 -0
  122. package/docs/guide/cli.md +174 -0
  123. package/docs/guide/configuration.md +152 -0
  124. package/docs/guide/getting-started.md +130 -0
  125. package/docs/guide/index.md +64 -0
  126. package/docs/guide/natural-scale.md +123 -0
  127. package/docs/guide/philosophy.md +103 -0
  128. package/docs/guide/responsive.md +129 -0
  129. package/docs/guide/states.md +162 -0
  130. package/docs/guide/tri-attribute.md +187 -0
  131. package/docs/index.md +64 -0
  132. package/docs/reference/breakpoints.md +131 -0
  133. package/docs/reference/colors.md +126 -0
  134. package/docs/reference/layout.md +115 -0
  135. package/docs/reference/space.md +121 -0
  136. package/docs/reference/spacing.md +74 -0
  137. package/docs/reference/visual.md +160 -0
  138. package/package.json +7 -13
  139. package/scripts/build-dist.js +49 -0
  140. package/src/cdn/jit.js +2 -2
  141. package/src/config/defaults.js +291 -2
@@ -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://unpkg.com/@bookklik/senangstart-css/dist/senangstart-css.min.js"></script>
7
+ *
8
+ * Or with custom config:
9
+ * <script type="senangstart/config">{ "theme": { "colors": { "brand": "#8B5CF6" } } }</script>
10
+ * <script src="https://unpkg.com/@bookklik/senangstart-css/dist/senangstart-css.min.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
+ })();