@umoa/saascfm-css 0.0.0-stage → 0.1.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/dist/index.js ADDED
@@ -0,0 +1,534 @@
1
+ // src/index.ts
2
+ import path from "path";
3
+ import fs from "fs";
4
+
5
+ // src/layout/css-spacing.ts
6
+ var SPACING_RULES = {
7
+ // sizing
8
+ w: { props: ["width"] },
9
+ h: { props: ["height"] },
10
+ mw: { props: ["max-width"] },
11
+ mh: { props: ["max-height"] },
12
+ minw: { props: ["min-width"] },
13
+ minh: { props: ["min-height"] },
14
+ // margin
15
+ mt: { props: ["margin-top"] },
16
+ mr: { props: ["margin-right"] },
17
+ mb: { props: ["margin-bottom"] },
18
+ ml: { props: ["margin-left"] },
19
+ mtb: { props: ["margin-top", "margin-bottom"] },
20
+ mrl: { props: ["margin-right", "margin-left"] },
21
+ // padding
22
+ p: { props: ["padding"] },
23
+ pt: { props: ["padding-top"] },
24
+ pr: { props: ["padding-right"] },
25
+ pb: { props: ["padding-bottom"] },
26
+ pl: { props: ["padding-left"] },
27
+ ptb: { props: ["padding-top", "padding-bottom"] },
28
+ prl: { props: ["padding-right", "padding-left"] },
29
+ // gap
30
+ g: { props: ["gap"], nonNegative: true },
31
+ gc: { props: ["column-gap"], nonNegative: true },
32
+ gr: { props: ["row-gap"], nonNegative: true },
33
+ // misc
34
+ bdrd: { props: ["border-radius"] },
35
+ bdw: { props: ["border-width"], companion: { "border-style": "solid" } },
36
+ zdex: { props: ["z-index"], unitless: true }
37
+ };
38
+ var SPACING_PERCENT_ENABLED = /* @__PURE__ */ new Set([
39
+ "w",
40
+ "h",
41
+ "mw",
42
+ "mh",
43
+ "minw",
44
+ "minh",
45
+ "mt",
46
+ "mr",
47
+ "mb",
48
+ "ml",
49
+ "mtb",
50
+ "mrl",
51
+ "p",
52
+ "pt",
53
+ "pr",
54
+ "pb",
55
+ "pl",
56
+ "ptb",
57
+ "prl"
58
+ ]);
59
+ var SPACING_VIEWPORT_ENABLED = /* @__PURE__ */ new Set(["w", "h"]);
60
+ var SPACING_ORDER = [
61
+ "w",
62
+ "h",
63
+ "mw",
64
+ "mh",
65
+ "minw",
66
+ "minh",
67
+ "p",
68
+ "ptb",
69
+ "prl",
70
+ "pt",
71
+ "pr",
72
+ "pb",
73
+ "pl",
74
+ "mtb",
75
+ "mrl",
76
+ "mt",
77
+ "mr",
78
+ "mb",
79
+ "ml",
80
+ "g",
81
+ "gc",
82
+ "gr",
83
+ "bdrd",
84
+ "bdw",
85
+ "zdex"
86
+ ];
87
+ var SPACING_ALTERNATION = Object.keys(SPACING_RULES).sort((a, b) => b.length - a.length).join("|");
88
+
89
+ // src/layout/css-spacing-static.ts
90
+ var SPACING_STATIC_RULES = {
91
+ bn: { border: "none" },
92
+ auto: { margin: "0 auto" },
93
+ hl: { "border-bottom": "1px solid var(--border-default, currentColor)", width: "100%" },
94
+ "hl-muted": { "border-bottom": "1px solid var(--border-muted, var(--border-default, currentColor))", width: "100%" },
95
+ vl: { "border-left": "2px solid var(--border-default, currentColor)", height: "20px" },
96
+ "mcon-480": { "max-width": "480px", margin: "0 auto" },
97
+ "mcon-640": { "max-width": "640px", margin: "0 auto" },
98
+ "mcon-768": { "max-width": "768px", margin: "0 auto" },
99
+ "mcon-1080": { "max-width": "1080px", margin: "0 auto" },
100
+ "mcon-1280": { "max-width": "1280px", margin: "0 auto" },
101
+ "mcon-1440": { "max-width": "1440px", margin: "0 auto" }
102
+ };
103
+ var SPACING_STATIC_ALTERNATION = Object.keys(SPACING_STATIC_RULES).sort((a, b) => b.length - a.length).join("|");
104
+
105
+ // src/layout/css-layout.ts
106
+ var LAYOUT_RULES = {
107
+ // flex container
108
+ flex: { display: "flex" },
109
+ "flex-fdr": { "flex-direction": "row" },
110
+ "flex-fdrr": { "flex-direction": "row-reverse" },
111
+ "flex-fdc": { "flex-direction": "column" },
112
+ "flex-fdcr": { "flex-direction": "column-reverse" },
113
+ "flex-wrap": { "flex-wrap": "wrap" },
114
+ "flex-nowrap": { "flex-wrap": "nowrap" },
115
+ // flex justify-content
116
+ "flex-jcfs": { "justify-content": "flex-start" },
117
+ "flex-jcfe": { "justify-content": "flex-end" },
118
+ "flex-jcc": { "justify-content": "center" },
119
+ "flex-jcsb": { "justify-content": "space-between" },
120
+ "flex-jcsa": { "justify-content": "space-around" },
121
+ "flex-jcse": { "justify-content": "space-evenly" },
122
+ // flex align-items
123
+ "flex-aifs": { "align-items": "flex-start" },
124
+ "flex-aife": { "align-items": "flex-end" },
125
+ "flex-aic": { "align-items": "center" },
126
+ "flex-aist": { "align-items": "stretch" },
127
+ "flex-aib": { "align-items": "baseline" },
128
+ // flex align-content
129
+ "flex-acfs": { "align-content": "flex-start" },
130
+ "flex-acfe": { "align-content": "flex-end" },
131
+ "flex-acc": { "align-content": "center" },
132
+ "flex-acst": { "align-content": "stretch" },
133
+ "flex-acsb": { "align-content": "space-between" },
134
+ "flex-acsa": { "align-content": "space-around" },
135
+ // flex align-self
136
+ "flex-assr": { "align-self": "stretch" },
137
+ "flex-asc": { "align-self": "center" },
138
+ "flex-ass": { "align-self": "start" },
139
+ "flex-ase": { "align-self": "end" },
140
+ // grid justify-items
141
+ "grid-jist": { "justify-items": "start" },
142
+ "grid-jie": { "justify-items": "end" },
143
+ "grid-jic": { "justify-items": "center" },
144
+ "grid-jistr": { "justify-items": "stretch" },
145
+ // grid align-items
146
+ "grid-aist": { "align-items": "start" },
147
+ "grid-aie": { "align-items": "end" },
148
+ "grid-aic": { "align-items": "center" },
149
+ "grid-aistr": { "align-items": "stretch" },
150
+ // text-align (found in the legacy file, was missing from the module)
151
+ "align-l": { "text-align": "left" },
152
+ "align-c": { "text-align": "center" },
153
+ "align-r": { "text-align": "right" },
154
+ // float
155
+ "float-l": { float: "left" },
156
+ "float-r": { float: "right" },
157
+ // float-c in the legacy file was actually `position: fixed; top: 50%; left: 50%`,
158
+ // not a real float — kept as its original (odd) behavior rather than
159
+ // silently "fixing" it into something it never was.
160
+ "float-c": { position: "fixed", top: "50%", left: "50%" }
161
+ };
162
+ var LAYOUT_ALTERNATION = Object.keys(LAYOUT_RULES).sort((a, b) => b.length - a.length).join("|");
163
+
164
+ // src/styling/css-typography.ts
165
+ var TYPOGRAPHY_RULES = {
166
+ // font-weight
167
+ nb: { "font-weight": "normal" },
168
+ b: { "font-weight": "bold" },
169
+ bx: { "font-weight": "bolder" },
170
+ "b-100": { "font-weight": "100" },
171
+ "b-200": { "font-weight": "200" },
172
+ "b-300": { "font-weight": "300" },
173
+ "b-400": { "font-weight": "400" },
174
+ "b-500": { "font-weight": "500" },
175
+ "b-600": { "font-weight": "600" },
176
+ "b-700": { "font-weight": "700" },
177
+ "b-800": { "font-weight": "800" },
178
+ "b-900": { "font-weight": "900" },
179
+ "b-lighter": { "font-weight": "100" },
180
+ "b-light": { "font-weight": "300" },
181
+ lighter: { "font-weight": "100" },
182
+ light: { "font-weight": "300" },
183
+ // text-transform
184
+ uppercase: { "text-transform": "uppercase" },
185
+ "to-uppercase": { "text-transform": "uppercase" },
186
+ lowercase: { "text-transform": "lowercase" },
187
+ "to-lowercase": { "text-transform": "lowercase" },
188
+ capitalize: { "text-transform": "capitalize" },
189
+ "text-none": { "text-transform": "none" },
190
+ // misc
191
+ i: { "font-style": "italic" },
192
+ underline: { "text-decoration": "underline" },
193
+ // word-wrap / hyphenation
194
+ ow: { "overflow-wrap": "break-word", "word-wrap": "break-word", hyphens: "auto" },
195
+ ww: { "overflow-wrap": "break-word", "word-wrap": "break-word", hyphens: "auto" }
196
+ };
197
+ var TYPOGRAPHY_ALTERNATION = Object.keys(TYPOGRAPHY_RULES).sort((a, b) => b.length - a.length).join("|");
198
+ var FONT_SIZE_PATTERN = "(?:fs|ls)-n?(?:\\d+)?(?:[dp]\\d+)?em";
199
+ function parseFontSize(cls) {
200
+ const match = cls.match(/^(fs|ls)-(n)?(\d+)?(?:[dp](\d+))?em$/);
201
+ if (!match) return null;
202
+ const [, kind, neg, intPart, decPart] = match;
203
+ if (!intPart && !decPart) return null;
204
+ if (neg && kind === "fs") return null;
205
+ const whole = intPart ?? "0";
206
+ const num = decPart ? `${whole}.${decPart}` : whole;
207
+ return {
208
+ prop: kind === "fs" ? "font-size" : "letter-spacing",
209
+ value: `${neg ? "-" : ""}${num}em`
210
+ };
211
+ }
212
+
213
+ // src/styling/css-cursor.ts
214
+ var CURSOR_RULES = {
215
+ "cursor-alias": { cursor: "alias" },
216
+ "cursor-all-scroll": { cursor: "all-scroll" },
217
+ "cursor-auto": { cursor: "auto" },
218
+ "cursor-cell": { cursor: "cell" },
219
+ "cursor-context-menu": { cursor: "context-menu" },
220
+ "cursor-col-resize": { cursor: "col-resize" },
221
+ "cursor-copy": { cursor: "copy" },
222
+ "cursor-crosshair": { cursor: "crosshair" },
223
+ "cursor-default": { cursor: "default" },
224
+ "cursor-e-resize": { cursor: "e-resize" },
225
+ "cursor-ew-resize": { cursor: "ew-resize" },
226
+ "cursor-grab": { cursor: "grab" },
227
+ "cursor-grabbing": { cursor: "grabbing" },
228
+ "cursor-help": { cursor: "help" },
229
+ "cursor-move": { cursor: "move" },
230
+ "cursor-n-resize": { cursor: "n-resize" },
231
+ "cursor-ne-resize": { cursor: "ne-resize" },
232
+ "cursor-nesw-resize": { cursor: "nesw-resize" },
233
+ "cursor-ns-resize": { cursor: "ns-resize" },
234
+ "cursor-nw-resize": { cursor: "nw-resize" },
235
+ "cursor-nwse-resize": { cursor: "nwse-resize" },
236
+ "cursor-no-drop": { cursor: "no-drop" },
237
+ "cursor-none": { cursor: "none" },
238
+ "cursor-not-allowed": { cursor: "not-allowed" },
239
+ "cursor-pointer": { cursor: "pointer" },
240
+ "cursor-progress": { cursor: "progress" },
241
+ "cursor-row-resize": { cursor: "row-resize" },
242
+ "cursor-s-resize": { cursor: "s-resize" },
243
+ "cursor-se-resize": { cursor: "se-resize" },
244
+ "cursor-sw-resize": { cursor: "sw-resize" },
245
+ "cursor-text": { cursor: "text" },
246
+ "cursor-w-resize": { cursor: "w-resize" },
247
+ "cursor-wait": { cursor: "wait" },
248
+ "cursor-zoom-in": { cursor: "zoom-in" },
249
+ "cursor-zoom-out": { cursor: "zoom-out" }
250
+ };
251
+ var CURSOR_ALTERNATION = Object.keys(CURSOR_RULES).sort((a, b) => b.length - a.length).join("|");
252
+
253
+ // src/styling/css-border.ts
254
+ var BORDER_STYLE_RULES = {
255
+ "bds-solid": { "border-style": "solid" },
256
+ "bds-dashed": { "border-style": "dashed" },
257
+ "bds-dotted": { "border-style": "dotted" },
258
+ "bds-double": { "border-style": "double" },
259
+ "bds-none": { "border-style": "none" }
260
+ };
261
+ var BORDER_STYLE_ALTERNATION = Object.keys(BORDER_STYLE_RULES).sort((a, b) => b.length - a.length).join("|");
262
+
263
+ // src/styling/css-color.ts
264
+ var PROP_BY_PREFIX = {
265
+ text: "color",
266
+ bg: "background-color",
267
+ border: "border-color"
268
+ };
269
+ var LOOKS_LIKE_KEY = /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/i;
270
+ function resolveTokens(tokens, palette) {
271
+ const resolved = {};
272
+ for (const [name, value] of Object.entries(tokens)) {
273
+ if (typeof value !== "string" || !value) {
274
+ console.warn(`[saascfm-css] token "${name}" has no value, skipped`);
275
+ continue;
276
+ }
277
+ const fromPalette = palette[value];
278
+ if (!fromPalette && LOOKS_LIKE_KEY.test(value)) {
279
+ console.warn(`[saascfm-css] token "${name}" references unknown primitive "${value}", skipped`);
280
+ continue;
281
+ }
282
+ resolved[name] = fromPalette ?? value;
283
+ }
284
+ return resolved;
285
+ }
286
+ function generateRootVars(resolved) {
287
+ const lines = Object.entries(resolved).sort(([a], [b]) => a.localeCompare(b)).map(([name, value]) => ` --${name}: ${value};`);
288
+ return `:root {
289
+ ${lines.join("\n")}
290
+ }
291
+ `;
292
+ }
293
+ function buildColorUtilityRules(resolved) {
294
+ const rules = {};
295
+ for (const name of Object.keys(resolved)) {
296
+ const prop = PROP_BY_PREFIX[name.split("-")[0]];
297
+ if (!prop) continue;
298
+ rules[name] = { [prop]: `var(--${name})` };
299
+ }
300
+ return rules;
301
+ }
302
+ function buildPrimitiveRules(primitives) {
303
+ const rules = {};
304
+ for (const [name, value] of Object.entries(primitives)) {
305
+ rules[name] = { color: value };
306
+ if (/^(rgba|hsla)/i.test(value)) continue;
307
+ rules[`bg-${name}`] = { "background-color": value };
308
+ rules[`border-${name}`] = { "border-color": value };
309
+ }
310
+ return rules;
311
+ }
312
+ function colorAlternation(rules) {
313
+ return Object.keys(rules).sort((a, b) => b.length - a.length).join("|");
314
+ }
315
+
316
+ // src/index.ts
317
+ var PKG = "saascfm-css";
318
+ var VIRTUAL_ID = "virtual:css-module.css";
319
+ var RESOLVED_VIRTUAL_ID = "\0" + VIRTUAL_ID;
320
+ function cssModule(options = {}) {
321
+ const srcDir = options.srcDir || "src";
322
+ const extensions = options.extensions || [".vue", ".js", ".jsx", ".ts", ".tsx", ".html"];
323
+ const exclude = options.exclude || [".colors.", ".tokens.", "primitives."];
324
+ const useSpacing = options.spacing !== false;
325
+ const useLayout = options.layout !== false;
326
+ const useTypography = options.typography !== false;
327
+ const useCursor = options.cursor !== false;
328
+ const useBorder = options.border !== false;
329
+ let COLOR_ROOT_VARS = "";
330
+ let COLOR_RULES = {};
331
+ let PRIMITIVE_COLOR_RULES = {};
332
+ let COLOR_ALTERNATION = "";
333
+ const colorsModule = options.colorsModule ?? {};
334
+ const tokens = colorsModule["TOKENS"];
335
+ const primitives = colorsModule["PRIMITIVES"];
336
+ const useColor = !!(tokens || primitives);
337
+ if (useColor) {
338
+ if (tokens) {
339
+ const resolved = resolveTokens(tokens, primitives ?? {});
340
+ COLOR_ROOT_VARS = generateRootVars(resolved);
341
+ COLOR_RULES = buildColorUtilityRules(resolved);
342
+ }
343
+ if (primitives && options.primitiveClasses !== false) {
344
+ PRIMITIVE_COLOR_RULES = buildPrimitiveRules(primitives);
345
+ }
346
+ COLOR_ALTERNATION = colorAlternation({ ...COLOR_RULES, ...PRIMITIVE_COLOR_RULES });
347
+ }
348
+ const alternatives = [];
349
+ if (useSpacing) {
350
+ alternatives.push(`(?:${SPACING_ALTERNATION})-n?\\d+(?:d\\d+)?(?:p|vw|vh)?`);
351
+ alternatives.push(`(?:${SPACING_STATIC_ALTERNATION})`);
352
+ }
353
+ if (useLayout) alternatives.push(`(?:${LAYOUT_ALTERNATION})`);
354
+ if (useTypography) {
355
+ alternatives.push(`(?:${TYPOGRAPHY_ALTERNATION})`);
356
+ alternatives.push(FONT_SIZE_PATTERN);
357
+ }
358
+ if (useCursor) alternatives.push(`(?:${CURSOR_ALTERNATION})`);
359
+ if (useBorder) alternatives.push(`(?:${BORDER_STYLE_ALTERNATION})`);
360
+ if (useColor && COLOR_ALTERNATION) alternatives.push(`(?:${COLOR_ALTERNATION})`);
361
+ const CLASS_RE = new RegExp(
362
+ `(?:^|["'\`\\s(])(${alternatives.join("|")})(!)?(?=["'\`\\s)]|$)`,
363
+ "g"
364
+ );
365
+ function parseClass(cls) {
366
+ if (useSpacing && SPACING_STATIC_RULES[cls]) {
367
+ return { kind: "static", decls: SPACING_STATIC_RULES[cls] };
368
+ }
369
+ if (useLayout && LAYOUT_RULES[cls]) {
370
+ return { kind: "static", decls: LAYOUT_RULES[cls] };
371
+ }
372
+ if (useTypography && TYPOGRAPHY_RULES[cls]) {
373
+ return { kind: "static", decls: TYPOGRAPHY_RULES[cls] };
374
+ }
375
+ if (useCursor && CURSOR_RULES[cls]) {
376
+ return { kind: "static", decls: CURSOR_RULES[cls] };
377
+ }
378
+ if (useBorder && BORDER_STYLE_RULES[cls]) {
379
+ return { kind: "static", decls: BORDER_STYLE_RULES[cls] };
380
+ }
381
+ if (useColor && COLOR_RULES[cls]) {
382
+ return { kind: "static", decls: COLOR_RULES[cls] };
383
+ }
384
+ if (useColor && PRIMITIVE_COLOR_RULES[cls]) {
385
+ return { kind: "static", decls: PRIMITIVE_COLOR_RULES[cls] };
386
+ }
387
+ if (useTypography) {
388
+ const fontSize = parseFontSize(cls);
389
+ if (fontSize) return { kind: "fontsize", prop: fontSize.prop, value: fontSize.value };
390
+ }
391
+ if (useSpacing) {
392
+ const match = cls.match(/^([a-z]+)-(n)?(\d+(?:d\d+)?)(p|vw|vh)?$/);
393
+ if (match) {
394
+ const [, prefix, neg, num, suffix] = match;
395
+ const rule = SPACING_RULES[prefix];
396
+ if (rule) {
397
+ if (suffix === "p" && !SPACING_PERCENT_ENABLED.has(prefix)) return null;
398
+ if ((suffix === "vw" || suffix === "vh") && !SPACING_VIEWPORT_ENABLED.has(prefix)) return null;
399
+ if (rule.unitless && (suffix || num.includes("d"))) return null;
400
+ if (neg && rule.nonNegative) return null;
401
+ const sign = neg ? "-" : "";
402
+ let unit;
403
+ if (rule.unitless) unit = "";
404
+ else if (suffix === "p") unit = "%";
405
+ else if (suffix === "vw") unit = "vw";
406
+ else if (suffix === "vh") unit = "vh";
407
+ else unit = "px";
408
+ return { kind: "numeric", props: rule.props, value: `${sign}${num.replace("d", ".")}${unit}`, companion: rule.companion };
409
+ }
410
+ }
411
+ }
412
+ return null;
413
+ }
414
+ function rank(base) {
415
+ if (useBorder && BORDER_STYLE_RULES[base]) return 3;
416
+ if (useSpacing && SPACING_STATIC_RULES[base]) return 0;
417
+ const m = base.match(/^([a-z]+)-n?\d/);
418
+ if (useSpacing && m && SPACING_RULES[m[1]]) return 1;
419
+ return 2;
420
+ }
421
+ function generateCSS(classes) {
422
+ const entries = [...classes].map((key) => {
423
+ const bang = key.endsWith("!");
424
+ const base = bang ? key.slice(0, -1) : key;
425
+ const m = base.match(/^([a-z]+)-n?\d/);
426
+ const sub = rank(base) === 1 && m ? SPACING_ORDER.indexOf(m[1]) : 0;
427
+ return { key, base, bang, tier: rank(base), sub };
428
+ });
429
+ entries.sort(
430
+ (x, y) => x.tier - y.tier || x.sub - y.sub || x.base.localeCompare(y.base) || Number(x.bang) - Number(y.bang)
431
+ );
432
+ let css = `/* AUTO-GENERATED by ${PKG} \u2014 do not edit by hand. */
433
+ `;
434
+ if (COLOR_ROOT_VARS) css += COLOR_ROOT_VARS;
435
+ for (const { base, bang } of entries) {
436
+ const parsed = parseClass(base);
437
+ if (!parsed) continue;
438
+ const flag = options.important || bang ? " !important" : "";
439
+ let decls;
440
+ if (parsed.kind === "numeric") {
441
+ const all = parsed.props.map((p) => ` ${p}: ${parsed.value}${flag};`);
442
+ const companion = parsed.companion ? Object.entries(parsed.companion).map(([p, v]) => ` ${p}: ${v}${flag};`) : [];
443
+ decls = [...all, ...companion].join("\n");
444
+ } else if (parsed.kind === "static") {
445
+ decls = Object.entries(parsed.decls).map(([prop, value]) => ` ${prop}: ${value}${flag};`).join("\n");
446
+ } else {
447
+ decls = ` ${parsed.prop}: ${parsed.value}${flag};`;
448
+ }
449
+ css += `.${base}${bang ? "\\!" : ""} {
450
+ ${decls}
451
+ }
452
+ `;
453
+ }
454
+ return css;
455
+ }
456
+ function walkDir(dir, exts, out = []) {
457
+ let entries;
458
+ try {
459
+ entries = fs.readdirSync(dir, { withFileTypes: true });
460
+ } catch {
461
+ return out;
462
+ }
463
+ for (const entry of entries) {
464
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
465
+ const full = path.join(dir, entry.name);
466
+ if (entry.isDirectory()) {
467
+ walkDir(full, exts, out);
468
+ } else if (exts.some((e) => entry.name.endsWith(e)) && !exclude.some((x) => full.includes(x))) {
469
+ out.push(full);
470
+ }
471
+ }
472
+ return out;
473
+ }
474
+ let root = process.cwd();
475
+ const found = /* @__PURE__ */ new Set();
476
+ let viteServer = null;
477
+ function scanFile(file) {
478
+ let content;
479
+ try {
480
+ content = fs.readFileSync(file, "utf-8");
481
+ } catch {
482
+ return false;
483
+ }
484
+ let changed = false;
485
+ let m;
486
+ CLASS_RE.lastIndex = 0;
487
+ while (m = CLASS_RE.exec(content)) {
488
+ const key = m[1] + (m[2] ?? "");
489
+ if (!found.has(key) && parseClass(m[1])) {
490
+ found.add(key);
491
+ changed = true;
492
+ }
493
+ }
494
+ return changed;
495
+ }
496
+ function scanAll() {
497
+ for (const file of walkDir(path.resolve(root, srcDir), extensions)) scanFile(file);
498
+ scanFile(path.resolve(root, "index.html"));
499
+ }
500
+ function handleFsEvent(file) {
501
+ if (!extensions.some((e) => file.endsWith(e))) return;
502
+ if (exclude.some((x) => file.includes(x))) return;
503
+ const changed = scanFile(file);
504
+ if (changed && viteServer) {
505
+ const mod = viteServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ID);
506
+ if (mod) viteServer.moduleGraph.invalidateModule(mod);
507
+ viteServer.ws.send({ type: "full-reload" });
508
+ }
509
+ }
510
+ return {
511
+ name: PKG,
512
+ configResolved(config) {
513
+ root = config.root;
514
+ },
515
+ buildStart() {
516
+ scanAll();
517
+ },
518
+ resolveId(id) {
519
+ if (id === VIRTUAL_ID) return RESOLVED_VIRTUAL_ID;
520
+ },
521
+ load(id) {
522
+ if (id === RESOLVED_VIRTUAL_ID) return generateCSS(found);
523
+ },
524
+ configureServer(server) {
525
+ viteServer = server;
526
+ server.watcher.add(path.resolve(root, srcDir));
527
+ server.watcher.on("change", handleFsEvent);
528
+ server.watcher.on("add", handleFsEvent);
529
+ }
530
+ };
531
+ }
532
+ export {
533
+ cssModule as default
534
+ };
package/package.json CHANGED
@@ -1,6 +1,60 @@
1
1
  {
2
2
  "name": "@umoa/saascfm-css",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "SaaSCFM scan-and-generate utility CSS for Vite: w-54, mt-12, g-8, text-primary.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.cjs"
17
+ }
18
+ },
19
+ "./client": {
20
+ "types": "./client.d.ts"
21
+ },
22
+ "./templates/*": "./templates/*"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "client.d.ts",
27
+ "templates",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "keywords": [
36
+ "vite",
37
+ "vite-plugin",
38
+ "css",
39
+ "utility-css",
40
+ "design-tokens"
41
+ ],
42
+ "license": "UNLICENSED",
43
+ "engines": {
44
+ "node": ">=18"
45
+ },
46
+ "peerDependencies": {
47
+ "vite": ">=5"
48
+ },
49
+ "devDependencies": {
50
+ "tsup": "^8.0.0",
51
+ "typescript": "^5.4.0",
52
+ "vite": "^5.4.0",
53
+ "@types/node": "^20.0.0"
54
+ },
55
+ "module": "./dist/index.js",
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "author": "UMOA"
6
60
  }
