next-style 1.1.8 → 1.2.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.
- package/dist/index.d.ts +235 -4
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import type { Properties } from "csstype";
|
|
2
2
|
import type { DetailedReactHTMLElement } from "react";
|
|
3
3
|
/**
|
|
4
|
-
* Style object
|
|
4
|
+
* Style object used by NextStyle.
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
* - Standard CSS properties (camelCase)
|
|
8
|
+
* - Pseudo states via `_hover`, `_focus`, `_active`
|
|
9
|
+
* - Responsive media queries via `_sm` ~ `_xxl`
|
|
10
|
+
*
|
|
11
|
+
* Example:
|
|
12
|
+
* ```ts
|
|
13
|
+
* const button = css({
|
|
14
|
+
* padding: "8px 16px",
|
|
15
|
+
* backgroundColor: "black",
|
|
16
|
+
* color: "white",
|
|
17
|
+
* _hover: { opacity: 0.8 },
|
|
18
|
+
* _md: { padding: "12px 20px" }
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
5
21
|
*/
|
|
6
22
|
export type NextStyleProperties = {
|
|
7
23
|
[K in keyof Properties<string | number>]?: Properties<string | number>[K];
|
|
@@ -28,37 +44,252 @@ type FontFaceObject = {
|
|
|
28
44
|
unicodeRange?: string;
|
|
29
45
|
};
|
|
30
46
|
type PseudoState = "hover" | "focus" | "active";
|
|
47
|
+
/**
|
|
48
|
+
* Builder for defining relations starting from a generated class name.
|
|
49
|
+
*
|
|
50
|
+
* This builder should only be created via `NextStyle.when(...)`.
|
|
51
|
+
*/
|
|
31
52
|
declare class RelationBuilder {
|
|
32
53
|
private ns;
|
|
33
54
|
private source;
|
|
34
55
|
private pseudo?;
|
|
56
|
+
/**
|
|
57
|
+
* @internal
|
|
58
|
+
* @param ns NextStyle instance
|
|
59
|
+
* @param source Source class name generated by `css()`
|
|
60
|
+
* @param pseudo Optional pseudo state applied to the source
|
|
61
|
+
*/
|
|
35
62
|
constructor(ns: NextStyle, source: string, pseudo?: PseudoState | undefined);
|
|
63
|
+
/**
|
|
64
|
+
* Apply `:hover` pseudo state to the source selector.
|
|
65
|
+
*
|
|
66
|
+
* All subsequent relations will be scoped under `:hover`.
|
|
67
|
+
*
|
|
68
|
+
* @returns RelationBuilder
|
|
69
|
+
*
|
|
70
|
+
* Example:
|
|
71
|
+
* ```ts
|
|
72
|
+
* when(card)
|
|
73
|
+
* .hover()
|
|
74
|
+
* .child(icon, { opacity: 1 })
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
36
77
|
hover(): RelationBuilder;
|
|
78
|
+
/**
|
|
79
|
+
* Apply `:focus` pseudo state to the source selector.
|
|
80
|
+
*
|
|
81
|
+
* @returns RelationBuilder
|
|
82
|
+
*/
|
|
37
83
|
focus(): RelationBuilder;
|
|
84
|
+
/**
|
|
85
|
+
* Apply `:active` pseudo state to the source selector.
|
|
86
|
+
*
|
|
87
|
+
* @returns RelationBuilder
|
|
88
|
+
*/
|
|
38
89
|
active(): RelationBuilder;
|
|
90
|
+
/**
|
|
91
|
+
* Define styles for an adjacent sibling selector.
|
|
92
|
+
*
|
|
93
|
+
* CSS equivalent:
|
|
94
|
+
* `.source + .target`
|
|
95
|
+
*
|
|
96
|
+
* @param target Target class name generated by `css()`
|
|
97
|
+
* @param style Style applied to the target element
|
|
98
|
+
*
|
|
99
|
+
* Example:
|
|
100
|
+
* ```ts
|
|
101
|
+
* when(input)
|
|
102
|
+
* .focus()
|
|
103
|
+
* .adjacent(label, { color: "red" })
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
39
106
|
adjacent(target: string, style: NextStyleProperties): void;
|
|
107
|
+
/**
|
|
108
|
+
* Define styles for a direct child selector.
|
|
109
|
+
*
|
|
110
|
+
* CSS equivalent:
|
|
111
|
+
* `.source > .target`
|
|
112
|
+
*
|
|
113
|
+
* @param target Target class name generated by `css()`
|
|
114
|
+
* @param style Style applied to the target element
|
|
115
|
+
*/
|
|
40
116
|
child(target: string, style: NextStyleProperties): void;
|
|
117
|
+
/**
|
|
118
|
+
* Define styles for a general sibling selector.
|
|
119
|
+
*
|
|
120
|
+
* CSS equivalent:
|
|
121
|
+
* `.source ~ .target`
|
|
122
|
+
*
|
|
123
|
+
* @param target Target class name generated by `css()`
|
|
124
|
+
* @param style Style applied to the target element
|
|
125
|
+
*/
|
|
41
126
|
sibling(target: string, style: NextStyleProperties): void;
|
|
127
|
+
/**
|
|
128
|
+
* Define styles for a descendant selector.
|
|
129
|
+
*
|
|
130
|
+
* CSS equivalent:
|
|
131
|
+
* `.source .target`
|
|
132
|
+
*
|
|
133
|
+
* @param target Target class name generated by `css()`
|
|
134
|
+
* @param style Style applied to the target element
|
|
135
|
+
*/
|
|
42
136
|
descendant(target: string, style: NextStyleProperties): void;
|
|
137
|
+
/**
|
|
138
|
+
* @internal
|
|
139
|
+
* Emit a global relational rule.
|
|
140
|
+
*/
|
|
43
141
|
private emit;
|
|
44
142
|
}
|
|
45
143
|
/**
|
|
46
|
-
* NextStyle
|
|
144
|
+
* NextStyle
|
|
145
|
+
*
|
|
146
|
+
* Lightweight runtime CSS-in-JS engine with deterministic class names.
|
|
147
|
+
*
|
|
148
|
+
* Features:
|
|
149
|
+
* - Scoped class generation
|
|
150
|
+
* - Nested pseudo selectors
|
|
151
|
+
* - Responsive media queries
|
|
152
|
+
* - Global styles
|
|
153
|
+
* - Keyframes and font-face support
|
|
154
|
+
*
|
|
155
|
+
* Example:
|
|
156
|
+
* ```ts
|
|
157
|
+
* const ns = new NextStyle("app")
|
|
158
|
+
* ```
|
|
47
159
|
*/
|
|
48
160
|
export declare class NextStyle {
|
|
49
161
|
private prefix;
|
|
50
162
|
private rules;
|
|
163
|
+
private globalStore;
|
|
51
164
|
constructor(prefix?: string);
|
|
165
|
+
/**
|
|
166
|
+
* Generate a scoped class name from a style object.
|
|
167
|
+
*
|
|
168
|
+
* The returned value is a branded class name and is intended
|
|
169
|
+
* to be used with `when(...)` and relational APIs.
|
|
170
|
+
*
|
|
171
|
+
* @param style Style definition object
|
|
172
|
+
* @returns Scoped class name
|
|
173
|
+
*
|
|
174
|
+
* Example:
|
|
175
|
+
* ```ts
|
|
176
|
+
* const button = css({ padding: 8 })
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
52
179
|
css: (style: NextStyleProperties) => string;
|
|
180
|
+
/**
|
|
181
|
+
* Define a global CSS selector.
|
|
182
|
+
*
|
|
183
|
+
* Styles are merged at property level instead of overwritten.
|
|
184
|
+
*
|
|
185
|
+
* @param selector CSS selector
|
|
186
|
+
* @param style Style definition
|
|
187
|
+
*
|
|
188
|
+
* Example:
|
|
189
|
+
* ```ts
|
|
190
|
+
* global("body", {
|
|
191
|
+
* fontFamily: "Kanit, sans-serif"
|
|
192
|
+
* })
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
53
195
|
global: (selector: string, style: NextStyleProperties) => void;
|
|
54
196
|
/**
|
|
55
|
-
* Apply default
|
|
197
|
+
* Apply default browser reset styles
|
|
198
|
+
* ```css
|
|
199
|
+
* html, body {
|
|
200
|
+
* max-width: 100vw;
|
|
201
|
+
* overflow-x: hidden;
|
|
202
|
+
* }
|
|
203
|
+
* body {
|
|
204
|
+
* color: "black";
|
|
205
|
+
* background: "white";
|
|
206
|
+
* -moz-osx-font-smoothing: grayscale;
|
|
207
|
+
* -webkit-font-smoothing: antialiased;
|
|
208
|
+
* font-family: "Arial, Helvetica, sans-serif"
|
|
209
|
+
* }
|
|
210
|
+
* *,
|
|
211
|
+
* *::before,
|
|
212
|
+
* *::after {
|
|
213
|
+
* margin: 0;
|
|
214
|
+
* padding: 0;
|
|
215
|
+
* box-sizing: border-box;
|
|
216
|
+
* }
|
|
217
|
+
* a {
|
|
218
|
+
* color: inherit;
|
|
219
|
+
* text-decoration: none
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
resetStyle: () => this;
|
|
224
|
+
/**
|
|
225
|
+
* Create relational selectors based on a class generated by `css(...)`.
|
|
226
|
+
*
|
|
227
|
+
* ⚠️ This method only accepts class names returned from `css`.
|
|
228
|
+
*
|
|
229
|
+
* @param source Class name generated by `css`
|
|
230
|
+
*
|
|
231
|
+
* Example:
|
|
232
|
+
* ```ts
|
|
233
|
+
* const card = css({ ... })
|
|
234
|
+
*
|
|
235
|
+
* when(card)
|
|
236
|
+
* .hover()
|
|
237
|
+
* .child("icon", { opacity: 1 })
|
|
238
|
+
* ```
|
|
56
239
|
*/
|
|
57
|
-
resetBrowserStyle: () => void;
|
|
58
240
|
when: (source: string) => RelationBuilder;
|
|
241
|
+
/**
|
|
242
|
+
* Register keyframes animation.
|
|
243
|
+
*
|
|
244
|
+
* @param frames Keyframes definition
|
|
245
|
+
* @returns Generated animation name
|
|
246
|
+
*
|
|
247
|
+
* Example:
|
|
248
|
+
* ```ts
|
|
249
|
+
* const fadeIn = keyframes({
|
|
250
|
+
* from: { opacity: 0 },
|
|
251
|
+
* to: { opacity: 1 }
|
|
252
|
+
* })
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
59
255
|
keyframes: (frames: KeyframesObject) => string;
|
|
256
|
+
/**
|
|
257
|
+
* Register a `@font-face` rule.
|
|
258
|
+
*
|
|
259
|
+
* Each unique definition is injected only once.
|
|
260
|
+
*
|
|
261
|
+
* @param font Font-face definition
|
|
262
|
+
*
|
|
263
|
+
* Example:
|
|
264
|
+
* ```ts
|
|
265
|
+
* fontFace({
|
|
266
|
+
* fontFamily: "Kanit",
|
|
267
|
+
* src: "url(/kanit.woff2) format('woff2')",
|
|
268
|
+
* fontWeight: 400
|
|
269
|
+
* })
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
60
272
|
fontFace: (font: FontFaceObject) => void;
|
|
273
|
+
/**
|
|
274
|
+
* Serialize all generated CSS into a single string.
|
|
275
|
+
*
|
|
276
|
+
* Intended for:
|
|
277
|
+
* - Manual `<style>` injection
|
|
278
|
+
* - SSR environments
|
|
279
|
+
*
|
|
280
|
+
* @returns CSS text or `null` if no styles exist
|
|
281
|
+
*/
|
|
61
282
|
toTextCss: () => string | null;
|
|
283
|
+
/**
|
|
284
|
+
* React component that injects generated CSS into a `<style>` tag.
|
|
285
|
+
*
|
|
286
|
+
* Returns `null` if no styles are registered.
|
|
287
|
+
*
|
|
288
|
+
* Example:
|
|
289
|
+
* ```tsx
|
|
290
|
+
* <StyleProvider />
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
62
293
|
StyleProvider: () => DetailedReactHTMLElement<{
|
|
63
294
|
children: string;
|
|
64
295
|
}, HTMLStyleElement> | null;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
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="",declarations=[];for(let key in style){let value=style[key];if(value==null||typeof value==="object"||key.startsWith("_"))continue;declarations.push(`${toKebabCase(key)}:${value}`)}if(declarations.length){let rule=`${ctx.selector}{
|
|
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="",declarations=[];for(let key in style){let value=style[key];if(value==null||typeof value==="object"||key.startsWith("_"))continue;declarations.push(`${toKebabCase(key)}:${value}`)}if(declarations.length){let rule=`${ctx.selector}{${declarations.join(";")}}`;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;globalStore=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}`,merged={...this.globalStore.get(key)??{},...style};this.globalStore.set(key,merged);let raw=serializeNested(merged,{selector}),cssText=postcssTransform(raw);if(this.rules.has(key))this.rules.delete(key);this.rules.set(key,cssText)};resetStyle=()=>{return this.global("html,body",{maxWidth:"100vw",overflowX:"hidden"}),this.global("body",{color:"black",background:"white",MozOsxFontSmoothing:"grayscale",WebkitFontSmoothing:"antialiased",fontFamily:"Arial, Helvetica, sans-serif"}),this.global("*,*::before,*::after",{margin:0,padding:0,boxSizing:"border-box"}),this.global("a",{color:"inherit",textDecoration:"none"}),this};when=(source)=>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 declarations=[],frame=frames[step];for(let prop in frame)declarations.push(`${toKebabCase(prop)}:${frame[prop]}`);body+=`${step}{ ${declarations.join(";")} }`}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 declarations=[];for(let prop in font)declarations.push(`${toKebabCase(prop)}:${font[prop]}`);let cssText=postcssTransform(`@font-face{ ${declarations.join(";")} }`);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
2
|
`;return cssText};StyleProvider=()=>{if(this.rules.size===0)return null;let cssText="";for(let rule of this.rules.values())cssText+=rule+`
|
|
3
3
|
`;return createElement("style",{children:cssText})}}export{NextStyle};
|
package/package.json
CHANGED