next-style 1.1.4 → 1.1.6

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,56 +1,46 @@
1
- # next-style
1
+ # NextStyle
2
2
 
3
- **next-style** is a lightweight runtime CSS-in-JS engine designed for React, Next.js, and Bun.
3
+ A lightweight **runtime CSS-in-JS engine** for React with deterministic class names, nested pseudo selectors, media queries, global styles, keyframes, and font-face support.
4
4
 
5
- It is intentionally designed to be **page-scoped and component-scoped**, ensuring predictable
6
- style isolation with zero global leakage between pages or routes.
7
-
8
- The library is framework-agnostic at its core and does not depend on React internally.
5
+ Designed for **page-scoped and component-scoped usage** without build-time tooling.
9
6
 
10
7
  ---
11
8
 
12
- ## Core Design Principles
13
-
14
- - Styles are scoped to a **single page or component**
15
- - No global singleton style registry
16
- - No cross-page or cross-route CSS leakage
17
- - Each page owns its own styles
18
- - Explicit style injection via a `<style>` tag
19
- - No implicit DOM side effects
9
+ ## Package Information
20
10
 
21
- Because of this design:
22
- - `new NextStyle()` must be created inside the page or component scope
23
- - Styles must be injected manually using `ns.StyleText`
11
+ - **Name:** next-style
12
+ - **Version:** 1.1.5
13
+ - **License:** MIT
14
+ - **Author:** kingslimes
15
+ https://github.com/kingslimes
16
+ - **Repository:**
17
+ https://github.com/kingslimes/next-style
18
+ - **Issue Tracker:**
19
+ https://github.com/kingslimes/next-style/issues
24
20
 
25
21
  ---
26
22
 
27
23
  ## Features
28
24
 
29
- - Object-based styling with strong TypeScript support
30
- - Deterministic hashing (same styles always produce the same class name)
31
- - Nested pseudo selectors (`_hover`, `_focus`, `_active`)
32
- - Built-in responsive media queries
33
- - Page-scoped global styles
25
+ - Object-based styling (TypeScript friendly)
26
+ - Deterministic class names (same style same class)
27
+ - Pseudo selectors (`:hover`, `:focus`, `:active`)
28
+ - Responsive media queries (`sm` → `xxl`)
29
+ - Global styles
34
30
  - `@keyframes` support
35
31
  - `@font-face` support
36
- - PostCSS + Autoprefixer integration
37
- - Automatic rule deduplication (per instance)
38
- - Single `<style>` injection per page or component
39
- - No side effects (`sideEffects: false`)
32
+ - Built-in PostCSS + Autoprefixer
33
+ - Zero DOM dependency
34
+ - Tree-shakeable (`sideEffects: false`)
35
+ - Copy–paste friendly API
40
36
 
41
37
  ---
42
38
 
43
39
  ## Installation
44
40
 
45
- ### npm
46
-
47
- ```sh
41
+ ``` bash
48
42
  npm install next-style
49
- ```
50
-
51
- ### Bun
52
-
53
- ```sh
43
+ # or
54
44
  bun add next-style
55
45
  ```
56
46
 
@@ -58,243 +48,482 @@ bun add next-style
58
48
 
59
49
  ## Peer Dependencies
60
50
 
61
- For most **Next.js applications**, you **do not need to install these manually**.
51
+ NextStyle relies on the following peer dependencies:
62
52
 
63
- - **React** is already included with Next.js
64
- - **PostCSS** and **Autoprefixer** are bundled and used internally by Next.js
53
+ ``` txt
54
+ react >= 18
55
+ postcss ^8
56
+ autoprefixer ^10
57
+ ```
65
58
 
66
- This section mainly applies if you are using **next-style outside of Next.js**, such as:
67
- - Custom React setups
68
- - Bun + React
69
- - Vite or other non-Next runtimes
59
+ Make sure they are installed in your project.
60
+
61
+ ---
70
62
 
71
- If required, install them manually:
63
+ ## Recommended Usage Pattern (Scoped)
72
64
 
73
- ```sh
74
- npm install react postcss autoprefixer
65
+ The **recommended and official pattern** is to scope styles per page or per component using destructuring.
66
+
67
+ ``` ts
68
+ const { css, StyleProvider } = new NextStyle("home")
75
69
  ```
