tailwind-style-sheets 0.0.1 → 0.0.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # tailwind-style-sheets
2
2
 
3
- A Turbopack loader and Next.js plugin for `.twss` files — co-locate your Tailwind class maps alongside components.
3
+ Co-locate Tailwind class maps alongside components using `.twss` files — a CSS-like syntax that pairs with a Turbopack loader and Next.js plugin.
4
4
 
5
5
  ## What it does
6
6
 
@@ -43,22 +43,13 @@ Inline is also valid:
43
43
  }
44
44
  ```
45
45
 
46
- Importing a `.twss` file gives you a plain object:
47
-
48
- ```ts
49
- import styles from "./Button.styles.twss";
50
- // styles.button → "cursor-pointer px-4 py-2 rounded-full text-sm font-medium transition-all active:scale-95"
51
- // styles["button--primary"] → "bg-blue-600 text-white hover:bg-blue-700"
52
- // styles["button--ghost"] → "bg-transparent text-blue-600 hover:bg-blue-50"
53
- ```
54
-
55
- Pair it with [`@michalshelenberg/modcn`](https://www.npmjs.com/package/@michalshelenberg/modcn) to compose BEM classes ergonomically:
46
+ ## Usage
56
47
 
57
48
  ```tsx
58
- import { modcn } from "@michalshelenberg/modcn";
49
+ import { twcn } from "tailwind-style-sheets";
59
50
  import styles from "./Button.styles.twss";
60
51
 
61
- const cn = modcn(styles);
52
+ const cn = twcn(styles);
62
53
 
63
54
  export function Button({ variant = "primary", className, children, ...props }) {
64
55
  return (
@@ -69,6 +60,8 @@ export function Button({ variant = "primary", className, children, ...props }) {
69
60
  }
70
61
  ```
71
62
 
63
+ `twcn` takes the imported styles object, and returns a function that resolves class names with `tailwind-merge` — pass it style keys, modifiers, and an optional `className` override.
64
+
72
65
  ## Installation
73
66
 
74
67
  ```bash
@@ -133,9 +126,3 @@ Add to `.vscode/settings.json` to get CSS syntax highlighting and silence the `@
133
126
  }
134
127
  }
135
128
  ```
136
-
137
- ## How it works
138
-
139
- 1. **Loader** (`loader.ts`) — Turbopack passes the raw `.twss` file content through the loader. A regex extracts each `.className { @apply ... }` block and converts it to `export default { className: "class1 class2 ..." }`.
140
-
141
- 2. **HMR watcher** (`plugin.ts`) — In development, `fs.watch` monitors `watchDir` for `.twss` changes. When a change is detected, it touches `globalsCSS`, which causes Next.js to re-run Tailwind's class scan and hot-reload styles.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { NextConfig } from 'next';
2
+ import { modcn } from 'modcn';
2
3
 
3
4
  interface TwssPluginOptions {
4
5
  /**
@@ -31,4 +32,7 @@ interface TwssPluginOptions {
31
32
  */
32
33
  declare function withTwssPlugin(nextConfig: NextConfig, options?: TwssPluginOptions): NextConfig;
33
34
 
34
- export { type TwssPluginOptions, withTwssPlugin };
35
+ type StylesMap = Record<string, string>;
36
+ declare function twcn(styles: StylesMap): (...inputs: Parameters<ReturnType<typeof modcn>>) => string;
37
+
38
+ export { type TwssPluginOptions, twcn, withTwssPlugin };
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
47
47
  // src/index.ts
48
48
  var index_exports = {};
49
49
  __export(index_exports, {
50
+ twcn: () => twcn,
50
51
  withTwssPlugin: () => withTwssPlugin
51
52
  });
52
53
  module.exports = __toCommonJS(index_exports);
@@ -75,7 +76,16 @@ function withTwssPlugin(nextConfig, options = {}) {
75
76
  })
76
77
  });
77
78
  }
79
+
80
+ // src/twcn.ts
81
+ var import_modcn = require("modcn");
82
+ var import_tailwind_merge = require("tailwind-merge");
83
+ function twcn(styles) {
84
+ const cn = (0, import_modcn.modcn)(styles);
85
+ return (...inputs) => (0, import_tailwind_merge.twMerge)(cn(...inputs));
86
+ }
78
87
  // Annotate the CommonJS export names for ESM import in node:
