simplestyle-js 5.5.1-alpha.2 → 6.1.0

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 (99) hide show
  1. package/README.md +169 -306
  2. package/compiler/cli.js +207 -0
  3. package/compiler/collector.js +50 -0
  4. package/compiler/dependencyGraph.js +217 -0
  5. package/compiler/empty.js +1 -0
  6. package/compiler/getCommonRootPath.js +44 -0
  7. package/compiler/interceptor.js +42 -0
  8. package/compiler/mock.js +107 -0
  9. package/compiler/register.js +24 -0
  10. package/dist/browser/index.d.ts +5 -0
  11. package/dist/browser/index.mjs +4 -0
  12. package/dist/makeStyles/createImports.d.ts +4 -0
  13. package/dist/makeStyles/createImports.mjs +25 -0
  14. package/dist/makeStyles/createKeyframes.d.ts +6 -0
  15. package/dist/makeStyles/createKeyframes.mjs +20 -0
  16. package/dist/makeStyles/createRawStyles.d.ts +4 -0
  17. package/dist/makeStyles/createRawStyles.mjs +18 -0
  18. package/dist/makeStyles/createSheet.d.ts +4 -0
  19. package/dist/makeStyles/createSheet.mjs +22 -0
  20. package/dist/makeStyles/createStyles.d.ts +9 -0
  21. package/dist/makeStyles/createStyles.mjs +54 -0
  22. package/dist/makeStyles/execCreateStyles.d.ts +6 -0
  23. package/dist/makeStyles/execCreateStyles.mjs +66 -0
  24. package/dist/makeStyles/flushSheetContents.d.ts +2 -0
  25. package/dist/makeStyles/flushSheetContents.mjs +20 -0
  26. package/dist/makeStyles/generateClassName.d.ts +13 -0
  27. package/dist/makeStyles/generateClassName.mjs +24 -0
  28. package/dist/makeStyles/makeCssFuncsBrowser.d.ts +29 -0
  29. package/dist/makeStyles/makeCssFuncsBrowser.mjs +64 -0
  30. package/dist/makeStyles/types.d.ts +27 -0
  31. package/dist/makeStyles/types.mjs +1 -0
  32. package/dist/makeStyles/utils.d.ts +5 -0
  33. package/dist/makeStyles/utils.mjs +13 -0
  34. package/dist/{cjs/simpleStyleRegistry.d.ts → simpleStyleRegistry.d.ts} +0 -4
  35. package/dist/{esm/simpleStyleRegistry.mjs → simpleStyleRegistry.mjs} +0 -5
  36. package/dist/ssr/index.d.ts +6 -0
  37. package/dist/ssr/index.mjs +4 -0
  38. package/dist/ssr/makeCssFuncsSSR.d.ts +31 -0
  39. package/dist/ssr/makeCssFuncsSSR.mjs +59 -0
  40. package/dist/types.d.ts +4 -0
  41. package/package.json +51 -166
  42. package/dist/cjs/astro/SimpleStyleProvider.astro +0 -16
  43. package/dist/cjs/createStyles.cjs +0 -274
  44. package/dist/cjs/createStyles.d.ts +0 -51
  45. package/dist/cjs/generateClassName.cjs +0 -62
  46. package/dist/cjs/generateClassName.d.ts +0 -3
  47. package/dist/cjs/index.cjs +0 -90
  48. package/dist/cjs/index.d.ts +0 -8
  49. package/dist/cjs/makeStyles.cjs +0 -55
  50. package/dist/cjs/makeStyles.d.ts +0 -42
  51. package/dist/cjs/next/SimpleStyleProvider.cjs +0 -31
  52. package/dist/cjs/next/SimpleStyleProvider.d.ts +0 -11
  53. package/dist/cjs/next/index.cjs +0 -19
  54. package/dist/cjs/next/index.d.ts +0 -2
  55. package/dist/cjs/next/registry.cjs +0 -52
  56. package/dist/cjs/next/registry.d.ts +0 -3
  57. package/dist/cjs/numToAlpha.cjs +0 -14
  58. package/dist/cjs/numToAlpha.d.ts +0 -1
  59. package/dist/cjs/package.json +0 -1
  60. package/dist/cjs/plugins.cjs +0 -25
  61. package/dist/cjs/simpleStyleRegistry.cjs +0 -59
  62. package/dist/cjs/styleCache.cjs +0 -27
  63. package/dist/cjs/styleCache.d.ts +0 -2
  64. package/dist/cjs/types.cjs +0 -4
  65. package/dist/cjs/types.d.ts +0 -9
  66. package/dist/cjs/util/deepEqual.cjs +0 -27
  67. package/dist/cjs/util/deepEqual.d.ts +0 -1
  68. package/dist/cjs/util/index.cjs +0 -18
  69. package/dist/cjs/util/index.d.ts +0 -1
  70. package/dist/esm/astro/SimpleStyleProvider.astro +0 -16
  71. package/dist/esm/createStyles.d.ts +0 -51
  72. package/dist/esm/createStyles.mjs +0 -242
  73. package/dist/esm/generateClassName.d.ts +0 -3
  74. package/dist/esm/generateClassName.mjs +0 -36
  75. package/dist/esm/index.d.ts +0 -8
  76. package/dist/esm/index.mjs +0 -6
  77. package/dist/esm/makeStyles.d.ts +0 -42
  78. package/dist/esm/makeStyles.mjs +0 -51
  79. package/dist/esm/next/SimpleStyleProvider.d.ts +0 -11
  80. package/dist/esm/next/SimpleStyleProvider.mjs +0 -27
  81. package/dist/esm/next/index.d.ts +0 -2
  82. package/dist/esm/next/index.mjs +0 -2
  83. package/dist/esm/next/registry.d.ts +0 -3
  84. package/dist/esm/next/registry.mjs +0 -34
  85. package/dist/esm/numToAlpha.d.ts +0 -1
  86. package/dist/esm/numToAlpha.mjs +0 -4
  87. package/dist/esm/plugins.d.ts +0 -3
  88. package/dist/esm/simpleStyleRegistry.d.ts +0 -37
  89. package/dist/esm/styleCache.d.ts +0 -2
  90. package/dist/esm/styleCache.mjs +0 -9
  91. package/dist/esm/types.d.ts +0 -9
  92. package/dist/esm/util/deepEqual.d.ts +0 -1
  93. package/dist/esm/util/deepEqual.mjs +0 -17
  94. package/dist/esm/util/index.d.ts +0 -1
  95. package/dist/esm/util/index.mjs +0 -1
  96. /package/dist/{esm/package.json → package.json} +0 -0
  97. /package/dist/{cjs/plugins.d.ts → plugins.d.ts} +0 -0
  98. /package/dist/{esm/plugins.mjs → plugins.mjs} +0 -0
  99. /package/dist/{esm/types.mjs → types.mjs} +0 -0