76
70
 
77
- ---
71
+ Why this works well:
72
+ - Clear scope ownership
73
+ - No global side effects
74
+ - Easy to copy and reuse
75
+ - Matches React’s mental model
78
76
 
79
- ## Basic Usage (Page Scoped)
77
+ ---
80
78
 
81
- Create a `NextStyle` instance **inside the page or component**.
82
- You may optionally provide a **custom prefix** to control generated class names.
79
+ ## Basic Example (Page Scoped)
83
80
 
84
- ```ts
81
+ ``` tsx
85
82
  import { NextStyle } from "next-style"
86
83
 
87
- export default function Page() {
88
- const ns = new NextStyle("home")
89
- const btn = ns.css({
90
- padding: "8px 16px",
91
- backgroundColor: "black",
92
- color: "white",
93
- borderRadius: "6px"
84
+ export default function HomePage() {
85
+ const { css, StyleProvider } = new NextStyle("home")
86
+
87
+ const title = css({
88
+ fontSize: "32px",
89
+ fontWeight: 700,
90
+ marginBottom: "16px"
94
91
  })
92
+
93
+ const button = css({
94
+ padding: "10px 20px",
95
+ borderRadius: "8px",
96
+ backgroundColor: "#2563eb",
97
+ color: "#fff",
98
+
99
+ _hover: {
100
+ backgroundColor: "#1d4ed8"
101
+ }
102
+ })
103
+
95
104
  return (
96
105
  <>
97
- <style>{ ns.StyleText }</style>
98
- <button className={ btn }>Click me</button>
106
+ <StyleProvider />
107
+ <h1 className={title}>Home</h1>
108
+ <button className={button}>Click me</button>
99
109
  </>
100
110
  )
101
111
  }
102
112
  ```
103
113
 
104
- Generated class names will look like:
114
+ ---
105
115
 
106
- ```txt
107
- home_ab12cd3
116
+ ## Styling API
117
+
118
+ ### `css(style): string`
119
+
120
+ Creates a class name from a style object.
121
+
122
+ ``` ts
123
+ const className = css({
124
+ color: "red",
125
+ fontSize: "16px"
126
+ })
108
127
  ```
109
128
 
110
- Notes:
111
- - The prefix is optional
112
- - If omitted, a default prefix is used
113
- - Prefixes help identify styles per page or component
114
- - Each page or component should create its own `NextStyle` instance
129
+ - Automatically converts camelCase → kebab-case
130
+ - Deduplicates styles using hashing
131
+ - Returns a stable class name
115
132
 
116
133
  ---
117
134
 
118
135
  ## Pseudo Selectors
119
136
 
120
- Pseudo selectors are defined using keys prefixed with `_`.
137
+ Supported pseudo keys:
138
+
139
+ | Key | CSS Output |
140
+ |----|-----------|
141
+ | `_hover` | `:hover` |
142
+ | `_focus` | `:focus` |
143
+ | `_active` | `:active` |
121
144
 
122
- ```ts
123
- const card = ns.css({
124
- backgroundColor: "#fff",
125
- transition: "0.2s ease",
145
+ Example:
146
+
147
+ ``` ts
148
+ css({
149
+ color: "black",
126
150
  _hover: {
127
- backgroundColor: "#f5f5f5"
128
- },
129
- _active: {
130
- transform: "scale(0.98)"
151
+ color: "red"
131
152
  }
132
153
  })
133
154
  ```
134
155
 
135
- Supported pseudo selectors:
136
- - `_hover`
137
- - `_focus`
138
- - `_active`
156
+ ---
157
+
158
+ ## Relation Selector API
159
+
160
+ `next-style` provides a **relation-based selector API** that allows you to define styles based on the state of one element affecting another element, without manually writing complex CSS selectors.
161
+
162
+ This API is designed to be:
163
+ - Declarative and readable
164
+ - Type-safe (no string selectors)
165
+ - Fully compatible with runtime CSS-in-JS
139
166
 
140
167
  ---
141
168
 
142
- ## Responsive Styles (Media Queries)
169
+ ### Basic Usage
143
170
 
144
- Built-in breakpoints:
171
+ ``` ts
172
+ const { css, when } = new NextStyle()
173
+
174
+ const container = css({})
175
+ const button = css({})
176
+
177
+ when(container)
178
+ .hover()
179
+ .adjacent(button, {
180
+ backgroundColor: "red"
181
+ })
182
+ ```
183
+ Equivalent CSS:
145
184
 
146
- - `_sm` → min-width: 640px
147
- - `_md` min-width: 768px
148
- - `_lg` → min-width: 1024px
149
- - `_xl` → min-width: 1280px
150
- - `_xxl` → min-width: 1536px
185
+ ``` css
186
+ .container:hover + .button {
187
+ background-color: red;
188
+ }
189
+ ```
190
+
191
+ ---
151
192
 
152
- ```ts
153
- const box = ns.css({
154
- width: 100,
193
+ ## Supported States
194
+
195
+ You can define relationships based on the following pseudo states:
196
+
197
+ - `hover()` → `:hover`
198
+ - `focus()` → `:focus`
199
+ - `active()` → `:active`
200
+
201
+ Example:
202
+
203
+ ``` ts
204
+ when(input)
205
+ .focus()
206
+ .sibling(label, {
207
+ color: "blue"
208
+ })
209
+ ```
210
+ Equivalent CSS:
211
+
212
+ ``` css
213
+ input:focus ~ label {
214
+ color: blue;
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Supported Relationships
221
+
222
+ ### Adjacent Sibling (`+`)
223
+
224
+ Applies styles to the **immediately following sibling**.
225
+
226
+ ``` ts
227
+ when(div)
228
+ .hover()
229
+ .adjacent(p, {
230
+ color: "red"
231
+ })
232
+ ```
233
+ CSS equivalent:
234
+
235
+ ``` css
236
+ div:hover + p {
237
+ color: red;
238
+ }
239
+ ```
240
+
241
+ ---
242
+
243
+ ### General Sibling (`~`)
244
+
245
+ Applies styles to **all following siblings**.
246
+
247
+ ``` ts
248
+ when(div)
249
+ .hover()
250
+ .sibling(p, {
251
+ color: "red"
252
+ })
253
+ ```
254
+ CSS equivalent:
255
+
256
+ ``` css
257
+ div:hover ~ p {
258
+ color: red;
259
+ }
260
+ ```
261
+
262
+ ---
263
+
264
+ ### Child (`>`)
265
+
266
+ Applies styles to **direct children only**.
267
+
268
+ ``` ts
269
+ when(card)
270
+ .hover()
271
+ .child(icon, {
272
+ transform: "scale(1.1)"
273
+ })
274
+ ```
275
+ CSS equivalent:
276
+
277
+ ``` css
278
+ card:hover > icon {
279
+ transform: scale(1.1);
280
+ }
281
+ ```
282
+
283
+ ---
284
+
285
+ ### Descendant (space)
286
+
287
+ Applies styles to **any nested element**.
288
+
289
+ ``` ts
290
+ when(menu)
291
+ .hover()
292
+ .descendant(item, {
293
+ backgroundColor: "#eee"
294
+ })
295
+ ```
296
+ CSS equivalent:
297
+
298
+ ``` css
299
+ menu:hover item {
300
+ background-color: #eee;
301
+ }
302
+ ```
303
+
304
+ ---
305
+
306
+ ## Why Use `when()` Instead of `global()`?
307
+
308
+ While `global()` allows full control over raw selectors, `when()` provides:
309
+
310
+ - Clear intent and better readability
311
+ - No need to manually concatenate class names
312
+ - Safer refactoring (class tokens, not strings)
313
+ - IDE autocomplete and JSDoc support
314
+
315
+ Comparison:
316
+
317
+ ``` ts
318
+ // global selector
319
+ global(`.${a}:hover + .${b}`, { color: "red" })
320
+
321
+ // relation API
322
+ when(a).hover().adjacent(b, { color: "red" })
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Notes
328
+
329
+ - `when()` works with class names generated by `css()`
330
+ - Relation rules are injected via the same internal pipeline as `global()`
331
+ - Media queries and nested styles are fully supported inside relation styles
332
+
333
+ ---
334
+
335
+ ## Example With Media Query
336
+
337
+ ``` ts
338
+ when(container)
339
+ .hover()
340
+ .sibling(text, {
341
+ color: "red",
155
342
  _md: {
156
- width: 200
157
- },
343
+ color: "blue"
344
+ }
345
+ })
346
+ ```
347
+
348
+ ---
349
+
350
+ This API is intentionally minimal and composable, allowing you to express complex UI relationships without leaking CSS selector syntax into your application code.
351
+
352
+ ---
353
+
354
+ ## Responsive Media Queries
355
+
356
+ Built-in breakpoints:
357
+
358
+ | Key | Media Query |
359
+ |----|-------------|
360
+ | `_sm` | `(min-width: 640px)` |
361
+ | `_md` | `(min-width: 768px)` |
362
+ | `_lg` | `(min-width: 1024px)` |
363
+ | `_xl` | `(min-width: 1280px)` |
364
+ | `_xxl` | `(min-width: 1536px)` |
365
+
366
+ Example:
367
+
368
+ ``` ts
369
+ css({
370
+ fontSize: "14px",
158
371
  _lg: {
159
- width: 300
372
+ fontSize: "18px"
160
373
  }
161
374
  })
162
375
  ```
163
376
 
164
- Media queries can be nested and are automatically merged.
377
+ Media queries can be nested and merged automatically.
165
378
 
166
379
  ---
167
380
 
168
- ## Global Styles (Page Scoped)
381
+ ## Global Styles
382
+
383
+ ### `global(selector, style)`
384
+
385
+ Apply styles globally without generating a class.
169
386
 
170
- Global styles are scoped to the current page or component instance.
387
+ ``` ts
388
+ const { global, StyleProvider } = new NextStyle("global")
171
389
 
172
- ```ts
173
- ns.global("body", {
390
+ global("body", {
174
391
  margin: 0,
175
- fontFamily: "Inter, sans-serif"
392
+ fontFamily: "system-ui"
176
393
  })
177
- ```
178
394
 
179
- These styles exist only for the lifetime of the page or component.
395
+ global("a", {
396
+ color: "inherit",
397
+ _hover: {
398
+ textDecoration: "underline"
399
+ }
400
+ })
401
+ ```
180
402
 
181
403
  ---
182
404
 
183
- ## Keyframes
405
+ ## Animations
406
+
407
+ ### `keyframes(frames): string`
184
408
 
185
- Create animations using `keyframes()`:
409
+ Creates a `@keyframes` rule and returns its name.
186
410
 
187
- ```ts
188
- const fadeIn = ns.keyframes({
411
+ ``` ts
412
+ const fadeIn = keyframes({
189
413
  from: { opacity: 0 },
190
414
  to: { opacity: 1 }
191
415
  })
192
- ```
193
416
 
194
- Use the animation in styles:
195
-
196
- ```ts
197
- const modal = ns.css({
198
- animation: `${ fadeIn } 0.3s ease-out`
417
+ css({
418
+ animation: `${fadeIn} 300ms ease-in`
199
419
  })
200
420
  ```
201
421
 
202
- Keyframes are scoped to the current `NextStyle` instance.
203
-
204
422
  ---
205
423
 
206
- ## Font Face
424
+ ## Fonts
207
425
 
208
- Declare fonts using `fontFace()`:
426
+ ### `fontFace(font)`
209
427
 
210
- ```ts
211
- ns.fontFace({
212
- fontFamily: "Inter",
213
- src: "url(/fonts/inter.woff2) format('woff2')",
428
+ Registers a `@font-face` rule.
429
+
430
+ ``` ts
431
+ fontFace({
432
+ fontFamily: "MyFont",
433
+ src: "url(/fonts/myfont.woff2)",
214
434
  fontWeight: 400,
215
435
  fontStyle: "normal",
216
436
  fontDisplay: "swap"
217
437
  })
218
438
  ```
219
439
 
220
- Font-face rules are injected only for the current page or component.
221
-
222
440
  ---
223
441
 
224
- ## Deterministic Hashing
442
+ ## Rendering Styles
225
443
 
226
- - Styles are hashed using a stable algorithm
227
- - Object keys are sorted before hashing
228
- - Semantically identical styles always produce the same class name
229
- - Prevents unnecessary class regeneration
444
+ ### `<StyleProvider />`
230
445
 
231
- ---
446
+ Injects all generated CSS into a `<style>` tag.
447
+
448
+ ``` tsx
449
+ <>
450
+ <StyleProvider />
451
+ <App />
452
+ </>
453
+ ```
232
454
 
233
- ## Server-Side Rendering (SSR)
455
+ - Returns `null` if no styles exist
456
+ - Should be rendered **once per scope**
234
457
 
235
- `next-style` is SSR-safe.
458
+ ---
236
459
 
237
- Because the core API only generates strings:
238
- - No JSX is exported from the library
239
- - No React runtime is required
240
- - No side effects occur during render
460
+ ### `toTextCss(): string | null`
241
461
 
242
- You can safely inject styles during SSR:
462
+ Returns all generated CSS as a string.
243
463
 
244
- ```tsx
245
- <style>{ ns.StyleText }</style>
246
- ```
464
+ Useful for:
465
+ - Server-side rendering (SSR)
466
+ - Manual injection
467
+ - Debugging
247
468
 
248
- The same output will be produced on both the server and the client.
469
+ ``` ts
470
+ const cssText = toTextCss()
471
+ ```
249
472
 
250
473
  ---
251
474
 
252
- ## Performance Characteristics
253
-
254
- - CSS rules are generated and deduplicated per instance
255
- - PostCSS and Autoprefixer results are cached
256
- - Only one `<style>` tag is required per page or component
257
- - No global runtime mutations
475
+ ## Component Scoped Example
258
476
 
259
- Ideal for:
260
- - Next.js App Router
261
- - Page-level isolation
262
- - Component-driven design systems
477
+ Reusable, self-contained component.
263
478
 
264
- ---
479
+ ``` tsx
480
+ import { NextStyle } from "next-style"
265
481
 
266
- ## Common Gotchas
482
+ export function Card({ title, children }) {
483
+ const { css, StyleProvider } = new NextStyle("card")
267
484
 
268
- - Do not create a shared `NextStyle` instance across pages
269
- - Do not treat `next-style` as a global style manager
270
- - Always inject `ns.StyleText` before elements that use generated class names
271
- - Avoid calling `ns.css()` conditionally with different order between renders
485
+ const root = css({
486
+ padding: "16px",
487
+ borderRadius: "12px",
488
+ backgroundColor: "#fff",
489
+ boxShadow: "0 10px 25px rgba(0,0,0,.1)"
490
+ })
272
491
 
273
- ---
492
+ const heading = css({
493
+ fontSize: "18px",
494
+ fontWeight: 600,
495
+ marginBottom: "8px"
496
+ })
274
497
 
275
- ## Package Information
498
+ return (
499
+ <>
500
+ <StyleProvider />
501
+ <div className={root}>
502
+ <div className={heading}>{title}</div>
503
+ {children}
504
+ </div>
505
+ </>
506
+ )
507
+ }
508
+ ```
276
509
 
277
- - Name: `next-style`
278
- - Version: `1.1.2`
279
- - License: MIT
280
- - Module type: ESM
281
- - Side effects: false
510
+ ---
282
511
 
283
- Repository:
284
- https://github.com/kingslimes/next-style
512
+ ## Best Practices
285
513
 
286
- Issues:
287
- https://github.com/kingslimes/next-style/issues
514
+ - Create **one NextStyle instance per page or component**
515
+ - Do **not** share instances globally
516
+ - Render `StyleProvider` only once per scope
517
+ - Use meaningful prefixes (`home`, `card`, `profile`)
288
518
 
289
519
  ---
290
520
 
291
- ## Roadmap
521
+ ## Design Intentions
292
522
 
293
- - `&` selector nesting
294
- - `_dark` / `_light` helpers
295
- - `@layer` support
296
- - Optional React helpers
297
- - Dev-time warnings for incorrect usage
523
+ - No descendant selectors (`& > div`)
524
+ - No arbitrary selector nesting
525
+ - Predictable output over expressiveness
526
+ - Optimized for runtime and SSR safety
298
527
 
299
528
  ---
300
529
 
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Properties } from "csstype";
2
+ import type { DetailedReactHTMLElement } from "react";
2
3
  export type NextStyleProperties = {
3
4
  [K in keyof Properties<string | number>]?: Properties<string | number>[K];
4
5
  } & {
@@ -23,14 +24,78 @@ type FontFaceObject = {
23
24
  fontDisplay?: string;
24
25
  unicodeRange?: string;
25
26
  };
27
+ type PseudoState = "hover" | "focus" | "active";
28
+ declare class RelationBuilder {
29
+ private ns;
30
+ private source;
31
+ private pseudo?;
32
+ constructor(ns: NextStyle, source: string, pseudo?: PseudoState | undefined);
33
+ /** :hover */
34
+ hover(): RelationBuilder;
35
+ /** :focus */
36
+ focus(): RelationBuilder;
37
+ /** :active */
38
+ active(): RelationBuilder;
39
+ /**
40
+ * Adjacent sibling selector
41
+ *
42
+ * CSS:
43
+ * div:hover + p
44
+ *
45
+ * @example
46
+ * when(div).hover().adjacent(p, { color: "red" })
47
+ */
48
+ adjacent(target: string, style: NextStyleProperties): void;
49
+ /**
50
+ * Child selector
51
+ *
52
+ * CSS:
53
+ * div:hover > p
54
+ *
55
+ * @example
56
+ * when(div).hover().child(p, { color: "red" })
57
+ */
58
+ child(target: string, style: NextStyleProperties): void;
59
+ /**
60
+ * General sibling selector
61
+ *
62
+ * CSS:
63
+ * div:hover ~ p
64
+ *
65
+ * @example
66
+ * when(div).hover().sibling(p, { color: "red" })
67
+ */
68
+ sibling(target: string, style: NextStyleProperties): void;
69
+ /**
70
+ * Descendant selector
71
+ *
72
+ * CSS:
73
+ * div:hover p
74
+ *
75
+ * @example
76
+ * when(div).hover().descendant(p, { color: "red" })
77
+ */
78
+ descendant(target: string, style: NextStyleProperties): void;
79
+ private emit;
80
+ }
26
81
  export declare class NextStyle {
27
82
  private prefix;
28
83
  private rules;
29
84
  constructor(prefix?: string);
30
85
  css: (style: NextStyleProperties) => string;
31
86
  global: (selector: string, style: NextStyleProperties) => void;
87
+ /**
88
+ * Relation selector API
89
+ *
90
+ * @example
91
+ * when(container).hover().sibling(text)
92
+ */
93
+ when: (source: string) => RelationBuilder;
32
94
  keyframes: (frames: KeyframesObject) => string;
33
95
  fontFace: (font: FontFaceObject) => void;
34
- get StyleText(): string | null;
96
+ toTextCss: () => string | null;
97
+ StyleProvider: () => DetailedReactHTMLElement<{
98
+ children: string;
99
+ }, HTMLStyleElement> | null;
35
100
  }
36
101
  export {};
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- import postcss from"postcss";import autoprefixer from"autoprefixer";var processor=postcss([autoprefixer({overrideBrowserslist:[">0.2%","not dead","not op_mini all"]})]),postcssCache=new Map;function postcssTransform(cssText){let cached=postcssCache.get(cssText);if(cached)return cached;let result=processor.process(cssText,{from:void 0}).css;return postcssCache.set(cssText,result),result}function stableStringify(value){if(value==null||typeof value!=="object")return JSON.stringify(value);if(Array.isArray(value))return`[${value.map(stableStringify).join(",")}]`;return`{${Object.keys(value).sort().map((k)=>`"${k}":${stableStringify(value[k])}`).join(",")}}`}function createHashName(seed){let hash=BigInt("0xcbf29ce484222325"),prime=BigInt("0x100000001b3");for(let i=0;i<seed.length;i++)hash^=BigInt(seed.charCodeAt(i)),hash*=prime,hash&=BigInt("0xffffffffffffffff");return hash.toString(36).slice(0,9)}function toKebabCase(prop){return prop.replace(/[A-Z]/g,(m)=>`-${m.toLowerCase()}`)}var MEDIA_MAP={_sm:"(min-width:640px)",_md:"(min-width:768px)",_lg:"(min-width:1024px)",_xl:"(min-width:1280px)",_xxl:"(min-width:1536px)"};function mergeMedia(parent,current){if(!parent)return current;if(!current)return parent;return`${parent} and ${current}`}function serializeNested(style,ctx){let css="",base="";for(let key in style){let value=style[key];if(value==null||typeof value==="object"||key.startsWith("_"))continue;base+=`${toKebabCase(key)}:${value};`}if(base){let rule=`${ctx.selector}{${base}}`;css+=ctx.media?`@media ${ctx.media}{${rule}}`:rule}for(let pseudo of["_hover","_focus","_active"]){let value=style[pseudo];if(!value)continue;css+=serializeNested(value,{selector:`${ctx.selector}:${pseudo.slice(1)}`,media:ctx.media})}for(let key in MEDIA_MAP){let mediaKey=key,value=style[mediaKey];if(!value)continue;css+=serializeNested(value,{selector:ctx.selector,media:mergeMedia(ctx.media,MEDIA_MAP[mediaKey])})}return css}class NextStyle{prefix;rules=new Map;constructor(prefix="next"){this.prefix=prefix}css=(style)=>{let seed=stableStringify(style),hash=createHashName(seed),className=`${this.prefix}_${hash}`,key=`class:${className}`;if(!this.rules.has(key)){let raw=serializeNested(style,{selector:`.${className}`}),cssText=postcssTransform(raw);this.rules.set(key,cssText)}return className};global=(selector,style)=>{let key=`global:${selector}`;if(!this.rules.has(key)){let raw=serializeNested(style,{selector}),cssText=postcssTransform(raw);this.rules.set(key,cssText)}};keyframes=(frames)=>{let seed=stableStringify(frames),hash=createHashName(seed),name=`${this.prefix}_${hash}`,key=`@keyframes:${name}`;if(!this.rules.has(key)){let body="";for(let step in frames){let props="",frame=frames[step];for(let prop in frame)props+=`${toKebabCase(prop)}:${frame[prop]};`;body+=`${step}{${props}}`}let cssText=postcssTransform(`@keyframes ${name}{${body}}`);this.rules.set(key,cssText)}return name};fontFace=(font)=>{let seed=stableStringify(font),key=`@font-face:${createHashName(seed)}`;if(!this.rules.has(key)){let body="";for(let prop in font)body+=`${toKebabCase(prop)}:${font[prop]};`;let cssText=postcssTransform(`@font-face{${body}}`);this.rules.set(key,cssText)}};get StyleText(){if(this.rules.size===0)return null;let cssText="";for(let rule of this.rules.values())cssText+=rule+`
2
- `;return cssText}}export{NextStyle};
1
+ import postcss from"postcss";import{createElement}from"react";import autoprefixer from"autoprefixer";var processor=postcss([autoprefixer({overrideBrowserslist:[">0.2%","not dead","not op_mini all"]})]),postcssCache=new Map;function postcssTransform(cssText){let cached=postcssCache.get(cssText);if(cached)return cached;let result=processor.process(cssText,{from:void 0}).css;return postcssCache.set(cssText,result),result}function stableStringify(value){if(value==null||typeof value!=="object")return JSON.stringify(value);if(Array.isArray(value))return`[${value.map(stableStringify).join(",")}]`;return`{${Object.keys(value).sort().map((k)=>`"${k}":${stableStringify(value[k])}`).join(",")}}`}function createHashName(seed){let hash=BigInt("0xcbf29ce484222325"),prime=BigInt("0x100000001b3");for(let i=0;i<seed.length;i++)hash^=BigInt(seed.charCodeAt(i)),hash*=prime,hash&=BigInt("0xffffffffffffffff");return hash.toString(36).slice(0,9)}function toKebabCase(prop){return prop.replace(/[A-Z]/g,(m)=>`-${m.toLowerCase()}`)}var MEDIA_MAP={_sm:"(min-width:640px)",_md:"(min-width:768px)",_lg:"(min-width:1024px)",_xl:"(min-width:1280px)",_xxl:"(min-width:1536px)"};function mergeMedia(parent,current){if(!parent)return current;if(!current)return parent;return`${parent} and ${current}`}function serializeNested(style,ctx){let css="",base="";for(let key in style){let value=style[key];if(value==null||typeof value==="object"||key.startsWith("_"))continue;base+=`${toKebabCase(key)}:${value};`}if(base){let rule=`${ctx.selector}{${base}}`;css+=ctx.media?`@media ${ctx.media}{${rule}}`:rule}for(let pseudo of["_hover","_focus","_active"]){let value=style[pseudo];if(!value)continue;css+=serializeNested(value,{selector:`${ctx.selector}:${pseudo.slice(1)}`,media:ctx.media})}for(let key in MEDIA_MAP){let mediaKey=key,value=style[mediaKey];if(!value)continue;css+=serializeNested(value,{selector:ctx.selector,media:mergeMedia(ctx.media,MEDIA_MAP[mediaKey])})}return css}class RelationBuilder{ns;source;pseudo;constructor(ns,source,pseudo){this.ns=ns;this.source=source;this.pseudo=pseudo}hover(){return new RelationBuilder(this.ns,this.source,"hover")}focus(){return new RelationBuilder(this.ns,this.source,"focus")}active(){return new RelationBuilder(this.ns,this.source,"active")}adjacent(target,style){this.emit("+",target,style)}child(target,style){this.emit(">",target,style)}sibling(target,style){this.emit("~",target,style)}descendant(target,style){this.emit(" ",target,style)}emit(combinator,target,style){let pseudo=this.pseudo?`:${this.pseudo}`:"",selector=`.${this.source}${pseudo}${combinator}.${target}`;this.ns.global(selector,style)}}class NextStyle{prefix;rules=new Map;constructor(prefix="next"){this.prefix=prefix}css=(style)=>{let seed=stableStringify(style),hash=createHashName(seed),className=`${this.prefix}_${hash}`,key=`class:${className}`;if(!this.rules.has(key)){let raw=serializeNested(style,{selector:`.${className}`}),cssText=postcssTransform(raw);this.rules.set(key,cssText)}return className};global=(selector,style)=>{let key=`global:${selector}`;if(!this.rules.has(key)){let raw=serializeNested(style,{selector}),cssText=postcssTransform(raw);this.rules.set(key,cssText)}};when=(source)=>{return new RelationBuilder(this,source)};keyframes=(frames)=>{let seed=stableStringify(frames),hash=createHashName(seed),name=`${this.prefix}_${hash}`,key=`@keyframes:${name}`;if(!this.rules.has(key)){let body="";for(let step in frames){let props="",frame=frames[step];for(let prop in frame)props+=`${toKebabCase(prop)}:${frame[prop]};`;body+=`${step}{${props}}`}let cssText=postcssTransform(`@keyframes ${name}{${body}}`);this.rules.set(key,cssText)}return name};fontFace=(font)=>{let seed=stableStringify(font),key=`@font-face:${createHashName(seed)}`;if(!this.rules.has(key)){let body="";for(let prop in font)body+=`${toKebabCase(prop)}:${font[prop]};`;let cssText=postcssTransform(`@font-face{${body}}`);this.rules.set(key,cssText)}};toTextCss=()=>{if(this.rules.size===0)return null;let cssText="";for(let rule of this.rules.values())cssText+=rule+`
2
+ `;return cssText};StyleProvider=()=>{if(this.rules.size===0)return null;let cssText="";for(let rule of this.rules.values())cssText+=rule+`
3
+ `;return createElement("style",{children:cssText})}}export{NextStyle};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-style",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Lightweight runtime CSS-in-JS engine with nested pseudo selectors, media queries, global styles, keyframes, and font-face support.",
5
5
  "author": {
6
6
  "name": "kingslimes",
@@ -52,16 +52,14 @@
52
52
  "font-face"
53
53
  ],
54
54
  "peerDependencies": {
55
+ "react": ">=18",
55
56
  "postcss": "^8",
56
57
  "autoprefixer": "^10"
57
58
  },
58
59
  "devDependencies": {
59
60
  "csstype": "latest"
60
61
  },
61
- "engines": {
62
- "node": ">=18"
63
- },
64
62
  "publishConfig": {
65
63
  "access": "public"
66
64
  }
67
- }
65
+ }