79
88
  0 && (module.exports = {
89
+ twcn,
80
90
  withTwssPlugin
81
91
  });
package/dist/loader.js CHANGED
@@ -1,14 +1,43 @@
1
1
  "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
2
19
 
3
20
  // src/loader.ts
21
+ var loader_exports = {};
22
+ __export(loader_exports, {
23
+ default: () => loader_default
24
+ });
25
+ module.exports = __toCommonJS(loader_exports);
26
+
27
+ // src/parse.ts
4
28
  var BLOCK_REGEX = /\.(\w[\w-]*)\s*\{\s*@apply\s+([\s\S]*?)\s*\}/g;
5
- var twssLoader = function(source) {
29
+ function parseTwss(source) {
6
30
  const styles = {};
7
31
  let match;
8
32
  while ((match = BLOCK_REGEX.exec(source)) !== null) {
9
33
  const [, className, classes] = match;
10
34
  styles[className] = classes.trim().replace(/\s+/g, " ");
11
35
  }
12
- return `export default ${JSON.stringify(styles)};`;
36
+ return styles;
37
+ }
38
+
39
+ // src/loader.ts
40
+ var twssLoader = function(source) {
41
+ return `export default ${JSON.stringify(parseTwss(source))};`;
13
42
  };
14
- module.exports = twssLoader;
43
+ var loader_default = twssLoader;
@@ -0,0 +1,5 @@
1
+ import { Plugin } from 'vite';
2
+
3
+ declare function twssVitePlugin(): Plugin;
4
+
5
+ export { twssVitePlugin };
package/dist/vite.mjs ADDED
@@ -0,0 +1,37 @@
1
+ // src/parse.ts
2
+ var BLOCK_REGEX = /\.(\w[\w-]*)\s*\{\s*@apply\s+([\s\S]*?)\s*\}/g;
3
+ function parseTwss(source) {
4
+ const styles = {};
5
+ let match;
6
+ while ((match = BLOCK_REGEX.exec(source)) !== null) {
7
+ const [, className, classes] = match;
8
+ styles[className] = classes.trim().replace(/\s+/g, " ");
9
+ }
10
+ return styles;
11
+ }
12
+
13
+ // src/vite-plugin.ts
14
+ function twssVitePlugin() {
15
+ return {
16
+ name: "tailwind-style-sheets",
17
+ transform(code, id) {
18
+ if (!id.endsWith(".twss")) return null;
19
+ const styles = parseTwss(code);
20
+ return {
21
+ code: `export default ${JSON.stringify(styles)};`,
22
+ map: null
23
+ };
24
+ },
25
+ handleHotUpdate({ file, server }) {
26
+ if (!file.endsWith(".twss")) return;
27
+ const mod = server.moduleGraph.getModuleById(file);
28
+ if (mod) {
29
+ server.moduleGraph.invalidateModule(mod);
30
+ server.hot.send({ type: "full-reload" });
31
+ }
32
+ }
33
+ };
34
+ }
35
+ export {
36
+ twssVitePlugin
37
+ };
package/package.json CHANGED
@@ -1,17 +1,37 @@
1
1
  {
2
2
  "name": "tailwind-style-sheets",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.js"
11
+ },
12
+ "./vite": {
13
+ "types": "./dist/vite.d.mts",
14
+ "import": "./dist/vite.mjs"
15
+ }
16
+ },
6
17
  "bin": {
7
18
  "tailwind-style-sheets": "./dist/cli.js"
8
19
  },
9
20
  "scripts": {
10
- "build": "tsup",
21
+ "build": "rm -rf dist && tsup",
11
22
  "dev": "tsup --watch"
12
23
  },
24
+ "dependencies": {
25
+ "tailwind-merge": "^3.5.0"
26
+ },
13
27
  "peerDependencies": {
14
- "next": ">=15"
28
+ "modcn": "^0.0.1",
29
+ "next": ">=15",
30
+ "vite": ">=5"
31
+ },
32
+ "peerDependenciesMeta": {
33
+ "next": { "optional": true },
34
+ "vite": { "optional": true }
15
35
  },
16
36
  "publishConfig": {
17
37
  "access": "public"
@@ -20,6 +40,7 @@
20
40
  "@types/node": "^20",
21
41
  "next": "16.2.1",
22
42
  "tsup": "^8.5.1",
23
- "typescript": "^5"
43
+ "typescript": "^5",
44
+ "vite": "^8.0.1"
24
45
  }
