swatchkit 0.4.1 → 0.6.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 +20 -3
- package/build.js +61 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ my-project/
|
|
|
36
36
|
│ ├── colors.html
|
|
37
37
|
│ ├── typography.html
|
|
38
38
|
│ └── ...
|
|
39
|
-
└──
|
|
39
|
+
└── dist/
|
|
40
40
|
└── swatchkit/ # Built pattern library
|
|
41
41
|
└── index.html
|
|
42
42
|
```
|
|
@@ -207,7 +207,7 @@ Copies "blueprints" into your project to get you started.
|
|
|
207
207
|
* **`swatchkit/`**: Sets up the documentation structure and layout.
|
|
208
208
|
|
|
209
209
|
### 2. `swatchkit` (Build Process)
|
|
210
|
-
Compiles your documentation site into `
|
|
210
|
+
Compiles your documentation site into `dist/swatchkit/`.
|
|
211
211
|
|
|
212
212
|
1. **Reads JSON Tokens**: Scans `tokens/*.json` and calculates fluid typography/spacing.
|
|
213
213
|
2. **Generates CSS**: Creates `css/tokens.css`. **Do not edit this file**; it is overwritten every build.
|
|
@@ -249,7 +249,7 @@ swatchkit [command] [options]
|
|
|
249
249
|
| `--watch` | `-w` | Watch files and rebuild on change. |
|
|
250
250
|
| `--config` | `-c` | Path to config file. |
|
|
251
251
|
| `--input` | `-i` | Pattern directory (Default: `swatchkit/`). |
|
|
252
|
-
| `--outDir` | `-o` | Output directory (Default: `
|
|
252
|
+
| `--outDir` | `-o` | Output directory (Default: `dist/swatchkit`). |
|
|
253
253
|
| `--force` | `-f` | Overwrite layout file during init. |
|
|
254
254
|
|
|
255
255
|
## Configuration
|
|
@@ -275,6 +275,23 @@ module.exports = {
|
|
|
275
275
|
};
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
+
## Using with a Framework
|
|
279
|
+
|
|
280
|
+
SwatchKit outputs to `dist/swatchkit/` by default. If your framework (Vite, Astro, etc.) cleans the `dist/` directory during its build, run SwatchKit **after** your framework build:
|
|
281
|
+
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"scripts": {
|
|
285
|
+
"build": "vite build && swatchkit",
|
|
286
|
+
"dev": "vite dev & swatchkit -w"
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
In watch mode, SwatchKit detects when its output directory is deleted by an external tool and automatically rebuilds.
|
|
292
|
+
|
|
293
|
+
SwatchKit only ever writes inside its own output subdirectory — it will never modify or delete other files in `dist/`.
|
|
294
|
+
|
|
278
295
|
## Acknowledgements
|
|
279
296
|
|
|
280
297
|
The CSS compositions included by default in SwatchKit are adapted from [Every Layout](https://every-layout.dev/) by Heydon Pickering and Andy Bell. Highly recommend their documentation for a deep dive into their brilliant CSS techniques.
|
package/build.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const fs = require("fs");
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const chokidar = require("chokidar");
|
|
5
|
-
const { processTokens } = require("./src/tokens");
|
|
5
|
+
const { processTokens, generateTokenUtilities } = require("./src/tokens");
|
|
6
6
|
const { generateTokenSwatches } = require("./src/generators");
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -110,12 +110,12 @@ function resolveSettings(cliOptions, fileConfig) {
|
|
|
110
110
|
const swatchkitDir = findSwatchkitDir();
|
|
111
111
|
|
|
112
112
|
// Output Dir
|
|
113
|
-
// Default:
|
|
113
|
+
// Default: dist/swatchkit
|
|
114
114
|
const outDir = cliOptions.outDir
|
|
115
115
|
? path.resolve(cwd, cliOptions.outDir)
|
|
116
116
|
: fileConfig.outDir
|
|
117
117
|
? path.resolve(cwd, fileConfig.outDir)
|
|
118
|
-
: path.join(cwd, "
|
|
118
|
+
: path.join(cwd, "dist/swatchkit");
|
|
119
119
|
|
|
120
120
|
// CSS directory - where tokens.css and user's main.css live
|
|
121
121
|
// Default: css/ at project root
|
|
@@ -298,7 +298,11 @@ function runInit(settings, options) {
|
|
|
298
298
|
// processTokens now expects the folder where tokens.css should live
|
|
299
299
|
// We pass settings.cssDir, but processTokens internally joins 'tokens.css'
|
|
300
300
|
// So we need to point it to css/global
|
|
301
|
-
processTokens(settings.tokensDir, path.join(settings.cssDir, "global"));
|
|
301
|
+
const tokensContext = processTokens(settings.tokensDir, path.join(settings.cssDir, "global"));
|
|
302
|
+
|
|
303
|
+
if (tokensContext) {
|
|
304
|
+
generateTokenUtilities(tokensContext, path.join(settings.cssDir, "utilities"));
|
|
305
|
+
}
|
|
302
306
|
|
|
303
307
|
const targetLayout = settings.projectLayout;
|
|
304
308
|
|
|
@@ -424,6 +428,24 @@ ${scriptContent}
|
|
|
424
428
|
return swatches;
|
|
425
429
|
}
|
|
426
430
|
|
|
431
|
+
function validateOutDir(outDir) {
|
|
432
|
+
const cwd = process.cwd();
|
|
433
|
+
const relative = path.relative(cwd, outDir);
|
|
434
|
+
|
|
435
|
+
if (
|
|
436
|
+
!relative || // outDir === cwd
|
|
437
|
+
relative === '..' || // above cwd
|
|
438
|
+
relative.startsWith('../') || // above cwd
|
|
439
|
+
path.isAbsolute(relative) || // different drive/root
|
|
440
|
+
relative.split(path.sep).length < 2 // top-level dir like "dist" with no subfolder
|
|
441
|
+
) {
|
|
442
|
+
console.error(
|
|
443
|
+
`[SwatchKit] Refusing to clean outDir "${outDir}" — must be a subdirectory at least 2 levels deep (e.g., dist/swatchkit).`,
|
|
444
|
+
);
|
|
445
|
+
process.exit(1);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
427
449
|
function build(settings) {
|
|
428
450
|
console.log(`[SwatchKit] Starting build...`);
|
|
429
451
|
console.log(` Source: ${settings.swatchkitDir}`);
|
|
@@ -438,7 +460,13 @@ function build(settings) {
|
|
|
438
460
|
process.exit(1);
|
|
439
461
|
}
|
|
440
462
|
|
|
441
|
-
// 2.
|
|
463
|
+
// 2. Clean previous output (only our subdirectory, never the parent)
|
|
464
|
+
validateOutDir(settings.outDir);
|
|
465
|
+
if (fs.existsSync(settings.outDir)) {
|
|
466
|
+
fs.rmSync(settings.outDir, { recursive: true });
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// 3. Ensure dist directories exist
|
|
442
470
|
[settings.outDir, settings.distCssDir, settings.distJsDir].forEach((dir) => {
|
|
443
471
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
444
472
|
});
|
|
@@ -446,7 +474,12 @@ function build(settings) {
|
|
|
446
474
|
// 2.5 Process Tokens
|
|
447
475
|
console.log("Reading JSON tokens (tokens/*.json)...");
|
|
448
476
|
// Output tokens.css to css/global/tokens.css
|
|
449
|
-
processTokens(settings.tokensDir, path.join(settings.cssDir, "global"));
|
|
477
|
+
const tokensContext = processTokens(settings.tokensDir, path.join(settings.cssDir, "global"));
|
|
478
|
+
|
|
479
|
+
// Generate Utilities to css/utilities/tokens.css
|
|
480
|
+
if (tokensContext) {
|
|
481
|
+
generateTokenUtilities(tokensContext, path.join(settings.cssDir, "utilities"));
|
|
482
|
+
}
|
|
450
483
|
|
|
451
484
|
// 2.6 Generate token display HTML from JSON
|
|
452
485
|
const tokensUiDir = path.join(settings.swatchkitDir, "tokens");
|
|
@@ -674,7 +707,7 @@ function build(settings) {
|
|
|
674
707
|
|
|
675
708
|
// --- 6. Watch Logic ---
|
|
676
709
|
function watch(settings) {
|
|
677
|
-
const
|
|
710
|
+
const sourcePaths = [
|
|
678
711
|
settings.swatchkitDir,
|
|
679
712
|
settings.tokensDir,
|
|
680
713
|
settings.projectLayout,
|
|
@@ -683,30 +716,48 @@ function watch(settings) {
|
|
|
683
716
|
|
|
684
717
|
console.log("[SwatchKit] Watch mode enabled.");
|
|
685
718
|
console.log("Watching for changes in:");
|
|
686
|
-
|
|
719
|
+
sourcePaths.forEach((p) => console.log(` - ${p}`));
|
|
720
|
+
console.log(` Polling: ${settings.outDir} (rebuild if deleted by external tools)`);
|
|
687
721
|
|
|
688
722
|
let buildTimeout;
|
|
723
|
+
let isRebuilding = false;
|
|
724
|
+
|
|
689
725
|
const rebuild = () => {
|
|
690
726
|
if (buildTimeout) clearTimeout(buildTimeout);
|
|
691
727
|
buildTimeout = setTimeout(() => {
|
|
692
728
|
try {
|
|
729
|
+
isRebuilding = true;
|
|
693
730
|
console.log("[SwatchKit] Change detected. Rebuilding...");
|
|
694
731
|
build(settings);
|
|
695
732
|
} catch (e) {
|
|
696
733
|
console.error("[SwatchKit] Build failed:", e.message);
|
|
734
|
+
} finally {
|
|
735
|
+
isRebuilding = false;
|
|
697
736
|
}
|
|
698
737
|
}, 100); // 100ms debounce
|
|
699
738
|
};
|
|
700
739
|
|
|
701
|
-
|
|
740
|
+
// Watch source files for changes
|
|
741
|
+
const sourceWatcher = chokidar.watch(sourcePaths, {
|
|
702
742
|
ignored: /(^|[\/\\])\../, // ignore dotfiles
|
|
703
743
|
persistent: true,
|
|
704
744
|
ignoreInitial: true,
|
|
705
745
|
});
|
|
706
746
|
|
|
707
|
-
|
|
747
|
+
sourceWatcher.on("all", () => {
|
|
708
748
|
rebuild();
|
|
709
749
|
});
|
|
750
|
+
|
|
751
|
+
// Poll for output directory deletion (e.g., when a framework build wipes dist/).
|
|
752
|
+
// We use polling instead of a chokidar watcher on the output dir to avoid
|
|
753
|
+
// infinite rebuild loops — since our own build deletes and recreates the
|
|
754
|
+
// output directory, an event-based watcher would retrigger endlessly.
|
|
755
|
+
setInterval(() => {
|
|
756
|
+
if (!isRebuilding && !fs.existsSync(settings.outDir)) {
|
|
757
|
+
console.log("[SwatchKit] Output directory was deleted. Rebuilding...");
|
|
758
|
+
rebuild();
|
|
759
|
+
}
|
|
760
|
+
}, 2000);
|
|
710
761
|
}
|
|
711
762
|
|
|
712
763
|
// --- Main Execution ---
|