@netoyed/ux4g-design-system-v3-postcss 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.
@@ -0,0 +1,414 @@
1
+ import fg from 'fast-glob';
2
+ import fs from 'fs';
3
+
4
+ const registry = {
5
+ // --- Spacing ---
6
+ 'p': { type: 'space', property: 'padding' },
7
+ 'pt': { type: 'space', property: 'padding-top' },
8
+ 'pr': { type: 'space', property: 'padding-right' },
9
+ 'pb': { type: 'space', property: 'padding-bottom' },
10
+ 'pl': { type: 'space', property: 'padding-left' },
11
+ 'px': { type: 'space', property: ['padding-left', 'padding-right'] },
12
+ 'py': { type: 'space', property: ['padding-top', 'padding-bottom'] },
13
+
14
+ 'm': { type: 'space', property: 'margin' },
15
+ 'mt': { type: 'space', property: 'margin-top' },
16
+ 'mr': { type: 'space', property: 'margin-right' },
17
+ 'mb': { type: 'space', property: 'margin-bottom' },
18
+ 'ml': { type: 'space', property: 'margin-left' },
19
+ 'mx': { type: 'space', property: ['margin-left', 'margin-right'] },
20
+ 'my': { type: 'space', property: ['margin-top', 'margin-bottom'] },
21
+
22
+ // --- Colors ---
23
+ 'text': { type: 'color', property: 'color' },
24
+ 'bg': { type: 'color', property: 'background-color' },
25
+ 'border': { type: 'color', property: 'border-color' },
26
+
27
+ // --- Typography ---
28
+ 'font': { type: 'fontDetail', property: 'font-weight' },
29
+ 'text-size': { type: 'text', property: 'font-size' },
30
+ 'leading': { type: 'value', property: 'line-height' },
31
+ 'tracking': { type: 'value', property: 'letter-spacing' },
32
+ 'align': { type: 'static', property: 'text-align' }, // text-center
33
+
34
+ // --- Layout ---
35
+ 'flex': { type: 'static', property: 'display', value: 'flex' },
36
+ 'inline-flex': { type: 'static', property: 'display', value: 'inline-flex' },
37
+ 'grid': { type: 'static', property: 'display', value: 'grid' },
38
+ 'hidden': { type: 'static', property: 'display', value: 'none' },
39
+ 'block': { type: 'static', property: 'display', value: 'block' },
40
+ 'inline-block': { type: 'static', property: 'display', value: 'inline-block' },
41
+
42
+ 'items': { type: 'static', property: 'align-items' }, // start, end, center, baseline, stretch
43
+ 'justify': { type: 'static', property: 'justify-content' }, // start, end, center, between, around, evenly
44
+ 'self': { type: 'static', property: 'align-self' },
45
+
46
+ 'flex-col': { type: 'static', property: 'flex-direction', value: 'column' },
47
+ 'flex-row': { type: 'static', property: 'flex-direction', value: 'row' },
48
+ 'flex-wrap': { type: 'static', property: 'flex-wrap', value: 'wrap' },
49
+ 'flex-nowrap': { type: 'static', property: 'flex-wrap', value: 'nowrap' },
50
+
51
+ 'gap': { type: 'space', property: 'gap' },
52
+ 'gap-x': { type: 'space', property: 'column-gap' },
53
+ 'gap-y': { type: 'space', property: 'row-gap' },
54
+
55
+ // --- Sizing ---
56
+ 'w': { type: 'size', property: 'width' },
57
+ 'h': { type: 'size', property: 'height' },
58
+ 'min-w': { type: 'size', property: 'min-width' },
59
+ 'min-h': { type: 'size', property: 'min-height' },
60
+ 'max-w': { type: 'size', property: 'max-width' },
61
+ 'max-h': { type: 'size', property: 'max-height' },
62
+
63
+ // --- Borders & Effects ---
64
+ 'rounded': { type: 'radius', property: 'border-radius' },
65
+ 'shadow': { type: 'shadow', property: 'box-shadow' },
66
+ 'opacity': { type: 'value', property: 'opacity' },
67
+ 'z': { type: 'zIndex', property: 'z-index' },
68
+
69
+ // --- Position ---
70
+ 'absolute': { type: 'static', property: 'position', value: 'absolute' },
71
+ 'relative': { type: 'static', property: 'position', value: 'relative' },
72
+ 'fixed': { type: 'static', property: 'position', value: 'fixed' },
73
+ 'top': { type: 'space', property: 'top' },
74
+ 'right': { type: 'space', property: 'right' },
75
+ 'bottom': { type: 'space', property: 'bottom' },
76
+ 'left': { type: 'space', property: 'left' },
77
+ };
78
+
79
+ function generateUtility(className, config) {
80
+ let bp = null;
81
+ let util = className;
82
+
83
+ if (className.includes(':')) {
84
+ [bp, util] = className.split(':');
85
+ }
86
+
87
+ let css = '';
88
+
89
+ if (!util.startsWith(config.prefix)) return null;
90
+ const coreUtil = util.replace(config.prefix, '');
91
+
92
+ for (const [key, def] of Object.entries(registry)) {
93
+ const prefix = `${key}-`;
94
+ if (coreUtil.startsWith(prefix)) {
95
+ const value = coreUtil.slice(prefix.length);
96
+
97
+ let varName = '';
98
+
99
+ if (def.type === 'space') varName = `var(--${config.prefix}space-${value})`;
100
+ else if (def.type === 'color') varName = `var(--${config.prefix}color-${value})`;
101
+ else if (def.type === 'radius') varName = `var(--${config.prefix}radius-${value || 'DEFAULT'})`;
102
+ else if (def.type === 'shadow') varName = `var(--${config.prefix}shadow-${value || 'DEFAULT'})`;
103
+ else if (def.type === 'zIndex') varName = `var(--${config.prefix}zIndex-${value})`;
104
+ else if (def.type === 'fontDetail') varName = `var(--${config.prefix}fontWeight-${value})`;
105
+
106
+ else if (def.type === 'static') {
107
+ if (def.value) {
108
+ if (value !== '' && !def.allowValue) continue;
109
+ varName = def.value;
110
+ } else {
111
+ varName = value;
112
+ }
113
+ }
114
+
115
+ else if (def.type === 'size') {
116
+ if (config.theme.spacing[value]) {
117
+ varName = `var(--${config.prefix}space-${value})`;
118
+ } else if (value.includes('/')) {
119
+ const [num, den] = value.split('/');
120
+ varName = `${(parseInt(num) / parseInt(den)) * 100}%`;
121
+ } else {
122
+ continue;
123
+ }
124
+ }
125
+
126
+ else continue;
127
+
128
+ // Generate CSS properties
129
+ const props = Array.isArray(def.property) ? def.property : [def.property];
130
+ const decls = (def.type === 'static' && def.value) ? varName : props.map(p => `${p}:${varName}`).join(';');
131
+
132
+ css = `.${escape(className)}{${decls};}`;
133
+ break;
134
+ }
135
+ }
136
+
137
+ if (!css) return null;
138
+
139
+ if (bp) {
140
+ const size = config.breakpoints[bp];
141
+ return `@media (min-width:${size}){${css}}`;
142
+ }
143
+
144
+ return css;
145
+ }
146
+
147
+ function escape(cls) {
148
+ return cls.replace(/:/g, '\\:');
149
+ }
150
+
151
+ /**
152
+ * UX4G Design System – Default Config
153
+ * DO NOT EDIT (user overrides via ux4g.config.js)
154
+ */
155
+
156
+ const defaultConfig = {
157
+ /**
158
+ * --------------------------------------------------
159
+ * CORE
160
+ * --------------------------------------------------
161
+ */
162
+ prefix: 'ux4g-',
163
+
164
+ /**
165
+ * dev | build | cdn
166
+ * NOTE: CLI command will override this
167
+ */
168
+ mode: 'build',
169
+
170
+ /**
171
+ * --------------------------------------------------
172
+ * CONTENT (used for purge / JIT)
173
+ * --------------------------------------------------
174
+ */
175
+ content: [
176
+ './index.html',
177
+ './src/**/*.{js,ts,jsx,tsx,vue,html}',
178
+ './pages/**/*.{js,ts,jsx,tsx}',
179
+ './components/**/*.{js,ts,jsx,tsx}',
180
+ './**/*.php'
181
+ ],
182
+
183
+ /**
184
+ * --------------------------------------------------
185
+ * THEME (tokens)
186
+ * --------------------------------------------------
187
+ */
188
+ theme: {
189
+ colors: {
190
+ primary: {
191
+ 50: '#EFF6FF',
192
+ 500: '#3B82F6',
193
+ 700: '#1D4ED8'
194
+ },
195
+ secondary: {
196
+ 500: '#9333EA'
197
+ },
198
+ danger: {
199
+ 500: '#EF4444'
200
+ }
201
+ },
202
+
203
+ spacing: {
204
+ 0: '0px',
205
+ 1: '4px',
206
+ 2: '8px',
207
+ 4: '16px',
208
+ 6: '24px',
209
+ 8: '32px'
210
+ },
211
+
212
+ fontSize: {
213
+ xs: '12px',
214
+ sm: '14px',
215
+ md: '16px',
216
+ lg: '18px',
217
+ xl: '20px'
218
+ },
219
+
220
+ fontWeight: {
221
+ regular: 400,
222
+ medium: 500,
223
+ bold: 700
224
+ },
225
+
226
+ radius: {
227
+ sm: '4px',
228
+ md: '8px',
229
+ lg: '12px',
230
+ xl: '16px'
231
+ },
232
+
233
+ shadow: {
234
+ sm: '0 1px 2px rgba(0,0,0,0.05)',
235
+ md: '0 4px 6px rgba(0,0,0,0.1)'
236
+ },
237
+
238
+ zIndex: {
239
+ dropdown: 1000,
240
+ modal: 1100,
241
+ toast: 1200
242
+ }
243
+ },
244
+
245
+ /**
246
+ * --------------------------------------------------
247
+ * RESPONSIVE
248
+ * --------------------------------------------------
249
+ */
250
+ breakpoints: {
251
+ sm: '640px',
252
+ md: '768px',
253
+ lg: '1024px',
254
+ xl: '1280px'
255
+ },
256
+
257
+ /**
258
+ * --------------------------------------------------
259
+ * DARK MODE / THEMES
260
+ * --------------------------------------------------
261
+ */
262
+ darkMode: {
263
+ enabled: true,
264
+ strategy: 'data-attribute', // class | data-attribute
265
+ attribute: 'data-theme',
266
+ themes: {
267
+ light: 'light',
268
+ dark: 'dark'
269
+ }
270
+ },
271
+
272
+ /**
273
+ * --------------------------------------------------
274
+ * SAFELIST (dynamic classes)
275
+ * --------------------------------------------------
276
+ */
277
+ safelist: [],
278
+
279
+ /**
280
+ * --------------------------------------------------
281
+ * COMPONENTS
282
+ * --------------------------------------------------
283
+ */
284
+ components: {
285
+ button: true,
286
+ card: true,
287
+ input: true,
288
+ modal: false
289
+ },
290
+
291
+ /**
292
+ * --------------------------------------------------
293
+ * PLUGINS
294
+ * --------------------------------------------------
295
+ */
296
+ plugins: [],
297
+
298
+ /**
299
+ * --------------------------------------------------
300
+ * OUTPUT
301
+ * --------------------------------------------------
302
+ */
303
+ output: {
304
+ dir: 'dist',
305
+ file: 'ux4g.css',
306
+ minify: true,
307
+ sourceMap: false
308
+ }
309
+ };
310
+
311
+ const preflight = `
312
+ /* UX4G Preflight (Reset) */
313
+ *, ::before, ::after { box-sizing: border-box; border-width: 0; border-style: solid; border-color: currentColor; }
314
+ html { line-height: 1.5; -webkit-text-size-adjust: 100%; -moz-tab-size: 4; tab-size: 4; font-family: system-ui, sans-serif; }
315
+ body { margin: 0; line-height: inherit; }
316
+ hr { height: 0; color: inherit; border-top-width: 1px; }
317
+ abbr:where([title]) { text-decoration: underline dotted; }
318
+ h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; }
319
+ a { color: inherit; text-decoration: inherit; }
320
+ b, strong { font-weight: bolder; }
321
+ code, kbd, samp, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 1em; }
322
+ small { font-size: 80%; }
323
+ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
324
+ sub { bottom: -0.25em; }
325
+ sup { top: -0.5em; }
326
+ table { text-indent: 0; border-color: inherit; border-collapse: collapse; }
327
+ button, input, optgroup, select, textarea { font-family: inherit; font-size: 100%; line-height: inherit; color: inherit; margin: 0; padding: 0; }
328
+ button, select { text-transform: none; }
329
+ button, [type='button'], [type='reset'], [type='submit'] { -webkit-appearance: button; background-color: transparent; background-image: none; }
330
+ :-moz-focusring { outline: auto; }
331
+ :-moz-ui-invalid { box-shadow: none; }
332
+ progress { vertical-align: baseline; }
333
+ ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { height: auto; }
334
+ [type='search'] { -webkit-appearance: textfield; outline-offset: -2px; }
335
+ ::-webkit-search-decoration { -webkit-appearance: none; }
336
+ ::-webkit-file-upload-button { -webkit-appearance: button; font: inherit; }
337
+ summary { display: list-item; }
338
+ blockquote, dl, dd, h1, h2, h3, h4, h5, h6, hr, figure, p, pre { margin: 0; }
339
+ fieldset { margin: 0; padding: 0; }
340
+ legend { padding: 0; }
341
+ ol, ul, menu { list-style: none; margin: 0; padding: 0; }
342
+ textarea { resize: vertical; }
343
+ input::placeholder, textarea::placeholder { opacity: 1; color: #9ca3af; }
344
+ button, [role="button"] { cursor: pointer; }
345
+ :disabled { cursor: default; }
346
+ img, svg, video, canvas, audio, iframe, embed, object { display: block; vertical-align: middle; }
347
+ img, video { max-width: 100%; height: auto; }
348
+ [hidden] { display: none; }
349
+ `;
350
+
351
+ // Helper to deep merge config (simplified version of CLI one)
352
+ function deepMerge(target, source) {
353
+ if (typeof source !== 'object' || source === null) return source;
354
+ const result = { ...target };
355
+ for (const key of Object.keys(source)) {
356
+ if (Array.isArray(source[key])) {
357
+ result[key] = source[key];
358
+ } else if (typeof source[key] === 'object' && typeof target[key] === 'object') {
359
+ result[key] = deepMerge(target[key], source[key]);
360
+ } else {
361
+ result[key] = source[key];
362
+ }
363
+ }
364
+ return result;
365
+ }
366
+
367
+ var index = (opts = {}) => {
368
+ return {
369
+ postcssPlugin: 'ux4g',
370
+ async Once(root, { result }) {
371
+ // 1. Load Config
372
+ // In a real plugin, we use 'jiti' to load user config synchronously or async.
373
+ // Here we merge defaults with options passed in postcss.config.js
374
+ let config = deepMerge(defaultConfig, opts);
375
+
376
+ // Try to look for ux4g.config.js if no options passed?
377
+ // For now, let's rely on the passed options or defaults.
378
+ config.prefix = 'ux4g-'; // Enforce
379
+
380
+ // 2. Scan Files
381
+ const files = await fg(config.content);
382
+ const foundClasses = new Set();
383
+
384
+ const prefix = config.prefix.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
385
+ const CLASS_REGEX = new RegExp(`(sm:|md:|lg:|xl:)?${prefix}[a-z0-9\\-]+`, 'g');
386
+
387
+ for (const file of files) {
388
+ const content = fs.readFileSync(file, 'utf8');
389
+ const matches = content.match(CLASS_REGEX);
390
+ if (matches) matches.forEach(c => foundClasses.add(c));
391
+ }
392
+
393
+ // 3. Generate CSS
394
+ let utilitiesCSS = '';
395
+ for (const cls of foundClasses) {
396
+ const css = generateUtility(cls, config);
397
+ if (css) utilitiesCSS += css + '\n';
398
+ }
399
+
400
+ // 4. Replace Directives
401
+ root.walkAtRules('ux4g', (rule) => {
402
+ if (rule.params === 'base') {
403
+ rule.replaceWith(preflight);
404
+ } else if (rule.params === 'utilities') {
405
+ rule.replaceWith(utilitiesCSS);
406
+ }
407
+ });
408
+ }
409
+ };
410
+ };
411
+
412
+ const postcss = true;
413
+
414
+ export { index as default, postcss };