25
46
  }
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { withTwssPlugin } from "./plugin";
2
2
  export type { TwssPluginOptions } from "./plugin";
3
+ export { twcn } from "./twcn";
package/src/loader.ts CHANGED
@@ -15,18 +15,10 @@
15
15
  * Output (JS module):
16
16
  * export default { base: "px-4 py-2 rounded font-semibold", primary: "bg-blue-600 text-white hover:bg-blue-700" }
17
17
  */
18
- const BLOCK_REGEX = /\.(\w[\w-]*)\s*\{\s*@apply\s+([\s\S]*?)\s*\}/g;
18
+ import { parseTwss } from "./parse";
19
19
 
20
20
  const twssLoader: (source: string) => string = function (source) {
21
- const styles: Record<string, string> = {};
22
-
23
- let match: RegExpExecArray | null;
24
- while ((match = BLOCK_REGEX.exec(source)) !== null) {
25
- const [, className, classes] = match;
26
- styles[className] = classes.trim().replace(/\s+/g, " ");
27
- }
28
-
29
- return `export default ${JSON.stringify(styles)};`;
21
+ return `export default ${JSON.stringify(parseTwss(source))};`;
30
22
  };
31
23
 
32
- export = twssLoader;
24
+ export default twssLoader;
package/src/parse.ts ADDED
@@ -0,0 +1,13 @@
1
+ const BLOCK_REGEX = /\.(\w[\w-]*)\s*\{\s*@apply\s+([\s\S]*?)\s*\}/g;
2
+
3
+ export function parseTwss(source: string): Record<string, string> {
4
+ const styles: Record<string, string> = {};
5
+
6
+ let match: RegExpExecArray | null;
7
+ while ((match = BLOCK_REGEX.exec(source)) !== null) {
8
+ const [, className, classes] = match;
9
+ styles[className] = classes.trim().replace(/\s+/g, " ");
10
+ }
11
+
12
+ return styles;
13
+ }
package/src/twcn.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { modcn } from "modcn";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ type StylesMap = Record<string, string>;
5
+
6
+ export function twcn(styles: StylesMap) {
7
+ const cn = modcn(styles);
8
+ return (...inputs: Parameters<ReturnType<typeof modcn>>) =>
9
+ twMerge(cn(...inputs));
10
+ }
@@ -0,0 +1,28 @@
1
+ import { parseTwss } from "./parse";
2
+ import type { Plugin } from "vite";
3
+
4
+ export function twssVitePlugin(): Plugin {
5
+ return {
6
+ name: "tailwind-style-sheets",
7
+
8
+ transform(code, id) {
9
+ if (!id.endsWith(".twss")) return null;
10
+
11
+ const styles = parseTwss(code);
12
+ return {
13
+ code: `export default ${JSON.stringify(styles)};`,
14
+ map: null,
15
+ };
16
+ },
17
+
18
+ handleHotUpdate({ file, server }) {
19
+ if (!file.endsWith(".twss")) return;
20
+
21
+ const mod = server.moduleGraph.getModuleById(file);
22
+ if (mod) {
23
+ server.moduleGraph.invalidateModule(mod);
24
+ server.hot.send({ type: "full-reload" });
25
+ }
26
+ },
27
+ };
28
+ }
package/src/vite.ts ADDED
@@ -0,0 +1 @@
1
+ export { twssVitePlugin } from "./vite-plugin";
package/tsconfig.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2017",
4
- "module": "commonjs",
5
- "moduleResolution": "node",
4
+ "module": "esnext",
5
+ "moduleResolution": "bundler",
6
6
  "skipLibCheck": true,
7
7
  "strict": true,
8
8
  "esModuleInterop": true,
package/tsup.config.ts CHANGED
@@ -6,7 +6,12 @@ export default defineConfig([
6
6
  format: ["cjs"],
7
7
  external: ["./loader"],
8
8
  dts: true,
9
- clean: true,
9
+ },
10
+ {
11
+ entry: ["src/vite.ts"],
12
+ format: ["esm"],
13
+ external: ["vite"],
14
+ dts: true,
10
15
  },
11
16
  {
12
17
  entry: ["src/cli.ts"],