@@ -0,0 +1,25 @@
1
+ export const PRIMITIVES = {
2
+ 'brand-500': '#3B6FF0',
3
+ 'neutral-50': '#FAFAF9',
4
+ 'neutral-200': '#E8E8E5',
5
+ 'neutral-600': '#5C5C57',
6
+ 'neutral-900': '#181816',
7
+ 'white': '#FFFFFF',
8
+ 'red-500': '#D64545',
9
+ 'green-500': '#2F7A4C',
10
+ }
11
+
12
+ export const TOKENS = {
13
+ 'text-primary': 'neutral-900',
14
+ 'text-secondary': 'neutral-600',
15
+ 'text-inverse': 'white',
16
+ 'text-brand': 'brand-500',
17
+ 'bg-page': 'neutral-50',
18
+ 'bg-surface': 'white',
19
+ 'bg-brand': 'brand-500',
20
+ 'border-default': 'neutral-200',
21
+ 'text-status-error': 'red-500',
22
+ 'bg-status-error': 'red-500',
23
+ 'text-status-success': 'green-500',
24
+ 'bg-status-success': 'green-500',
25
+ }
@@ -0,0 +1,14 @@
1
+ import { PRIMITIVES } from './primitives.colors'
2
+ import { SURFACE_TOKENS } from './surface.colors'
3
+ import { BORDER_TOKENS } from './border.colors'
4
+ import { STATUS_TOKENS } from './status.colors'
5
+ import { NAVIGATION_TOKENS } from './navigation.colors'
6
+
7
+ export { PRIMITIVES }
8
+
9
+ export const TOKENS = {
10
+ ...SURFACE_TOKENS,
11
+ ...BORDER_TOKENS,
12
+ ...STATUS_TOKENS,
13
+ ...NAVIGATION_TOKENS,
14
+ }
@@ -0,0 +1,7 @@
1
+ export const BORDER_TOKENS = {
2
+ 'border-default': 'neutral-200',
3
+ 'border-muted': 'neutral-100',
4
+ 'border-strong': 'neutral-300',
5
+ 'border-brand': 'brand-500',
6
+ 'border-focus': 'brand-400',
7
+ }
@@ -0,0 +1,9 @@
1
+ export const NAVIGATION_TOKENS = {
2
+ 'nav-bg': 'neutral-50',
3
+ 'nav-item-text': 'neutral-600',
4
+ 'nav-item-active-bg': 'brand-50',
5
+ 'nav-item-active-text': 'brand-600',
6
+ 'nav-group-label': 'neutral-500',
7
+ 'nav-children-border': 'neutral-200',
8
+ 'nav-children-active-border': 'brand-500',
9
+ }