package/README.md CHANGED
@@ -2,26 +2,16 @@
2
2
 
3
3
  An ultra-tiny, neat, easy-to-use CSS-in-JS library with SSR support,
4
4
  tiny bundle size and only *one runtime dependency*.
5
+ Framework agnostic by design — works with React, Vue, Svelte, Next.js, Astro, or no framework at all.
5
6
 
6
7
  `6.48kB` / `2.69kB gzip` ([courtesy of bundlejs.com](https://bundlejs.com/?q=simplestyle-js))
7
8
 
8
- # Simplestyle-js Reference
9
-
10
- A concise guide to the core `simplestyle-js` APIs, how they fit together, and how to use them in browser and server-rendered apps (including Next.js).
11
-
12
9
  ## Table of Contents
13
10
  - [Install](#install)
14
- - [Quick Start](#quick-start)
11
+ - [Quick Start (Browser)](#quick-start-browser)
12
+ - [SSR / Static Extraction (Framework-Agnostic)](#ssr--static-extraction-framework-agnostic)
15
13
  - [API Reference](#api-reference)
16
14
  - [Patterns and Tips](#patterns-and-tips)
17
- - [Creating reusable variables and / or design system-like tokens](#reusable-variables)
18
- - [SSR](#ssr)
19
- - [Next.js](#nextjs)
20
- - [Astro](#astro)
21
- - [SSR steps for most SSR / SSG frameworks](#ssr-steps-for-most-ssr--ssg-frameworks)
22
- - [1. Set your seed, create a SimpleStyleRegistry and your style functions](#1-set-your-seed-create-a-simplestyleregistry-and-your-style-functions)
23
- - [2. Render the generated styles in your HTML](#2-render-the-generated-styles-in-your-html)
24
- - [3. Create your styles and have fun!](#3-create-your-styles-and-have-fun)
25
15
  - [Creating a simplestyle-js plugin](#creating-a-simplestyle-js-plugin)
26
16
  - [Plugin Example (Autoprefixer)](#plugin-example-autoprefixer)
27
17
  - [License](#license)
@@ -50,367 +40,239 @@ pnpm add simplestyle-js
50
40
  yarn add simplestyle-js
51
41
  ```
52
42
 
53
- ## Quick Start
43
+ ## Quick Start (Runtime styles in the Browser)
44
+
45
+ Use the browser entrypoint for runtime CSS injection. This variant creates `<style />` tags in the browser and is the most traditional CSS‑in‑JS experience.
46
+
47
+ ```tsx
48
+ import { makeCssFuncs } from 'simplestyle-js/browser';
49
+
50
+ const { createStyles, createKeyframes, createRawStyles } = makeCssFuncs();
54
51
 
55
- ```jsx
56
- import createStyles from 'simplestyle-js';
52
+ const { keyframe } = createKeyframes('Pulse', () => ({
53
+ '0%': { opacity: 0.6, transform: 'scale(0.98)' },
54
+ '100%': { opacity: 1, transform: 'scale(1)' },
55
+ }));
56
+
57
+ createRawStyles('GlobalReset', () => ({
58
+ '*, *::before, *::after': { boxSizing: 'border-box' },
59
+ body: { margin: 0, fontFamily: 'system-ui, sans-serif' },
60
+ }));
57
61
 
58
62
  const { classes } = createStyles('Button', () => ({
59
63
  root: {
60
- '&:hover': { backgroundColor: '#2d6cdf' },
61
- '@media (max-width: 768px)': { padding: '10px 12px' },
62
64
  backgroundColor: '#1f4aa8',
63
65
  borderRadius: 6,
64
66
  color: '#fff',
65
67
  padding: '12px 16px',
68
+ animation: `${keyframe} 900ms ease-in-out infinite alternate`,
69
+ '&:hover': { backgroundColor: '#2d6cdf' },
70
+ '@media (max-width: 768px)': { padding: '10px 12px' },
66
71
  },
67
72
  }));
68
73
 
69
74
  document.querySelector('button')?.classList.add(classes.root);
70
-
71
- // or, in a React / JSX-like component
72
- const Button = (props) => <button {...props} className={classes.root}>Awesome button</button>
73
75
  ```
74
76
 
75
- Rules support nested selectors via `&`, media queries, and `$className` back-references to other generated classes.
76
-
77
- ## API Reference
77
+ Rules support nested selectors via `&`, media queries, and `$className` backreferences to other generated classes.
78
78
 
79
- - `createStyles(ruleId, rules, options?)`
80
- - Builds a set of class names and CSS from a rules object. Returns `{ classes, stylesheet, updateSheet }`.
81
- - `options.flush` (default `true`): injects a `<style>` tag into `document.head`.
82
- - `options.insertBefore` / `insertAfter`: choose where the `<style>` tag is placed when flushing.
83
- - `options.registry`: provide a `SimpleStyleRegistry` instance to **collect** CSS instead of touching the DOM (ideal for SSR).
84
- - `updateSheet(updatedRules)` merges rules and updates the existing sheet (works when `flush` is `true` or a `registry` is provided). Returns `{ classes, stylesheet } | null`.
85
- - Example:
86
- ```ts
87
- const { classes, stylesheet } = createStyles('Nav', () => ({
88
- wrapper: { display: 'flex', gap: 12 },
89
- link: {
90
- '&:hover': { textDecoration: 'underline' },
91
- },
92
- '@media (max-width: 600px)': {
93
- wrapper: { flexDirection: 'column' },
94
- },
95
- }), { flush: false }); // do not write to the DOM automatically
96
- ```
97
-
98
- - `imports(ruleId, importRulesFnc, options?)`
99
- - Allow you to define one or more `@import()` rules for importing or referencing external stylesheets. **Note**: These imports will not be transformed or attempted to have their contents imported.
100
-
101
- - `keyframes(ruleId, framesFnc, options?)`
102
- - Generates a unique animation name and accompanying `@keyframes` CSS.
103
- - Returns `{ keyframe: string; stylesheet: string; }`. Respects `flush` and `insertBefore/After` options.
104
-
105
- - `rawStyles(ruleId, rulesFnc, options?)`
106
- - Writes rules without generating new class names. Keys must already be selectors (e.g., `html`, `body *`, `.app`).
107
- - Good for global resets or theme primitives. Respects `flush` and `registry`.
108
-
109
- - `makeCssFuncs({ registry?, variables? })`
110
- - Returns `createStyles`, `keyframes` and `rawStyles` functions for you to use that are bound to an optional `SimpleStyleRegistry` and an optional `variables` object.
111
- - Use this variant if you want to bind all of the CSS functions to a set of styling tokens / variables that you want accessible and available wherever you write your CSS, complete with IDE intellisense.
112
- - Use this as a convenience if you don't want to manually wire up each CSS function (listed below) to your registry.
113
-
114
- - `makeCreateStyles(registry)`
115
- - Convenience wrapper that returns a `createStyles` instance pre-bound to a `SimpleStyleRegistry`. Use this when you want every call to accumulate in a registry (especially useful for SSR / Server-side rendering).
116
-
117
- - `makeRawStyles(registry)`
118
- - Returns a `rawStyles` helper preconfigured with the provided registry; calls will auto-add to that registry instead of touching the DOM (same motivation as `makeCreateStyles` for SSR motivations).
119
-
120
- - `makeKeyframes(registry)`
121
- - Returns a `keyframes` helper preconfigured with the provided registry; calls will auto-add to that registry instead of touching the DOM (same motivation as `makeCreateStyles` for SSR motivations).
122
-
123
- - `setSeed(seed: number | null)`
124
- - Controls the deterministic suffix used for generated class names. Setting the same seed in server and client renders keeps class names stable for hydration. Pass `null` to reset to `Date.now()`.
125
-
126
- - `registerPosthook(fn: (sheet: string) => string)`
127
- - Adds a transform that runs after CSS strings are generated but before they are flushed or stored. Use for autoprefixing, minification, or custom transforms. Hooks run in registration order.
128
-
129
- - Types
130
- - `SimpleStyleRules`: `{ [selectorOrKey: string]: Properties | SimpleStyleRules }` (recursive rule tree).
131
- - `CreateStylesOptions`: shape of the options described above.
132
- - `PosthookPlugin`: signature for `registerPosthook`.
79
+ ## SSR / Static Extraction (Framework‑Agnostic)
133
80
 
134
- ## Patterns and Tips
81
+ The SSR workflow requires usage of the built in `ssjs` CLI tool.
82
+ This works by scanning your source files and generating a single `.css` file, containing all of the collected styles.
83
+ Your source code remains untouched and does not require any transformation or transpilation.
84
+ To leverage this, you **must** use the SSR entrypoint and place all styles in files named with the following format:
135
85
 
136
- - **Nested selectors**: `&` is replaced with the parent selector. Comma-separated selectors are supported (e.g., `'&:hover, &:focus'`).
137
- - **Back-references**: Use `$otherRule` to reference another generated class in the same `createStyles` call.
138
- - **NOTE:** The `$otherRule` needs to have been declared above where you're trying to use it in a descendant selector.
139
- - **Media queries**: Top-level `@media` keys contain further rule objects.
140
- - **DOM placement**: `insertBefore` and `insertAfter` let you control the exact placement for where `<style />` tags will be rendered (does not apply to SSR / Server-side rendering).br
141
- - **Updating styles**: `updateSheet` merges the new rules and updates the existing `<style>` tag (or registry entry, if you're not letting `simplestyle-js` flush to the DOM automatically for you). It also returns `{ classes, stylesheet }` so you can re-use class names if needed.
86
+ ```
87
+ *.styles.{js|cjs|mjs|ts|mts|cts|jsx|tsx}
88
+ ```
142
89
 
143
- ## Reusable Variables
90
+ Run the `ssjs` CLI to compile a single CSS file. This works with **Next.js, Astro, or any framework** (SSR or SSG) because the output is just plain CSS.
144
91
 
145
- SimpleStyle provides an easy way to "bind" all of the CSS functions it exports to an object that contains your tokens, variables, etc.
146
- To do this, you would use the same API that's used to bind to a specific sheet registry, but specify the `variables` option:
92
+ ### 1) Write styles in `*.styles.*` files
147
93
 
148
- ```typescript
149
- import { makeCssFuncs, SimpleStyleRegistry } from "simplestyle-js";
94
+ ```ts
95
+ // src/components/button.styles.ts
96
+ import { makeCssFuncs } from 'simplestyle-js/ssr';
150
97
 
98
+ const { createStyles } = makeCssFuncs();
151
99
 
152
- export const { createStyles, keyframes } = makeCssFuncs({
153
- variables: {
154
- background: {
155
- primary: '#f1f1f3',
156
- secondary: '#555',
157
- },
158
- },
159
- });
160
-
161
- const { classes } = createStyles('my-component', vars => ({
162
- card: {
163
- // use all of your variables here.
164
- // your IDE should provide code assistance to you
165
- // to inform you of what variables are available
166
- backgroundColor: vars.background.secondary,
100
+ export const { classes } = createStyles('Button', () => ({
101
+ root: {
102
+ backgroundColor: '#1f4aa8',
103
+ borderRadius: 6,
104
+ color: '#fff',
105
+ padding: '12px 16px',
106
+ '&:hover': { backgroundColor: '#2d6cdf' },
167
107
  },
168
108
  }));
169
109
  ```
170
110
 
171
- ## SSR
111
+ ```tsx
112
+ // src/components/Button.tsx
113
+ import { classes } from './button.styles';
172
114
 
173
- ### Next.js
115
+ export function Button() {
116
+ return <button className={classes.root}>Click me</button>;
117
+ }
118
+ ```
174
119
 
175
- Create your scoped CSS functions using the per-request Next.js registry, then wrap the `SimpleStyleProvider` around your `layout` file. This ensures styles are collected during server rendering and injected into the `<head />` during streaming.
120
+ ### 2) Compile with `ssjs`
176
121
 
177
- ```typescript
178
- // src/styleRegistry.ts
122
+ Define **accurate `--entrypoints`** CLI flags for your code so the compiler can follow your import graph and discover all of your styles.
123
+ The resulting CSS is written in the same order as your source code / import tree.
179
124
 
180
- import { makeCssFuncs, setSeed } from "simplestyle-js";
181
- import { getSimpleStyleRegistry } from "simplestyle-js/next";
125
+ ```bash
126
+ bun ssjs --entrypoints src/app.tsx src/pages/**/*.tsx --outfile public/my-styles.css
127
+ ```
128
+ ```bash
129
+ npx ssjs --entrypoints src/app.tsx src/pages/**/*.tsx --outfile public/my-styles.css
130
+ ```
131
+ ```bash
132
+ pnpm ssjs --entrypoints src/app.tsx src/pages/**/*.tsx --outfile public/my-styles.css
133
+ ```
134
+ ```bash
135
+ yarn ssjs --entrypoints src/app.tsx src/pages/**/*.tsx --outfile public/my-styles.css
136
+ ```
182
137
 
183
- // ensures deterministic creation of CSS classnames
184
- setSeed(11223344);
138
+ Optional watch mode:
185
139
 
186
- export const { createStyles, imports, keyframes, rawStyles } = makeCssFuncs(() => ({
187
- registry: getSimpleStyleRegistry(),
188
- }));
140
+ ```bash
141
+ npx ssjs --entrypoints src/app.tsx src/pages/**/*.tsx --outfile public/my-styles.css --watch
189
142
  ```
190
143
 
191
- ```tsx
192
- // src/app/layout.tsx
193
- import type { Metadata } from "next";
194
- import { SimpleStyleProvider } from "simplestyle-js/next";
195
- import { createStyles } from "./styleRegistry";
196
-
197
- // start writing CSS!
198
- const { classes } = createStyles('RootLayoutStyles', () => ({
199
- rootLayout: {
200
- backgroundColor: 'pink',
201
- padding: '1rem',
202
- },
203
- }));
144
+ ### 3) Include the generated CSS
204
145
 
205
- export default function RootLayout({
206
- children,
207
- }: Readonly<{
208
- children: React.ReactNode;
209
- }>) {
210
- return (
211
- <html lang="en">
212
- <body className={classes.rootLayout}>
213
- <SimpleStyleProvider>
214
- {children}
215
- </SimpleStyleProvider>
216
- </body>
217
- </html>
218
- );
219
- }
146
+ The output file is plain CSS. Include it the same way you would any stylesheet:
147
+
148
+ ```html
149
+ <!-- SSR/SSG: add to your HTML head -->
150
+ <link rel="stylesheet" href="/my-styles.css" />
220
151
  ```
221
152
 
222
- Check out this [Code Sandbox w/Next.js integration to see how it works](https://codesandbox.io/p/devbox/t3smf4).
153
+ Or import it via your framework’s entry:
154
+
155
+ ```ts
156
+ // e.g. Next.js or Astro entry files, or any UI application that uses a bundler
157
+ import '../public/my-styles.css';
158
+ ```
223
159
 
224
- If you're building a component library that needs to work in Next.js with SSR, use the same `getSimpleStyleRegistry()` callback inside that library's `makeCssFuncs` call so it participates in the app's per-request registry. On the client, `getSimpleStyleRegistry()` returns `null`, so styles fall back to runtime injection.
160
+ ## API Reference
225
161
 
162
+ **Important:** always call `makeCssFuncs()` from the correct entrypoint:
226
163
 
227
- ### Astro
164
+ - Browser runtime: `import { makeCssFuncs } from 'simplestyle-js/browser'`
165
+ - SSR: `import { makeCssFuncs } from 'simplestyle-js/ssr'`
228
166
 
229
- Due to how Astro processes its front matter sections at build time, and how this also affects local development, each `.astro` file that has its own CSS rules will also need to have its own `SimpleStyleRegistry` instance.
230
- The overall developer experience is similar to Next.js, but requires a pinch more boilerplate.
167
+ ### `makeCssFuncs({ variables? }?)`
231
168
 
232
- ```typescript
233
- // src/styleRegistry.ts
169
+ Creates the CSS helpers and optionally binds your design tokens for typed access.
234
170
 
235
- import { makeCssFuncs, setSeed } from "simplestyle-js";
171
+ ```ts
172
+ import { makeCssFuncs } from 'simplestyle-js/browser'; // or import the SSR variant from 'simplestyle-js/ssr';
236
173
 
237
- // ensures deterministic creation of CSS classnames
238
- setSeed(11223344);
174
+ const { createStyles } = makeCssFuncs({
175
+ variables: {
176
+ colors: { brand: '#1f4aa8' },
177
+ },
178
+ });
239
179
 
240
- export { createStyles, imports, keyframes, rawStyles } = makeCssFuncs({});
180
+ const { classes } = createStyles('Card', (vars) => ({
181
+ root: { backgroundColor: vars.colors.brand },
182
+ }));
241
183
  ```
242
184
 
243
- ```astro
244
- ---
245
- import { SimpleStyleRegistry } from "simplestyle-js";
246
- import SimpleStyleProvider from "simplestyle-js/astro/SimpleStyleProvider";
247
-
248
- import {
249
- createStyles,
250
- keyframes,
251
- rawStyles,
252
- } from "../styleRegistry";
185
+ ### `createStyles(ruleId, rulesFn, options?)`
253
186
 
254
- const registry = new SimpleStyleRegistry();
187
+ Builds class names + CSS.
188
+ Returns `{ classes, stylesheet, updateSheet }`.
189
+ Use the returned `classes` directly in your component code / HTML.
255
190
 
256
- rawStyles("basic-css-reset", () => ({
257
- "*": {
258
- boxSizing: "border-box",
259
- },
260
- "body, html": {
261
- fontFamily: "sans-serif",
262
- fontSize: "16px",
263
- padding: 0,
264
- },
265
- }), {
266
- // provide the registry used for this `.astro` file here
267
- registry,
268
- });
191
+ ```ts
192
+ const { classes } = createStyles('Nav', () => ({
193
+ wrapper: { display: 'flex', gap: 12 },
194
+ link: { '&:hover': { textDecoration: 'underline' } },
195
+ '@media (max-width: 600px)': { wrapper: { flexDirection: 'column' } },
196
+ }));
197
+ ```
269
198
 
270
- // make changes to me and I will hot reload!
271
- const { keyframe } = keyframes("HomePage", () => ({
272
- "0%": {
273
- backgroundColor: "#cc2222cc",
274
- },
275
- "33%": {
276
- backgroundColor: "#22cc22cc",
277
- },
278
- "66%": {
279
- backgroundColor: "#2222cccc",
280
- },
281
- "100%": {
282
- backgroundColor: "#cc2222cc",
283
- },
284
- }), {
285
- // provide the registry used for this `.astro` file here
286
- registry,
287
- });
199
+ Back‑reference example (use `$otherRule` to reference another generated class):
288
200
 
289
- const { classes } = createStyles("HomePage", () => ({
290
- background: {
291
- alignItems: "center",
292
- animation: `${keyframe} 5s linear infinite`,
293
- display: "flex",
294
- flexFlow: "column",
295
- height: "90vh",
296
- justifyContent: "center",
297
- margin: "0 auto",
298
- width: "90vw",
299
- },
300
- content: {
301
- backgroundColor: "#00000033",
302
- borderRadius: "4px",
303
- color: "white",
304
- padding: "1rem",
201
+ ```ts
202
+ const { classes } = createStyles('Card', () => ({
203
+ title: { fontWeight: 700, marginBottom: 8 },
204
+ root: {
205
+ padding: 16,
206
+ borderRadius: 8,
207
+ backgroundColor: '#f6f7fb',
208
+ '& $title': { color: '#1f4aa8' },
305
209
  },
306
- }), {
307
- // provide the registry used for this `.astro` file here
308
- registry,
309
- });
310
- ---
311
- <!-- wrap your astro content here with the provider and give it the registry you created in your front matter -->
312
- <SimpleStyleProvider registry={registry}>
313
- <div class={classes.background}>
314
- <div class={classes.content}>
315
- <h1>Astro</h1>
316
- <p>
317
- Checkout the CSS class and animation applied to the body, which is
318
- making my colors changes.
319
- </p>
320
- <p>Feel free to edit me and I'll hot reload!</p>
321
- </div>
322
- </div>
323
- </SimpleStyleProvider>
210
+ }));
324
211
  ```
325
212
 
326
- Check out this [Code Sandbox w/Astro integration to see how it works](https://codesandbox.io/p/devbox/mq9twt).
327
-
328
- **General SSR Concepts**
213
+ ### `createKeyframes(ruleId, framesFn, options?)`
329
214
 
330
- `simplestyle-js` is intentionally unopinionated, especially when it comes to deep integrations with various frameworks. This also applies to SSR / Server-side rendering.
331
- The core APIs needed to make this work are:
215
+ Generates a unique animation name and `@keyframes` CSS. Returns `{ keyframe, stylesheet }`.
332
216
 
333
- - `new SimpleStyleRegistry()` - creates a new StyleSheet registry where all of your styles will be accumulated
334
- - `setSeed(number)` - ensures that classNames are deterministically computed and will be the same on the server and when they're rehydrated on the client
335
- - `makeCssFuncs({ registry })` - returns `createStyles()`, `keyframes()` and `rawStyles()` functions that are locked to your StyleSheet registry
217
+ ```ts
218
+ const { keyframe } = createKeyframes('FadeIn', () => ({
219
+ '0%': { opacity: 0, transform: 'translateY(6px)' },
220
+ '100%': { opacity: 1, transform: 'translateY(0px)' },
221
+ }));
336
222
 
337
- ### SSR steps for most SSR / SSG frameworks
223
+ const { classes } = createStyles('Notice', () => ({
224
+ root: {
225
+ animation: `${keyframe} 320ms ease-out`,
226
+ },
227
+ }));
228
+ ```
338
229
 
339
- #### 1. Set your seed, create a SimpleStyleRegistry and your style functions
230
+ ### `createRawStyles(ruleId, rulesFn, options?)`
340
231
 
341
- **Note**: This file can be located anywhere in your repository.
342
- For demonstration purposes, we'll locate this at our `src/` root, and name it `styleLib.js`
232
+ Writes rules without generating class names. Keys must be selectors (`html`, `body *`, `.app`).
343
233
 
344
- ```javascript
345
- import { makeCssFuncs, setSeed, SimpleStyleRegistry } from "simplestyle-js";
234
+ ```ts
235
+ createRawStyles('GlobalReset', () => ({
236
+ '*, *::before, *::after': { boxSizing: 'border-box' },
237
+ 'html, body': {
238
+ margin: 0,
239
+ padding: 0,
240
+ fontFamily: 'system-ui, sans-serif',
241
+ lineHeight: 1.4,
242
+ backgroundColor: '#fff',
243
+ color: '#111',
244
+ },
245
+ img: { maxWidth: '100%', display: 'block' },
246
+ button: { font: 'inherit' },
247
+ }));
248
+ ```
346
249
 
347
- // set the className generation seed to ensure classNames are computed consistently
348
- // between the client and the server.
349
- // the number you use is arbitrary.
350
- // set it higher to have most characters injected in your generated class names
351
- setSeed(1);
250
+ ### `createImports(ruleId, rulesFn, options?)`
352
251
 
353
- // create the registry to hold all of the styles on the server
354
- export const StyleRegistry = new SimpleStyleRegistry();
252
+ Creates `@import` rules. The array items must already be valid `@import` strings.
355
253
 
356
- // export the style functions that will be locked to your registry
357
- export const { createStyles, imports, keyframes, rawStyles } = makeCssFuncs({ registry: })
254
+ ```ts
255
+ createImports('Imports', () => [
256
+ '@import "https://unpkg.com/normalize.css/normalize.css"',
257
+ ]);
358
258
  ```
359
259
 
360
- #### 2. Render the generated styles in your HTML
361
-
362
- **Note**: If you use Next.js, you would do this in your `layout.jsx` or `layout.tsx` file.
363
- Additionally, if you're not using React or any other JSX-inspired framework, you can use
364
- `StyleRegistry.getHTML()` to return an HTML string with all of the `<style />` tags you need,
365
- or `StyleRegistry.getCSS()` to just return a single, concatenated CSS string.
366
-
367
- ```jsx
368
- import { StyleRegistry } from '../styleLib.js';
369
-
370
- export default function Layout({ children }) {
371
- return (
372
- <body lang="en">
373
- {/* render your <style /> tags and set the IDs on them */}
374
- {StyleRegistry.getRulesById().map(([id, css]) => (
375
- <style id={id} key={id}>
376
- {css}
377
- </style>
378
- ))}
379
- {children}
380
- </body>
381
- );
382
- }
383
- ```
260
+ ### `registerPosthook(fn: (sheet: string) => string)`
384
261
 
385
- #### 3. Create your styles and have fun!
262
+ Registers a transform that runs after CSS strings are generated, but before they’re flushed or written.
386
263
 
387
- ```jsx
388
- import { createStyles } from '../styleLib.js';
264
+ ### Types
389
265
 
390
- // create your styles
391
- const { classes } = createStyles('my-component', () => ({
392
- awesome: {
393
- backgroundColor: 'purple',
394
- fontSize: '2rem',
395
- padding: '2rem',
266
+ - `SimpleStyleRules`: `{ [selectorOrKey: string]: Properties | SimpleStyleRules }`
267
+ - `CreateStylesOptions`: options for flushing/placement in the browser runtime.
268
+ - `PosthookPlugin`: signature for `registerPosthook`.
396
269
 
397
- '& > span': {
398
- fontStyle: 'italic',
399
- fontWeight: 'bold',
400
- textDecoration: 'underline',
401
- },
402
- },
403
- }));
270
+ ## Patterns and Tips
404
271
 
405
- export function MyCoolComponent() {
406
- // use your styles here!
407
- return (
408
- <div className={classes.awesome}>
409
- This is super <span>cool.</span>
410
- </div>
411
- );
412
- }
413
- ```
272
+ - **Nested selectors**: `&` is replaced with the parent selector. Comma‑separated selectors are supported (e.g., `'&:hover, &:focus'`).
273
+ - **Back‑references**: Use `$otherRule` to reference another generated class in the same `createStyles` call (the referenced rule should appear earlier in the object).
274
+ - **Media queries**: Top‑level `@media` keys contain further rule objects.
275
+ - **Updating styles**: `updateSheet` merges new rules and updates the existing `<style>` tag (browser) or returns an updated sheet string (SSR extraction).
414
276
 
415
277
  ## Creating a simplestyle-js plugin
416
278
 
@@ -421,12 +283,13 @@ Do this if you want to integrate with `postcss`, `autoprefixer`, or any other CS
421
283
  ```ts
422
284
  import autoprefixer from 'autoprefixer';
423
285
  import postcss from 'postcss';
424
- import { registerPosthook } from 'simplestyle-js';
286
+ import { registerPosthook } from 'simplestyle-js/browser';
425
287
 
426
288
  registerPosthook(css => postcss([autoprefixer]).process(css, { from: undefined }).css);
427
289
  ```
428
290
 
429
- Any future `createStyles`, `rawStyles`, or `keyframes` calls will run through the posthook chain.
291
+ Any future `createStyles`, `createRawStyles`, or `createKeyframes` calls will run through the posthook chain.
292
+ You can use the same API from `simplestyle-js/ssr` if you want the transform applied to extracted CSS as well.
430
293
 
431
294
  ## License
432
295
  [MIT](https://en.wikipedia.org/wiki/MIT_License)