{"id":13599754,"url":"https://github.com/blakeembrey/free-style","last_synced_at":"2025-10-08T21:58:10.783Z","repository":{"id":25156803,"uuid":"28579585","full_name":"blakeembrey/free-style","owner":"blakeembrey","description":"Make CSS easier and more maintainable by using JavaScript","archived":false,"fork":false,"pushed_at":"2024-01-18T20:30:38.000Z","size":952,"stargazers_count":707,"open_issues_count":3,"forks_count":28,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-09-09T08:37:37.192Z","etag":null,"topics":["css","css-in-js","css-string","dedupe","hash","javascript","js","minification","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blakeembrey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-12-29T03:56:46.000Z","updated_at":"2025-07-09T07:58:10.000Z","dependencies_parsed_at":"2024-01-17T20:32:44.784Z","dependency_job_id":"121462f1-4834-4201-8b49-5f6c8d89ad3c","html_url":"https://github.com/blakeembrey/free-style","commit_stats":{"total_commits":278,"total_committers":14,"mean_commits":"19.857142857142858","dds":"0.14028776978417268","last_synced_commit":"eb921ab5457f327ac24f0ea2822715d73af4cfd3"},"previous_names":[],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/blakeembrey/free-style","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blakeembrey%2Ffree-style","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blakeembrey%2Ffree-style/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blakeembrey%2Ffree-style/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blakeembrey%2Ffree-style/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blakeembrey","download_url":"https://codeload.github.com/blakeembrey/free-style/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blakeembrey%2Ffree-style/sbom","scorecard":{"id":242573,"data":{"date":"2025-08-11","repo":{"name":"github.com/blakeembrey/free-style","commit":"eb921ab5457f327ac24f0ea2822715d73af4cfd3"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Pinned-Dependencies","score":4,"reason":"dependency not pinned by hash detected -- score normalized to 4","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/blakeembrey/free-style/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/blakeembrey/free-style/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/blakeembrey/free-style/ci.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/blakeembrey/free-style/ci.yml/master?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 1 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"18 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c24v-8rfc-w8vw","Warn: Project is vulnerable to: GHSA-8jhw-289h-jh2g","Warn: Project is vulnerable to: GHSA-64vr-g452-qvp3","Warn: Project is vulnerable to: GHSA-9cwx-2883-4wfx","Warn: Project is vulnerable to: GHSA-vg6x-rcgg-rjx6","Warn: Project is vulnerable to: GHSA-x574-m823-4x7w","Warn: Project is vulnerable to: GHSA-4r4m-qw57-chr8","Warn: Project is vulnerable to: GHSA-xcj6-pq6g-qj4x","Warn: Project is vulnerable to: GHSA-356w-63v5-8wf4","Warn: Project is vulnerable to: GHSA-859w-5945-r5v3","Warn: Project is vulnerable to: GHSA-9crc-q9x8-hgqq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T06:55:29.171Z","repository_id":25156803,"created_at":"2025-08-17T06:55:29.171Z","updated_at":"2025-08-17T06:55:29.171Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000686,"owners_count":26082837,"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-08T02:00:06.501Z","response_time":56,"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","css-in-js","css-string","dedupe","hash","javascript","js","minification","typescript"],"created_at":"2024-08-01T17:01:10.751Z","updated_at":"2025-10-08T21:58:10.761Z","avatar_url":"https://github.com/blakeembrey.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Free-Style\n\n\u003e **Free-Style** is designed to make CSS easier and more maintainable by using JavaScript.\n\n## Installation\n\n```\nnpm install free-style --save\n```\n\n## Why?\n\nThere's a [great presentation by Christopher Chedeau](https://speakerdeck.com/vjeux/react-css-in-js) you should check out.\n\n### Solved by using CSS in JS\n\n- No global variables (What and where is `.button`? Why is it conflicting?)\n- Defined dependency systems (CommonJS, Require.js, `\u003cscript /\u003e`)\n- Dead code elimination automatically removes unused styles\n- Minification through JavaScript tooling\n- Shared constants and reusable styles\n- Every style is isolated, tested and namespaced to the JS component\n- Extensible - everything from [Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math) to [color manipulation](https://github.com/MoOx/color) already exists!\n\n### Also solved with Free-Style\n\n- Works with third-party DOM components (You can nest regular `.class-name` in your styles)\n- Deterministically generates styles and class names, and automatically merges duplicate styles\n- Develop components alongside the style (No more hunting CSS files for estranged `ul \u003e li \u003e a`)\n- Create universal applications and serve styles for **only** the components rendered (see [React Free-Style](http://github.com/blakeembrey/react-free-style))\n- Write the CSS you already know (`{ '\u0026:hover': { ... } }`)\n- Automatically namespace `@`-rule styles (`{ '@media (min-width: 500px)': { ... } }`)\n- Overload CSS properties using arrays (`{ backgroundColor: ['red', 'linear-gradient(to right, red 0%, blue 100%)'] }`)\n- Small and powerful API that works with any ecosystem (~360 SLOC)\n\n### But How?\n\n**Free-Style** generates a hash from the style to use as the class name. This allows duplicate styles to automatically be merged on duplicate hashes. Every style is \"registered\" and assigned to a variable, which gets the most out of linters that will warn on unused variables and features like dead code minification. Styles should usually be created outside of the application run loop (e.g. `render()`) so the CSS string and hashes are only generated once.\n\n### Ways to Use\n\n- [`typestyle`](https://github.com/typestyle/typestyle) - Popular type-safe interface for working with CSS\n- [`react-free-style`](https://github.com/blakeembrey/react-free-style) - React implementation that renders styles on the current page (for universal apps)\n- [`stylin`](https://github.com/ajoslin/stylin) - Simplest abstraction for creating styles, rules, and keyframes, and keeps `\u003cstyle /\u003e` in sync\n- [`ethcss`](https://github.com/ethorz/ethcss) - Library for writing CSS with literal objects\n- **This module!** - Manually create, compose and manipulate style instances\n\n## Usage\n\n```js\nimport { create } from \"free-style\";\n\n// Create a stylesheet instance.\nconst sheet = create();\n\n// Register a new style, returning a class name to use.\nconst backgroundStyle = sheet.registerStyle({\n  backgroundColor: \"red\",\n}); //=\u003e \"f14svl5e\"\n\n// Inject `\u003cstyle\u003e` into the `\u003chead\u003e`.\nconst styleElement = document.createElement(\"style\");\nstyleElement.textContent = sheet.getStyles();\ndocument.head.appendChild(styleElement);\n\n// Render the style by using the class name.\nReact.render(\n  \u003cdiv className={backgroundStyle}\u003eHello world!\u003c/div\u003e,\n  document.body,\n);\n```\n\n### Style\n\n```js\nconst buttonStyle = sheet.registerStyle({\n  $displayName: \"button\",\n  backgroundColor: \"red\",\n  padding: 10,\n});\n\nconsole.log(buttonStyle); //=\u003e \"button_f65pi0b\"\n```\n\n**Tip:** The string returned by `registerStyle` is a unique hash of the content and used as the HTML class name. The `$displayName` is only used during development, and stripped in production (`process.env.NODE_ENV === 'production'`).\n\n#### Overload CSS properties\n\n```js\nStyle.registerStyle({\n  background: [\n    \"red\",\n    \"-moz-linear-gradient(left, red 0%, blue 100%)\",\n    \"-webkit-linear-gradient(left, red 0%, blue 100%)\",\n    \"-o-linear-gradient(left, red 0%, blue 100%)\",\n    \"-ms-linear-gradient(left, red 0%, blue 100%)\",\n    \"linear-gradient(to right, red 0%, blue 100%)\",\n  ],\n}); //=\u003e \"f1n85iiq\"\n```\n\n#### Nested rules\n\n```js\nStyle.registerStyle({\n  color: \"red\",\n  \"@media (min-width: 500px)\": {\n    //=\u003e \"@media (min-width: 500px){.fk9tfor{color:blue}}\"\n    color: \"blue\",\n  },\n}); //=\u003e \"fk9tfor\"\n```\n\n#### Nested selectors\n\n```js\nStyle.registerStyle({\n  color: \"red\",\n  \".classy\": {\n    //=\u003e \".fc1zv17 .classy\"\n    color: \"blue\",\n  },\n}); //=\u003e \"fc1zv17\"\n```\n\n#### Parent selector\n\n```js\nStyle.registerStyle({\n  color: \"red\",\n  \"\u0026:hover\": {\n    //=\u003e \".f1h42yg6:hover\"\n    color: \"blue\",\n  },\n}); //=\u003e \"f1h42yg6\"\n```\n\n**Tip:** The ampersand (`\u0026`) will be replaced by the parent selector at runtime.\n\n#### Use JavaScript\n\n```js\nconst ellipsisStyle = {\n  whiteSpace: \"nowrap\",\n  overflow: \"hidden\",\n  textOverflow: \"ellipsis\",\n};\n\nconst redEllipsisStyle = Style.registerStyle({\n  color: \"red\",\n  ...ellipsisStyle,\n}); //=\u003e \"fvxl8qs\"\n\n// Share rule between styles using computed properties.\nconst mediaQuery = \"@media (min-width: 400px)\";\n\nconst style = Style.registerStyle({\n  backgroundColor: \"red\",\n  [mediaQuery]: {\n    backgroundColor: \"pink\",\n  },\n});\n```\n\n#### Unique style output\n\nSometimes you need to skip the de-duping behavior of `free-style`. Use `$unique` to force separate styles:\n\n```js\nStyle.registerStyle({\n  color: \"blue\",\n  \"\u0026::-webkit-input-placeholder\": {\n    color: `rgba(0, 0, 0, 0)`,\n    $unique: true,\n  },\n  \"\u0026::-moz-placeholder\": {\n    color: `rgba(0, 0, 0, 0)`,\n    $unique: true,\n  },\n  \"\u0026::-ms-input-placeholder\": {\n    color: `rgba(0, 0, 0, 0)`,\n    $unique: true,\n  },\n}); //=\u003e \"f13byakl\"\n\nStyle.getStyles(); //=\u003e \".f13byakl{color:blue}.f13byakl::-webkit-input-placeholder{color:rgba(0, 0, 0, 0)}.f13byakl::-moz-placeholder{color:rgba(0, 0, 0, 0)}.f13byakl::-ms-input-placeholder{color:rgba(0, 0, 0, 0)}\"\n```\n\n### Rules\n\n```js\nconst colorAnimation = Style.registerStyle({\n  $global: true,\n  \"@keyframes \u0026\": {\n    from: { color: \"red\" },\n    to: { color: \"blue\" },\n  },\n}); //=\u003e \"h1j3ughx\"\n\nconst style = Style.registerStyle({\n  animationName: colorAnimation,\n  animationDuration: \"1s\",\n}); //=\u003e \"fibanyf\"\n```\n\n#### Global rules and styles\n\n```js\nStyle.registerStyle({\n  $global: true,\n  \"@font-face\": {\n    fontFamily: '\"Bitstream Vera Serif Bold\"',\n    src: 'url(\"https://mdn.mozillademos.org/files/2468/VeraSeBd.ttf\")',\n  },\n});\n\nStyle.registerStyle({\n  $global: true,\n  \"@media print\": {\n    body: {\n      color: \"red\",\n    },\n  },\n});\n\nStyle.registerStyle({\n  $global: true,\n  body: {\n    margin: 0,\n    padding: 0,\n  },\n});\n\nStyle.registerStyle({\n  $global: true,\n  body: {\n    margin: 0,\n    padding: 0,\n    \"@print\": {\n      color: \"#000\",\n    },\n  },\n  h1: {\n    fontSize: \"2em\",\n  },\n});\n```\n\n### CSS string\n\n```js\nStyle.getStyles(); //=\u003e \".f65pi0b{background-color:red;padding:10px}\"\n```\n\n## TypeScript and ESM\n\nThis package is a [pure ESM package](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) and ships with TypeScript definitions. It cannot be `require`'d or used with CommonJS module resolution in TypeScript.\n\n## Useful libraries\n\n- [`polished`](https://polished.js.org)\n- [`classnames`](https://github.com/JedWatson/classnames)\n- [`color`](https://github.com/MoOx/color)\n- [`style-helper`](https://github.com/blakeembrey/style-helper)\n- [`postcss-js`](https://github.com/postcss/postcss-js)\n- [`inline-style-prefixer`](https://github.com/rofrischmann/inline-style-prefixer)\n- [`insert-css`](https://github.com/substack/insert-css)\n- [`image-url`](https://github.com/ajoslin/image-url)\n- [**Add yours!**](https://github.com/blakeembrey/free-style/issues/new)\n\n## Implementation details\n\n### Debugging\n\nDisplay names will automatically be removed when `process.env.NODE_ENV === \"production\"`.\n\n### Changes\n\nThe only argument to `create()` is a map of change function handlers. All functions are required:\n\n- `add(style: Container\u003cany\u003e, index: number)`\n- `change(style: Container\u003cany\u003e, index: number)`\n- `remove(style: Container\u003cany\u003e, index: number)`\n\nAll styles implement `Container`, so you can call `getStyles()` or `clone()`.\n\n### Merging\n\n`Sheet`, `Style`, and `Rule` have the ability to be merged.\n\n```js\nconst otherSheet = create();\n\nsheet.merge(otherSheet); // Merge the current styles of `otherSheet` into `sheet`.\nsheet.unmerge(otherSheet); // Remove the current styles of `otherSheet` from `sheet`.\n```\n\n### Pre-process styles\n\nIf you plan to re-use styles across `Sheet`s, it will be more efficient to use `compile` once and `register` many times instead of `registerStyle`.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblakeembrey%2Ffree-style","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblakeembrey%2Ffree-style","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblakeembrey%2Ffree-style/lists"}