├── .gitignore ├── .github ├── banner.jpg └── clazzx.png ├── mod.ts ├── .helix └── languages.toml ├── src ├── build.ts ├── tests.ts └── clazzx.ts ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | npm/ -------------------------------------------------------------------------------- /.github/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b3nten/clazzx/HEAD/.github/banner.jpg -------------------------------------------------------------------------------- /.github/clazzx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b3nten/clazzx/HEAD/.github/clazzx.png -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | export { ClazzX, clx } from "./src/clazzx.ts"; 2 | export type { StyleProps } from "./src/clazzx.ts"; 3 | -------------------------------------------------------------------------------- /.helix/languages.toml: -------------------------------------------------------------------------------- 1 | [[language]] 2 | name = "javascript" 3 | language-server = { command = "deno", args = ["lsp"] } 4 | config = { enable = true } 5 | 6 | [[language]] 7 | name = "typescript" 8 | language-server = { command = "deno", args = ["lsp"] } 9 | config = { enable = true } 10 | -------------------------------------------------------------------------------- /src/build.ts: -------------------------------------------------------------------------------- 1 | // ex. scripts/build_npm.ts 2 | import { build, emptyDir } from "https://deno.land/x/dnt/mod.ts"; 3 | 4 | await emptyDir("./npm"); 5 | 6 | await build({ 7 | entryPoints: ["./mod.ts"], 8 | outDir: "./npm", 9 | shims: { 10 | // see JS docs for overview and more options 11 | deno: true, 12 | }, 13 | package: { 14 | // package.json properties 15 | name: "clazzx", 16 | version: "1.0.0", 17 | description: "ClazzX is a small typesafe utility library for composing CSS classes.", 18 | license: "MIT", 19 | repository: { 20 | type: "git", 21 | url: "git+https://github.com/B3nten/clazzx", 22 | }, 23 | }, 24 | typeCheck: false, 25 | }); 26 | 27 | // post build steps 28 | Deno.copyFileSync("LICENSE", "npm/LICENSE"); 29 | Deno.copyFileSync("README.md", "npm/README.md"); -------------------------------------------------------------------------------- /src/tests.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.162.0/testing/asserts.ts"; 2 | import { clx, ClazzX } from "../mod.ts"; 3 | 4 | assertEquals(clx("text-3xl font-bold"), "text-3xl font-bold"); 5 | assertEquals(clx(["text-3xl", "font-bold"]), "text-3xl font-bold"); 6 | assertEquals(clx(["text-3xl", undefined, null]), "text-3xl"); 7 | 8 | assertEquals(clx("text-3xl", "font-bold"), "text-3xl font-bold"); 9 | assertEquals(clx("text-3xl", undefined, null), "text-3xl"); 10 | assertEquals(clx(["text-3xl"], ["font-bold"]), "text-3xl font-bold"); 11 | 12 | class Btn extends ClazzX { 13 | base = "text-3xl font-bold"; 14 | small = "text-sm"; 15 | } 16 | 17 | console.log("btn", Btn.compose({ })); 18 | 19 | class Input extends Btn { 20 | base = "text-3xl font-bold"; 21 | error = "text-red-500" 22 | compounds = [ 23 | { 24 | states: ["small", "error"], 25 | classes: "hover:bg-red-200", 26 | }, 27 | ] 28 | } 29 | 30 | console.log("input", Input.compose({ small: true, error: true })); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2022 Benton Boychuk-Chorney 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/clazzx.ts: -------------------------------------------------------------------------------- 1 | type Clx = 2 | | string 3 | | boolean 4 | | undefined 5 | | null 6 | | Array; 7 | 8 | 9 | /** 10 | * 11 | *clx accepts any number of strings, booleans, undefined, null, or arrays of those types and returns a string of all truthy values. 12 | * @example 13 | * ``` 14 | * clx("text-3xl font-bold") // "text-3xl font-bold" 15 | * clx(["text-3xl", "font-bold"]) // "text-3xl font-bold" 16 | * clx(["text-3xl", undefined, null]) // "text-3xl" 17 | * clx("text-3xl", "font-bold") // "text-3xl font-bold" 18 | * clx("text-3xl", undefined, null) // "text-3xl" 19 | * clx(["text-3xl"], ["font-bold"]) // "text-3xl font-bold" 20 | * ``` 21 | */ 22 | 23 | export const clx = (...input: Array): string => { 24 | if (input.length === 1) { 25 | if (Array.isArray(input[0])) { 26 | return clx(...input[0]); 27 | } else if (typeof input[0] === "string") { 28 | return input[0]; 29 | } 30 | } 31 | const acc: string[] = []; 32 | for (const item of input) { 33 | if (Array.isArray(item)) { 34 | acc.push(clx(...item)); 35 | } else if (typeof item === "string") { 36 | acc.push(item); 37 | } 38 | } 39 | let str = ""; 40 | for (let i = 0; i < acc.length; i++) { 41 | if (acc[i]) { 42 | str += acc[i] + (i < acc.length - 1 ? " " : ""); 43 | } 44 | } 45 | return str; 46 | }; 47 | 48 | type OmitIntrinsic = Omit; 49 | 50 | /** 51 | * StyleProps creates a type from a ClazzX class that is used to define the input to the `compose` method. 52 | * @example 53 | * ``` 54 | * class Btn extends ClazzX { 55 | * base = "text-3xl font-bold"; 56 | * small = "text-sm"; 57 | * } 58 | * 59 | * function Button({...props}: StyleProps) { 60 | * return