swatchkit 0.5.0 → 0.6.1

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 (3) hide show
  1. package/README.md +20 -3
  2. package/build.js +58 -8
  3. 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
- └── public/
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 `public/swatchkit/`.
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: `public/swatchkit`). |
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
@@ -110,12 +110,12 @@ function resolveSettings(cliOptions, fileConfig) {
110
110
  const swatchkitDir = findSwatchkitDir();
111
111
 
112
112
  // Output Dir
113
- // Default: public/swatchkit
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, "public/swatchkit");
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
@@ -428,6 +428,24 @@ ${scriptContent}
428
428
  return swatches;
429
429
  }
430
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
+
431
449
  function build(settings) {
432
450
  console.log(`[SwatchKit] Starting build...`);
433
451
  console.log(` Source: ${settings.swatchkitDir}`);
@@ -442,7 +460,13 @@ function build(settings) {
442
460
  process.exit(1);
443
461
  }
444
462
 
445
- // 2. Ensure dist directories exist
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
446
470
  [settings.outDir, settings.distCssDir, settings.distJsDir].forEach((dir) => {
447
471
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
448
472
  });
@@ -683,7 +707,7 @@ function build(settings) {
683
707
 
684
708
  // --- 6. Watch Logic ---
685
709
  function watch(settings) {
686
- const watchPaths = [
710
+ const sourcePaths = [
687
711
  settings.swatchkitDir,
688
712
  settings.tokensDir,
689
713
  settings.projectLayout,
@@ -692,30 +716,56 @@ function watch(settings) {
692
716
 
693
717
  console.log("[SwatchKit] Watch mode enabled.");
694
718
  console.log("Watching for changes in:");
695
- watchPaths.forEach((p) => console.log(` - ${p}`));
719
+ sourcePaths.forEach((p) => console.log(` - ${p}`));
720
+ console.log(` Polling: ${settings.outDir} (rebuild if deleted by external tools)`);
696
721
 
697
722
  let buildTimeout;
723
+ let isRebuilding = false;
724
+
698
725
  const rebuild = () => {
699
726
  if (buildTimeout) clearTimeout(buildTimeout);
700
727
  buildTimeout = setTimeout(() => {
701
728
  try {
729
+ isRebuilding = true;
702
730
  console.log("[SwatchKit] Change detected. Rebuilding...");
703
731
  build(settings);
704
732
  } catch (e) {
705
733
  console.error("[SwatchKit] Build failed:", e.message);
734
+ } finally {
735
+ isRebuilding = false;
706
736
  }
707
737
  }, 100); // 100ms debounce
708
738
  };
709
739
 
710
- const watcher = chokidar.watch(watchPaths, {
711
- ignored: /(^|[\/\\])\../, // ignore dotfiles
740
+ // Watch source files for changes.
741
+ // Ignore the tokens UI directory inside swatchkitDir — the build generates
742
+ // HTML files there (swatchkit/tokens/*.html), which would retrigger the
743
+ // watcher and cause an infinite rebuild loop.
744
+ const tokensUiDir = path.join(settings.swatchkitDir, "tokens");
745
+
746
+ const sourceWatcher = chokidar.watch(sourcePaths, {
747
+ ignored: [
748
+ /(^|[\/\\])\../, // ignore dotfiles
749
+ tokensUiDir, // ignore build-generated token HTML
750
+ ],
712
751
  persistent: true,
713
752
  ignoreInitial: true,
714
753
  });
715
754
 
716
- watcher.on("all", (event, path) => {
755
+ sourceWatcher.on("all", () => {
717
756
  rebuild();
718
757
  });
758
+
759
+ // Poll for output directory deletion (e.g., when a framework build wipes dist/).
760
+ // We use polling instead of a chokidar watcher on the output dir to avoid
761
+ // infinite rebuild loops — since our own build deletes and recreates the
762
+ // output directory, an event-based watcher would retrigger endlessly.
763
+ setInterval(() => {
764
+ if (!isRebuilding && !fs.existsSync(settings.outDir)) {
765
+ console.log("[SwatchKit] Output directory was deleted. Rebuilding...");
766
+ rebuild();
767
+ }
768
+ }, 2000);
719
769
  }
720
770
 
721
771
  // --- Main Execution ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swatchkit",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "A lightweight tool for creating HTML pattern libraries.",
5
5
  "main": "build.js",
6
6
  "bin": {