next-style 1.1.1 → 1.1.3
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 +198 -122
- package/dist/index.js +2 -0
- package/package.json +10 -9
- package/dist/index.d.ts +0 -22
- package/dist/index.jsx +0 -92
package/README.md
CHANGED
|
@@ -1,227 +1,303 @@
|
|
|
1
|
-
#
|
|
1
|
+
# next-style
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
It supports nested pseudo selectors, responsive media queries, and automatic vendor prefixing via PostCSS — all at runtime with zero build-time CSS extraction.
|
|
3
|
+
**next-style** is a lightweight runtime CSS-in-JS engine designed for React, Next.js, and Bun.
|
|
5
4
|
|
|
6
|
-
|
|
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.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
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
|
|
20
|
+
|
|
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`
|
|
7
24
|
|
|
8
25
|
---
|
|
9
26
|
|
|
10
27
|
## Features
|
|
11
28
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
29
|
+
- Object-based styling with strong TypeScript support
|
|
30
|
+
- Deterministic hashing (same styles always produce the same class name)
|
|
14
31
|
- Nested pseudo selectors (`_hover`, `_focus`, `_active`)
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
32
|
+
- Built-in responsive media queries
|
|
33
|
+
- Page-scoped global styles
|
|
34
|
+
- `@keyframes` support
|
|
35
|
+
- `@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`)
|
|
20
40
|
|
|
21
41
|
---
|
|
22
42
|
|
|
23
43
|
## Installation
|
|
24
44
|
|
|
25
|
-
|
|
45
|
+
### npm
|
|
26
46
|
|
|
27
|
-
```
|
|
28
|
-
npm install next-style
|
|
47
|
+
```sh
|
|
48
|
+
npm install next-style
|
|
29
49
|
```
|
|
30
50
|
|
|
31
|
-
|
|
51
|
+
### Bun
|
|
32
52
|
|
|
33
|
-
```
|
|
34
|
-
bun add next-style
|
|
53
|
+
```sh
|
|
54
|
+
bun add next-style
|
|
35
55
|
```
|
|
36
56
|
|
|
37
57
|
---
|
|
38
58
|
|
|
39
|
-
##
|
|
59
|
+
## Peer Dependencies
|
|
40
60
|
|
|
41
|
-
|
|
42
|
-
import { NextStyle } from "next-style"
|
|
61
|
+
For most **Next.js applications**, you **do not need to install these manually**.
|
|
43
62
|
|
|
44
|
-
|
|
63
|
+
- **React** is already included with Next.js
|
|
64
|
+
- **PostCSS** and **Autoprefixer** are bundled and used internally by Next.js
|
|
45
65
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
_md: {
|
|
56
|
-
padding: "16px"
|
|
57
|
-
}
|
|
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
|
|
70
|
+
|
|
71
|
+
If required, install them manually:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
npm install react postcss autoprefixer
|
|
59
75
|
```
|
|
60
76
|
|
|
61
|
-
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Basic Usage (Page Scoped)
|
|
62
80
|
|
|
63
|
-
|
|
64
|
-
|
|
81
|
+
Create a `NextStyle` instance **inside the page or component**.
|
|
82
|
+
You may optionally provide a **custom prefix** to control generated class names.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { NextStyle } from "next-style"
|
|
86
|
+
|
|
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"
|
|
94
|
+
})
|
|
65
95
|
return (
|
|
66
96
|
<>
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
</div>
|
|
70
|
-
<style.Provider />
|
|
97
|
+
<style>{ ns.StyleText }</style>
|
|
98
|
+
<button className={ btn }>Click me</button>
|
|
71
99
|
</>
|
|
72
100
|
)
|
|
73
101
|
}
|
|
74
102
|
```
|
|
75
103
|
|
|
76
|
-
|
|
104
|
+
Generated class names will look like:
|
|
77
105
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
### Base Properties
|
|
81
|
-
|
|
82
|
-
All standard CSS properties are supported and fully typed:
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
{
|
|
86
|
-
margin: "8px",
|
|
87
|
-
fontSize: "14px",
|
|
88
|
-
backgroundColor: "#000"
|
|
89
|
-
}
|
|
106
|
+
```txt
|
|
107
|
+
home_ab12cd3
|
|
90
108
|
```
|
|
91
109
|
|
|
92
|
-
|
|
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
|
|
93
115
|
|
|
94
116
|
---
|
|
95
117
|
|
|
96
|
-
|
|
118
|
+
## Pseudo Selectors
|
|
97
119
|
|
|
98
|
-
|
|
120
|
+
Pseudo selectors are defined using keys prefixed with `_`.
|
|
99
121
|
|
|
100
122
|
```ts
|
|
101
|
-
{
|
|
123
|
+
const card = ns.css({
|
|
124
|
+
backgroundColor: "#fff",
|
|
125
|
+
transition: "0.2s ease",
|
|
102
126
|
_hover: {
|
|
103
|
-
|
|
104
|
-
},
|
|
105
|
-
_focus: {
|
|
106
|
-
outline: "2px solid blue"
|
|
127
|
+
backgroundColor: "#f5f5f5"
|
|
107
128
|
},
|
|
108
129
|
_active: {
|
|
109
130
|
transform: "scale(0.98)"
|
|
110
131
|
}
|
|
111
|
-
}
|
|
132
|
+
})
|
|
112
133
|
```
|
|
113
134
|
|
|
114
|
-
Supported
|
|
135
|
+
Supported pseudo selectors:
|
|
115
136
|
- `_hover`
|
|
116
137
|
- `_focus`
|
|
117
138
|
- `_active`
|
|
118
139
|
|
|
119
140
|
---
|
|
120
141
|
|
|
121
|
-
|
|
142
|
+
## Responsive Styles (Media Queries)
|
|
122
143
|
|
|
123
|
-
|
|
144
|
+
Built-in breakpoints:
|
|
124
145
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
| `_xl` | `(min-width: 1280px)` |
|
|
131
|
-
| `_xxl` | `(min-width: 1536px)` |
|
|
132
|
-
|
|
133
|
-
Example:
|
|
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
|
|
134
151
|
|
|
135
152
|
```ts
|
|
136
|
-
{
|
|
137
|
-
|
|
153
|
+
const box = ns.css({
|
|
154
|
+
width: 100,
|
|
155
|
+
_md: {
|
|
156
|
+
width: 200
|
|
157
|
+
},
|
|
138
158
|
_lg: {
|
|
139
|
-
|
|
159
|
+
width: 300
|
|
140
160
|
}
|
|
141
|
-
}
|
|
161
|
+
})
|
|
142
162
|
```
|
|
143
163
|
|
|
164
|
+
Media queries can be nested and are automatically merged.
|
|
165
|
+
|
|
144
166
|
---
|
|
145
167
|
|
|
146
|
-
##
|
|
168
|
+
## Global Styles (Page Scoped)
|
|
147
169
|
|
|
148
|
-
|
|
170
|
+
Global styles are scoped to the current page or component instance.
|
|
149
171
|
|
|
150
|
-
|
|
172
|
+
```ts
|
|
173
|
+
ns.global("body", {
|
|
174
|
+
margin: 0,
|
|
175
|
+
fontFamily: "Inter, sans-serif"
|
|
176
|
+
})
|
|
177
|
+
```
|
|
151
178
|
|
|
152
|
-
|
|
153
|
-
- It should be rendered **after** calling `css(...)`
|
|
154
|
-
- It performs no side effects if no styles were generated
|
|
179
|
+
These styles exist only for the lifetime of the page or component.
|
|
155
180
|
|
|
156
|
-
|
|
157
|
-
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Keyframes
|
|
184
|
+
|
|
185
|
+
Create animations using `keyframes()`:
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
const fadeIn = ns.keyframes({
|
|
189
|
+
from: { opacity: 0 },
|
|
190
|
+
to: { opacity: 1 }
|
|
191
|
+
})
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Use the animation in styles:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const modal = ns.css({
|
|
198
|
+
animation: `${ fadeIn } 0.3s ease-out`
|
|
199
|
+
})
|
|
158
200
|
```
|
|
159
201
|
|
|
202
|
+
Keyframes are scoped to the current `NextStyle` instance.
|
|
203
|
+
|
|
160
204
|
---
|
|
161
205
|
|
|
162
|
-
##
|
|
206
|
+
## Font Face
|
|
163
207
|
|
|
164
|
-
|
|
208
|
+
Declare fonts using `fontFace()`:
|
|
165
209
|
|
|
166
|
-
```
|
|
167
|
-
|
|
210
|
+
```ts
|
|
211
|
+
ns.fontFace({
|
|
212
|
+
fontFamily: "Inter",
|
|
213
|
+
src: "url(/fonts/inter.woff2) format('woff2')",
|
|
214
|
+
fontWeight: 400,
|
|
215
|
+
fontStyle: "normal",
|
|
216
|
+
fontDisplay: "swap"
|
|
217
|
+
})
|
|
168
218
|
```
|
|
169
219
|
|
|
170
|
-
|
|
171
|
-
- Stable class names
|
|
172
|
-
- No duplicates
|
|
173
|
-
- Automatic caching of generated rules
|
|
220
|
+
Font-face rules are injected only for the current page or component.
|
|
174
221
|
|
|
175
222
|
---
|
|
176
223
|
|
|
177
|
-
##
|
|
224
|
+
## Deterministic Hashing
|
|
178
225
|
|
|
179
|
-
-
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
-
|
|
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
|
|
183
230
|
|
|
184
231
|
---
|
|
185
232
|
|
|
186
|
-
##
|
|
233
|
+
## Server-Side Rendering (SSR)
|
|
187
234
|
|
|
188
|
-
|
|
235
|
+
`next-style` is SSR-safe.
|
|
189
236
|
|
|
190
|
-
|
|
191
|
-
-
|
|
192
|
-
-
|
|
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
|
|
193
241
|
|
|
194
|
-
|
|
242
|
+
You can safely inject styles during SSR:
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
<style>{ ns.StyleText }</style>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The same output will be produced on both the server and the client.
|
|
195
249
|
|
|
196
250
|
---
|
|
197
251
|
|
|
198
|
-
##
|
|
252
|
+
## Performance Characteristics
|
|
199
253
|
|
|
200
|
-
|
|
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
|
|
201
258
|
|
|
202
|
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
259
|
+
Ideal for:
|
|
260
|
+
- Next.js App Router
|
|
261
|
+
- Page-level isolation
|
|
262
|
+
- Component-driven design systems
|
|
263
|
+
|
|
264
|
+
---
|
|
205
265
|
|
|
206
|
-
|
|
266
|
+
## Common Gotchas
|
|
207
267
|
|
|
208
|
-
-
|
|
209
|
-
-
|
|
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
|
|
210
272
|
|
|
211
273
|
---
|
|
212
274
|
|
|
213
|
-
##
|
|
275
|
+
## Package Information
|
|
214
276
|
|
|
215
|
-
|
|
277
|
+
- Name: `next-style`
|
|
278
|
+
- Version: `1.1.2`
|
|
279
|
+
- License: MIT
|
|
280
|
+
- Module type: ESM
|
|
281
|
+
- Side effects: false
|
|
282
|
+
|
|
283
|
+
Repository:
|
|
284
|
+
https://github.com/kingslimes/next-style
|
|
285
|
+
|
|
286
|
+
Issues:
|
|
287
|
+
https://github.com/kingslimes/next-style/issues
|
|
216
288
|
|
|
217
289
|
---
|
|
218
290
|
|
|
219
|
-
##
|
|
291
|
+
## Roadmap
|
|
220
292
|
|
|
221
|
-
|
|
293
|
+
- `&` selector nesting
|
|
294
|
+
- `_dark` / `_light` helpers
|
|
295
|
+
- `@layer` support
|
|
296
|
+
- Optional React helpers
|
|
297
|
+
- Dev-time warnings for incorrect usage
|
|
222
298
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## License
|
|
226
302
|
|
|
227
|
-
|
|
303
|
+
MIT © kingslimes
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-style",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
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",
|
|
@@ -16,22 +16,22 @@
|
|
|
16
16
|
"LICENSE",
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
|
-
"main": "./dist/index.
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
|
-
"import": "./dist/index.
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
24
|
"types": "./dist/index.d.ts"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|
|
29
|
-
"url": "https://github.com/kingslimes/
|
|
29
|
+
"url": "https://github.com/kingslimes/next-style.git"
|
|
30
30
|
},
|
|
31
31
|
"bugs": {
|
|
32
|
-
"url": "https://github.com/kingslimes/
|
|
32
|
+
"url": "https://github.com/kingslimes/next-style/issues"
|
|
33
33
|
},
|
|
34
|
-
"homepage": "https://github.com/kingslimes/
|
|
34
|
+
"homepage": "https://github.com/kingslimes/next-style#readme",
|
|
35
35
|
"keywords": [
|
|
36
36
|
"css",
|
|
37
37
|
"css-in-js",
|
|
@@ -52,15 +52,16 @@
|
|
|
52
52
|
"font-face"
|
|
53
53
|
],
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"react": ">=18",
|
|
56
55
|
"postcss": "^8",
|
|
57
56
|
"autoprefixer": "^10"
|
|
58
57
|
},
|
|
59
58
|
"devDependencies": {
|
|
60
|
-
"csstype": "
|
|
59
|
+
"csstype": "latest"
|
|
61
60
|
},
|
|
62
61
|
"engines": {
|
|
63
|
-
"bun": ">=1.0.0",
|
|
64
62
|
"node": ">=18"
|
|
63
|
+
},
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
65
66
|
}
|
|
66
67
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { Properties } from "csstype";
|
|
2
|
-
export type NextStyleProperties = {
|
|
3
|
-
[K in keyof Properties<string | number>]?: Properties<string | number>[K];
|
|
4
|
-
} & {
|
|
5
|
-
_hover?: NextStyleObject;
|
|
6
|
-
_focus?: NextStyleObject;
|
|
7
|
-
_active?: NextStyleObject;
|
|
8
|
-
_sm?: NextStyleObject;
|
|
9
|
-
_md?: NextStyleObject;
|
|
10
|
-
_lg?: NextStyleObject;
|
|
11
|
-
_xl?: NextStyleObject;
|
|
12
|
-
_xxl?: NextStyleObject;
|
|
13
|
-
};
|
|
14
|
-
type NextStyleObject = Omit<NextStyleProperties, "_sm" | "_md" | "_lg" | "_xl" | "_xxl">;
|
|
15
|
-
export declare class NextStyle {
|
|
16
|
-
private prefix;
|
|
17
|
-
private rules;
|
|
18
|
-
constructor(prefix?: string);
|
|
19
|
-
css: (style: NextStyleProperties) => string;
|
|
20
|
-
Provider: () => import("react").JSX.Element | null;
|
|
21
|
-
}
|
|
22
|
-
export {};
|
package/dist/index.jsx
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import postcss from "postcss";
|
|
2
|
-
import autoprefixer from "autoprefixer";
|
|
3
|
-
const processor = postcss([autoprefixer({
|
|
4
|
-
overrideBrowserslist: [">0.2%", "not dead", "not op_mini all"]
|
|
5
|
-
})]);
|
|
6
|
-
const postcssCache = new Map();
|
|
7
|
-
function postcssTransform(cssText) {
|
|
8
|
-
const cached = postcssCache.get(cssText);
|
|
9
|
-
if (cached) return cached;
|
|
10
|
-
const result = processor.process(cssText, {
|
|
11
|
-
from: undefined
|
|
12
|
-
}).css;
|
|
13
|
-
postcssCache.set(cssText, result);
|
|
14
|
-
return result;
|
|
15
|
-
}
|
|
16
|
-
function createHashName(seed) {
|
|
17
|
-
let hash = BigInt("0xcbf29ce484222325");
|
|
18
|
-
const prime = BigInt("0x100000001b3");
|
|
19
|
-
for (let i = 0; i < seed.length; i++) {
|
|
20
|
-
hash ^= BigInt(seed.charCodeAt(i));
|
|
21
|
-
hash *= prime;
|
|
22
|
-
hash &= BigInt("0xffffffffffffffff");
|
|
23
|
-
}
|
|
24
|
-
return hash.toString(36).slice(0, 9);
|
|
25
|
-
}
|
|
26
|
-
function toKebabCase(prop) {
|
|
27
|
-
return prop.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);
|
|
28
|
-
}
|
|
29
|
-
const MEDIA_MAP = {
|
|
30
|
-
_sm: "( min-width: 640px )",
|
|
31
|
-
_md: "( min-width: 768px )",
|
|
32
|
-
_lg: "( min-width: 1024px )",
|
|
33
|
-
_xl: "( min-width: 1280px )",
|
|
34
|
-
_xxl: "( min-width: 1536px )"
|
|
35
|
-
};
|
|
36
|
-
function serializeNested(style, ctx) {
|
|
37
|
-
let css = "";
|
|
38
|
-
let base = "";
|
|
39
|
-
for (const key in style) {
|
|
40
|
-
const value = style[key];
|
|
41
|
-
if (value == null || typeof value === "object" || key.startsWith("_")) continue;
|
|
42
|
-
base += `${toKebabCase(key)}:${value};`;
|
|
43
|
-
}
|
|
44
|
-
if (base) {
|
|
45
|
-
const rule = `${ctx.selector}{${base}}`;
|
|
46
|
-
css += ctx.media ? `${ctx.media}{${rule}}` : rule;
|
|
47
|
-
}
|
|
48
|
-
for (const pseudo of ["_hover", "_focus", "_active"]) {
|
|
49
|
-
const value = style[pseudo];
|
|
50
|
-
if (!value) continue;
|
|
51
|
-
css += serializeNested(value, {
|
|
52
|
-
...ctx,
|
|
53
|
-
selector: `${ctx.selector}:${pseudo.slice(1)}`
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
for (const key in MEDIA_MAP) {
|
|
57
|
-
const mediaKey = key;
|
|
58
|
-
const value = style[mediaKey];
|
|
59
|
-
if (!value) continue;
|
|
60
|
-
css += serializeNested(value, {
|
|
61
|
-
...ctx,
|
|
62
|
-
media: `@media ${MEDIA_MAP[mediaKey]}`
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return css;
|
|
66
|
-
}
|
|
67
|
-
export class NextStyle {
|
|
68
|
-
rules = new Map();
|
|
69
|
-
constructor(prefix = "next") {
|
|
70
|
-
this.prefix = prefix;
|
|
71
|
-
}
|
|
72
|
-
css = style => {
|
|
73
|
-
const hash = createHashName(JSON.stringify(style));
|
|
74
|
-
const className = `${this.prefix}_${hash}`;
|
|
75
|
-
if (!this.rules.has(className)) {
|
|
76
|
-
const raw = serializeNested(style, {
|
|
77
|
-
selector: `.${className}`
|
|
78
|
-
});
|
|
79
|
-
const cssText = postcssTransform(raw);
|
|
80
|
-
this.rules.set(className, cssText);
|
|
81
|
-
}
|
|
82
|
-
return className;
|
|
83
|
-
};
|
|
84
|
-
Provider = () => {
|
|
85
|
-
if (this.rules.size === 0) return null;
|
|
86
|
-
let cssText = "";
|
|
87
|
-
for (const rule of this.rules.values()) {
|
|
88
|
-
cssText += rule + "\n";
|
|
89
|
-
}
|
|
90
|
-
return <style>{cssText}</style>;
|
|
91
|
-
};
|
|
92
|
-
}
|