{"id":31742850,"url":"https://github.com/crescendolab-open/css-var-ts","last_synced_at":"2025-10-13T15:01:52.614Z","repository":{"id":318659089,"uuid":"1071268910","full_name":"crescendolab-open/css-var-ts","owner":"crescendolab-open","description":"Type-safe utilities for CSS Custom Properties","archived":false,"fork":false,"pushed_at":"2025-10-08T12:36:06.000Z","size":1812,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-08T14:25:49.690Z","etag":null,"topics":["css-in-js","css-properties","css-variables","design-system","emotion","emotionjs","figma","mui","mui-joy","mui-material","mui-system","reactjs","storybook","type-safe","typescript","variables"],"latest_commit_sha":null,"homepage":"https://crescendolab-open.github.io/css-var-ts/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crescendolab-open.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-07T05:45:03.000Z","updated_at":"2025-10-08T12:35:42.000Z","dependencies_parsed_at":"2025-10-08T14:27:14.926Z","dependency_job_id":"5f572228-828a-4f82-8298-ee6d614e172b","html_url":"https://github.com/crescendolab-open/css-var-ts","commit_stats":null,"previous_names":["crescendolab-open/css-var-ts"],"tags_count":1,"template":false,"template_full_name":"VdustR/template-aio","purl":"pkg:github/crescendolab-open/css-var-ts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Fcss-var-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Fcss-var-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Fcss-var-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Fcss-var-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crescendolab-open","download_url":"https://codeload.github.com/crescendolab-open/css-var-ts/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crescendolab-open%2Fcss-var-ts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001290,"owners_count":26083058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css-in-js","css-properties","css-variables","design-system","emotion","emotionjs","figma","mui","mui-joy","mui-material","mui-system","reactjs","storybook","type-safe","typescript","variables"],"created_at":"2025-10-09T11:18:39.587Z","updated_at":"2025-10-09T11:18:44.084Z","avatar_url":"https://github.com/crescendolab-open.png","language":"TypeScript","readme":"# 🌟 @crescendolab/css-var-ts\n\nType-safe, ergonomic utilities for authoring, registering, and consuming CSS Custom Properties (CSS Variables) in TypeScript.\n\n[![npm (scoped)](https://img.shields.io/npm/v/@crescendolab/css-var-ts)](https://www.npmjs.com/package/@crescendolab/css-var-ts)\n\n---\n\n## 🚀 Features\n\n- ✅ Strongly typed CSS variable keys \u0026 values\n- ✅ Auto–generated collision‑resistant variable names (slug + short random id)\n- ✅ Zero dependency (createCssVarUtils)\n- ✅ Convenient `.cssProps` map you can spread into inline styles / style objects\n- ✅ Easy integration with: `@emotion/css`, `@emotion/react` (css prop), `@mui/system` (`sx` prop)\n- ✅ Compose semantic variables from a base palette safely (`getValue` → `var(--token)`)\n- ✅ Advanced: custom variable key generator via `createCssVarUtils`\n- ✅ Advanced: works with `@property` at‑rule registration\n\n---\n\n## 📦 Installation\n\n```bash\npnpm add @crescendolab/css-var-ts\n# or\nnpm i @crescendolab/css-var-ts\n# or\nyarn add @crescendolab/css-var-ts\n```\n\n---\n\n## ⚡ Quick Start\n\n```ts\nimport { cssVarUtils } from \"@crescendolab/css-var-ts\";\n\n// 1. Define a base palette\nconst palette = cssVarUtils.define({\n  primaryBlue: \"#0074D9\",\n  accentPink: \"#F012BE\",\n  neutralBg: \"#FFFFFF\",\n  neutralFg: \"#111111\",\n});\n\n// 2. Define semantic tokens referencing the palette (type‑safe)\nconst semantic = cssVarUtils.define({\n  brand: palette.getValue(\"primaryBlue\"),\n  text: palette.getValue(\"neutralFg\"),\n  background: palette.getValue(\"neutralBg\"),\n});\n\n// 3. Use in styles\nconst style: React.CSSProperties = {\n  ...palette.cssProps,\n  ...semantic.cssProps,\n  color: semantic.getValue(\"text\"),\n  backgroundColor: semantic.getValue(\"background\"),\n};\n```\n\nResulting (example) generated variable keys (random 8‑char suffix) look like:\n\n```text\n--primaryblue-a1b2c3d4\n--accentpink-9fe012ab\n```\n\n---\n\n## 🧩 Basic Usage (from Storybook “01_basic”)\n\n```ts\nimport { cssVarUtils } from \"@crescendolab/css-var-ts\";\n\nconst paletteDefinition = cssVarUtils.define({\n  navy: \"#001F3F\",\n  blue: \"#0074D9\",\n  aqua: \"#7FDBFF\",\n  // ...\n});\n\nconst semantic = cssVarUtils.define({\n  primary: paletteDefinition.getValue(\"navy\"),\n  foreground: paletteDefinition.getValue(\"black\"),\n});\n\n// Override one semantic var dynamically\nconst dynamicStyle = {\n  ...paletteDefinition.cssProps,\n  ...semantic.cssProps,\n  [semantic.getKey(\"primary\")]: paletteDefinition.getValue(\"blue\"),\n  color: semantic.getValue(\"foreground\"),\n};\n```\n\nWhy the two steps? You keep a raw color inventory (can later switch based on theme) and build semantic tokens referencing it. Both sets remain type‑safe.\n\n---\n\n## 🎨 Integrations\n\n### Emotion (`@emotion/css`)\n\n```ts\nimport { css } from \"@emotion/css\";\nimport {\n  gruvboxCssVarBaseDefinition,\n  gruvboxCssVarLightDefinition,\n} from \"./styles\";\n\nconst container = css({\n  ...gruvboxCssVarBaseDefinition.cssProps,\n  ...gruvboxCssVarLightDefinition.cssProps,\n  color: gruvboxCssVarLightDefinition.getValue(\"fg\"),\n});\n```\n\n### Emotion (`css` prop)\n\n```tsx\nimport { css } from \"@emotion/react\";\nconst button = css({\n  color: gruvboxCssVarLightDefinition.getValue(\"fg\"),\n  backgroundColor: gruvboxCssVarLightDefinition.getValue(\"bg\"),\n});\n```\n\n### MUI (`sx` prop)\n\n```tsx\n\u003cBox\n  sx={{\n    ...gruvboxCssVarBaseDefinition.cssProps,\n    ...gruvboxCssVarLightDefinition.cssProps,\n    color: gruvboxCssVarLightDefinition.getValue(\"fg\"),\n  }}\n/\u003e\n```\n\n\u003e See live Storybook demos below for full examples including light/dark variants and status colors.\n\n---\n\n## 🛠️ Advanced\n\n### Custom Variable Key Strategy\n\nUse `createCssVarUtils` to fully control how variable names are produced (e.g. ephemeral / randomized keys).\n\n```ts\nimport { createCssVarUtils } from \"@crescendolab/css-var-ts\";\n\nconst randomCssVarUtils = createCssVarUtils({\n  recordKeyToCssVarKey: () =\u003e\n    `--random-${Math.random().toString(16).slice(2)}` as const,\n});\n\nconst randomVars = randomCssVarUtils.define({\n  primary: \"#0074D9\",\n});\n\nrandomVars.getKey(\"primary\"); // different each load\n```\n\n### `@property` Registration\n\nYou can register variables with the CSS Typed OM for transitions, inheritance, etc.\n\n```ts\nconst definition = cssVarUtils.define({ primaryColor: \"#F012BE\" });\n\nCSS.registerProperty({\n  name: definition.getKey(\"primaryColor\"),\n  syntax: \"\u003ccolor\u003e\",\n  inherits: true,\n  initialValue: \"#F012BE\",\n});\n```\n\n---\n\n### Recommendations for Large CSS-in-JS Apps\n\nFor large-scale web applications (mono-repos, micro frontends, dynamic plugin architectures) you should take extra precautions to avoid accidental variable name collisions and to harden your design system surface.\n\n1. Strengthen uniqueness: Provide a custom `recordKeyToCssVarKey` that injects a namespace (package name) plus a stable build hash or random suffix.\n\n   ```ts\n   import { createCssVarUtils } from \"@crescendolab/css-var-ts\";\n\n   const ns = process.env.APP_NAMESPACE ?? \"app\"; // e.g. marketing, analytics\n   const buildId = process.env.COMMIT_SHA?.slice(0, 7) ?? \"dev\";\n\n   const scopedCssVarUtils = createCssVarUtils({\n     recordKeyToCssVarKey: (k) =\u003e\n       `--${ns}-${buildId}-${k}-${Math.random().toString(36).slice(2, 8)}` as const,\n   });\n   ```\n\n   For deterministic builds replace `Math.random()` with a hash of `(ns + buildId + k)`.\n\n2. Strongly recommended: Register core design tokens via `@property` to enforce syntax (e.g. `\u003ccolor\u003e`, `\u003clength\u003e`) and enable smoother transitions \u0026 validation.\n3. Expose only semantic tokens to feature teams; keep raw palette tokens private to your design system package.\n4. Document namespace conventions so new packages follow the same pattern.\n5. Periodically audit generated variable names (e.g. collect with a build script) to detect drift or duplication.\n\nThese measures reduce the chance of silent styling regressions when independently deployed bundles are combined at runtime.\n\n---\n\n## 🔍 API Reference\n\n### `cssVarUtils`\n\nThe default exported utility bundle.\n\n```ts\nconst definition = cssVarUtils.define({ accent: \"#F012BE\" });\ndefinition.cssVarRecord; // { accent: \"#F012BE\" }\n// example suffix will differ each run (8 random hex chars):\ndefinition.cssProps; // { \"--accent-a1b2c3d4\": \"#F012BE\" }\ndefinition.getKey(\"accent\"); // \"--accent-a1b2c3d4\"\ndefinition.getValue(\"accent\"); // \"var(--accent-a1b2c3d4)\"\n```\n\nEach call to `define()` returns an object:\n\n| Key              | Type                      | Description                                                   |\n| ---------------- | ------------------------- | ------------------------------------------------------------- |\n| `cssVarRecord`   | original readonly record  | Raw tokens you passed in                                      |\n| `cssProps`       | Record\u003ccssVarKey, string\u003e | Object you can spread into style systems to declare variables |\n| `getKey(name)`   | string                    | Generated CSS variable name (e.g. `--accent-…`)               |\n| `getValue(name)` | `var(--token)`            | Proper `var()` usage string                                   |\n\n### `createCssVarUtils(options)`\n\nLow‑level factory to customize naming.\n\n```ts\nconst custom = createCssVarUtils({\n  recordKeyToCssVarKey: (k) =\u003e `--my-${k}` as const,\n});\n```\n\n### Helper Exports\n\n| Export         | Purpose                                                        |\n| -------------- | -------------------------------------------------------------- |\n| `slugify`      | Deterministic slug for record keys                             |\n| `randomString` | Cryptographically strong random id (hex) for custom strategies |\n\n---\n\n## 📚 Storybook Examples\n\n| Category           | Story              | Code                                                                                                                                                                                              | Live Demo                                                                                                                    |\n| ------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| Basic              | Palette + semantic | [`01_basic`](https://github.com/crescendolab-open/css-var-ts/tree/main/packages/examples/src/examples/01_basic/index.stories.tsx)                                                                 | [Playground](https://crescendolab-open.github.io/css-var-ts/?path=/story/examples-01-basic--playground)                      |\n| Emotion (class)    | `@emotion/css`     | [`02_integration/01_emotion/01_emotion_css`](https://github.com/crescendolab-open/css-var-ts/tree/main/packages/examples/src/examples/02_integration/01_emotion/01_emotion_css/index.stories.tsx) | [Demo](https://crescendolab-open.github.io/css-var-ts/?path=/story/examples-02-integration-01-emotion-01-emotion-css--story) |\n| Emotion (css prop) | `@emotion/react`   | [`02_integration/01_emotion/02_css_prop`](https://github.com/crescendolab-open/css-var-ts/tree/main/packages/examples/src/examples/02_integration/01_emotion/02_css_prop/index.stories.tsx)       | [Demo](https://crescendolab-open.github.io/css-var-ts/?path=/story/examples-02-integration-01-emotion-02-css-prop--story)    |\n| MUI                | `sx` prop          | [`02_integration/02_mui_sx_prop`](https://github.com/crescendolab-open/css-var-ts/tree/main/packages/examples/src/examples/02_integration/02_mui_sx_prop/index.stories.tsx)                       | [Demo](https://crescendolab-open.github.io/css-var-ts/?path=/story/examples-02-integration-02-mui-sx-prop--story)            |\n| Advanced           | Static custom keys | [`03_advanced/01_staticCssVarKey`](https://github.com/crescendolab-open/css-var-ts/tree/main/packages/examples/src/examples/03_advanced/01_staticCssVarKey.stories.tsx)                           | [Demo](https://crescendolab-open.github.io/css-var-ts/?path=/story/examples-03-advanced-01-staticcssvarkey--playground)      |\n| Advanced           | `@property`        | [`03_advanced/02_@property_atRule`](https://github.com/crescendolab-open/css-var-ts/tree/main/packages/examples/src/examples/03_advanced/02_@property_atRule.stories.tsx)                         | [Demo](https://crescendolab-open.github.io/css-var-ts/?path=/story/examples-03-advanced-02-property-atrule--at-rule)         |\n\n---\n\n## 🤔 Why add a random suffix?\n\nAdding a short random suffix mitigates accidental collisions when multiple packages / microfrontends define the same token names. It keeps names mostly human readable while providing lightweight namespacing. For fully deterministic readable names use a static strategy; for strict isolation include a package or build id.\n\n### Strategy Summary\n\nList of approaches:\n\n- Default (`cssVarUtils`): Slug + random 8‑char id = collision‑resistant and readable.\n- Static custom (see story): `--static-${slug}` for fully readable tokens; ensure uniqueness manually.\n- Random / ephemeral: `createCssVarUtils` + `randomString` / build hash for experiments, multi‑tenant isolation, A/B variants.\n\n---\n\n## 🧪 Testing Strategy\n\nLibrary surface is pure \u0026 easily unit testable (see `randomString.test.ts` for an example). Add tests as you add helpers: focus on stability of generated keys and referential integrity between `getKey` and `getValue`.\n\n---\n\n## 🛠 Release Automation\n\nThis repo uses **changesets** + GitHub Actions. On merge to `main`, a version PR is created / updated. Approve \u0026 merge to publish.\n\nEnsure org settings allow the workflow to create \u0026 approve PRs:\nSettings → Code and automation → Actions → General → Workflow permissions:\n\n- Read \u0026 write permissions\n- Allow GitHub Actions to create and approve pull requests\n\n---\n\n## 🤝 Contributing\n\nPRs welcome! See the [contributing guide](https://github.com/VdustR/template-aio/blob/main/CONTRIBUTING.md).\n\nSuggested areas:\n\n- New integrations (e.g. Tailwind plugin example)\n- Additional DX helpers\n- Documentation improvements\n\n---\n\n## 📜 License\n\n[Apache-2.0](https://github.com/crescendolab-open/reamgif/blob/main/LICENSE)\n\nCopyright (c) 2025 [Crescendo Lab](https://github.com/crescendolab-open/)\n\n---\n\nMade with ❤️ to make CSS variables first-class citizens in TypeScript.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrescendolab-open%2Fcss-var-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrescendolab-open%2Fcss-var-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrescendolab-open%2Fcss-var-ts/lists"}