zss-engine 0.2.8 → 0.2.10
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/build-12x-B3dvmUcg.mjs +52 -0
- package/dist/build-12x-C7vH1H69.js +54 -0
- package/dist/index.js +236 -30
- package/dist/index.mjs +225 -8
- package/package.json +10 -8
- package/types/index.d.ts +130 -8
- package/dist/types/common/css-properties.js +0 -2
- package/dist/types/common/css-properties.mjs +0 -1
- package/dist/types/common/css-property.js +0 -2
- package/dist/types/common/css-property.mjs +0 -1
- package/dist/types/index.js +0 -21
- package/dist/types/index.mjs +0 -5
- package/dist/types/main/create.js +0 -2
- package/dist/types/main/create.mjs +0 -1
- package/dist/types/main/global.js +0 -2
- package/dist/types/main/global.mjs +0 -1
- package/dist/types/main/vars.js +0 -2
- package/dist/types/main/vars.mjs +0 -1
- package/dist/utils/build.js +0 -27
- package/dist/utils/build.mjs +0 -23
- package/dist/utils/hash.js +0 -34
- package/dist/utils/hash.mjs +0 -31
- package/dist/utils/helper.js +0 -21
- package/dist/utils/helper.mjs +0 -16
- package/dist/utils/inject-client-css.js +0 -51
- package/dist/utils/inject-client-css.mjs +0 -47
- package/dist/utils/inject-client-global-css.js +0 -18
- package/dist/utils/inject-client-global-css.mjs +0 -15
- package/dist/utils/inject-server-css.js +0 -11
- package/dist/utils/inject-server-css.mjs +0 -7
- package/dist/utils/transpiler.js +0 -125
- package/dist/utils/transpiler.mjs +0 -122
- package/types/types/common/css-properties.d.ts +0 -46
- package/types/types/common/css-property.d.ts +0 -5
- package/types/types/index.d.ts +0 -5
- package/types/types/main/create.d.ts +0 -10
- package/types/types/main/global.d.ts +0 -37
- package/types/types/main/vars.d.ts +0 -10
- package/types/utils/build.d.ts +0 -1
- package/types/utils/hash.d.ts +0 -2
- package/types/utils/helper.d.ts +0 -6
- package/types/utils/inject-client-css.d.ts +0 -2
- package/types/utils/inject-client-global-css.d.ts +0 -1
- package/types/utils/inject-server-css.d.ts +0 -2
- package/types/utils/transpiler.d.ts +0 -4
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
import __node_cjsModule from 'node:module';
|
|
3
|
+
|
|
4
|
+
const isWindowDefined = typeof window !== 'undefined';
|
|
5
|
+
const isDocumentDefined = typeof document !== 'undefined';
|
|
6
|
+
const isServer = !isWindowDefined || !isDocumentDefined;
|
|
7
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
8
|
+
const isDevAndTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
|
|
9
|
+
const isDevServer = isDevelopment && isServer;
|
|
10
|
+
const exception = [
|
|
11
|
+
'line-height',
|
|
12
|
+
'font-weight',
|
|
13
|
+
'opacity',
|
|
14
|
+
'scale',
|
|
15
|
+
'z-index',
|
|
16
|
+
'column-count',
|
|
17
|
+
'order',
|
|
18
|
+
'orphans',
|
|
19
|
+
'widows'
|
|
20
|
+
];
|
|
21
|
+
const applyCssValue = (value, cssProp)=>{
|
|
22
|
+
if (typeof value === 'number') {
|
|
23
|
+
return exception.includes(cssProp) ? value.toString() : value + 'px';
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
};
|
|
27
|
+
const camelToKebabCase = (property)=>{
|
|
28
|
+
return property.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const require = __node_cjsModule.createRequire(import.meta.url);
|
|
32
|
+
|
|
33
|
+
const build = async (styleSheet, filePath, global)=>{
|
|
34
|
+
if (!isServer) return;
|
|
35
|
+
const fs = require('fs');
|
|
36
|
+
const { styleText } = require('util');
|
|
37
|
+
const message = global === '--global' ? styleText('underline', `✅Generated global CSS\n\n`) : styleText('underline', `✅Generated create CSS\n\n`);
|
|
38
|
+
try {
|
|
39
|
+
if (fs.existsSync(filePath)) {
|
|
40
|
+
const cssData = fs.readFileSync(filePath, 'utf-8');
|
|
41
|
+
if (!cssData.includes(styleSheet)) {
|
|
42
|
+
fs.appendFileSync(filePath, styleSheet, 'utf-8');
|
|
43
|
+
if (process.argv.includes('--log')) console.log(message + styleSheet);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('Error writing to file:', error);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { applyCssValue as a, build as b, camelToKebabCase as c, isDevelopment as d, isDevAndTest as e, isDevServer as f, isServer as i };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
const isWindowDefined = typeof window !== 'undefined';
|
|
3
|
+
const isDocumentDefined = typeof document !== 'undefined';
|
|
4
|
+
const isServer = !isWindowDefined || !isDocumentDefined;
|
|
5
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
6
|
+
const isDevAndTest = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
|
|
7
|
+
const isDevServer = isDevelopment && isServer;
|
|
8
|
+
const exception = [
|
|
9
|
+
'line-height',
|
|
10
|
+
'font-weight',
|
|
11
|
+
'opacity',
|
|
12
|
+
'scale',
|
|
13
|
+
'z-index',
|
|
14
|
+
'column-count',
|
|
15
|
+
'order',
|
|
16
|
+
'orphans',
|
|
17
|
+
'widows'
|
|
18
|
+
];
|
|
19
|
+
const applyCssValue = (value, cssProp)=>{
|
|
20
|
+
if (typeof value === 'number') {
|
|
21
|
+
return exception.includes(cssProp) ? value.toString() : value + 'px';
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
const camelToKebabCase = (property)=>{
|
|
26
|
+
return property.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const build = async (styleSheet, filePath, global)=>{
|
|
30
|
+
if (!isServer) return;
|
|
31
|
+
const fs = require('fs');
|
|
32
|
+
const { styleText } = require('util');
|
|
33
|
+
const message = global === '--global' ? styleText('underline', `✅Generated global CSS\n\n`) : styleText('underline', `✅Generated create CSS\n\n`);
|
|
34
|
+
try {
|
|
35
|
+
if (fs.existsSync(filePath)) {
|
|
36
|
+
const cssData = fs.readFileSync(filePath, 'utf-8');
|
|
37
|
+
if (!cssData.includes(styleSheet)) {
|
|
38
|
+
fs.appendFileSync(filePath, styleSheet, 'utf-8');
|
|
39
|
+
if (process.argv.includes('--log')) console.log(message + styleSheet);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Error writing to file:', error);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
exports.applyCssValue = applyCssValue;
|
|
49
|
+
exports.build = build;
|
|
50
|
+
exports.camelToKebabCase = camelToKebabCase;
|
|
51
|
+
exports.isDevAndTest = isDevAndTest;
|
|
52
|
+
exports.isDevServer = isDevServer;
|
|
53
|
+
exports.isDevelopment = isDevelopment;
|
|
54
|
+
exports.isServer = isServer;
|
package/dist/index.js
CHANGED
|
@@ -1,32 +1,238 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
|
|
3
|
+
var build12x = require('./build-12x-C7vH1H69.js');
|
|
4
|
+
|
|
5
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
6
|
+
function simpleHash(str) {
|
|
7
|
+
let hash = 0;
|
|
8
|
+
for(let i = 0; i < str.length; i++){
|
|
9
|
+
const char = str.charCodeAt(i);
|
|
10
|
+
hash = (hash << 5) - hash + char;
|
|
7
11
|
}
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
return Math.abs(hash);
|
|
13
|
+
}
|
|
14
|
+
function encodeBase36(num) {
|
|
15
|
+
let result = '';
|
|
16
|
+
do {
|
|
17
|
+
result = chars[num % 36] + result;
|
|
18
|
+
num = Math.floor(num / 36);
|
|
19
|
+
}while (num > 0)
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
function getStartingChar(hash) {
|
|
23
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz';
|
|
24
|
+
return chars[hash % chars.length];
|
|
25
|
+
}
|
|
26
|
+
function genBase36Hash(object, n) {
|
|
27
|
+
const serialized = JSON.stringify(object);
|
|
28
|
+
const hash = simpleHash(serialized);
|
|
29
|
+
let base36Hash = encodeBase36(hash);
|
|
30
|
+
const startingChar = getStartingChar(hash);
|
|
31
|
+
while(base36Hash.length < n - 1){
|
|
32
|
+
base36Hash = chars[hash % chars.length] + base36Hash;
|
|
33
|
+
}
|
|
34
|
+
return startingChar + base36Hash.slice(0, n - 1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const styleSheets$1 = {};
|
|
38
|
+
const hashCache = {};
|
|
39
|
+
function createStyleElement(hash) {
|
|
40
|
+
if (document.getElementById(hash)) return null;
|
|
41
|
+
const styleElement = document.createElement('style');
|
|
42
|
+
styleElement.setAttribute('id', hash);
|
|
43
|
+
styleElement.setAttribute('type', 'text/css');
|
|
44
|
+
styleSheets$1[hash] = styleElement;
|
|
45
|
+
document.head.appendChild(styleElement);
|
|
46
|
+
return styleSheets$1[hash];
|
|
47
|
+
}
|
|
48
|
+
function injectClientCSS(hash, sheet) {
|
|
49
|
+
if (build12x.isServer) return;
|
|
50
|
+
requestAnimationFrame(()=>{
|
|
51
|
+
styleCleanUp();
|
|
52
|
+
});
|
|
53
|
+
hashCache[hash] = hash;
|
|
54
|
+
const styleElement = createStyleElement(hash);
|
|
55
|
+
if (styleElement == null) return;
|
|
56
|
+
styleElement.textContent = sheet;
|
|
57
|
+
}
|
|
58
|
+
function styleCleanUp() {
|
|
59
|
+
requestAnimationFrame(()=>{
|
|
60
|
+
for(const hash in hashCache){
|
|
61
|
+
const classElements = document.querySelectorAll(`[class*="${hash}"]`);
|
|
62
|
+
if (classElements.length === 0) {
|
|
63
|
+
removeStyleElement(hashCache[hash]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function removeStyleElement(hash) {
|
|
69
|
+
if (styleSheets$1[hash]) {
|
|
70
|
+
delete styleSheets$1[hash];
|
|
71
|
+
if (hashCache.hasOwnProperty.call(hashCache, hash)) {
|
|
72
|
+
delete hashCache[hash];
|
|
73
|
+
}
|
|
74
|
+
const styleElement = document.getElementById(hash);
|
|
75
|
+
if (styleElement) {
|
|
76
|
+
document.head.removeChild(styleElement);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function injectClientGlobalCSS(sheet, scoped) {
|
|
82
|
+
if (build12x.isServer) return;
|
|
83
|
+
const existingStyleElement = document.querySelector(`[data-scope="${scoped}"]`);
|
|
84
|
+
if (existingStyleElement instanceof HTMLStyleElement) {
|
|
85
|
+
existingStyleElement.textContent += sheet;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const styleElement = document.createElement('style');
|
|
89
|
+
styleElement.setAttribute('data-scope', scoped);
|
|
90
|
+
styleElement.setAttribute('type', 'text/css');
|
|
91
|
+
styleElement.textContent = sheet;
|
|
92
|
+
document.head.appendChild(styleElement);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const styleSheets = {};
|
|
96
|
+
function injectServerCSS(hash, sheet) {
|
|
97
|
+
styleSheets[hash] = sheet;
|
|
98
|
+
}
|
|
99
|
+
function getServerCSS() {
|
|
100
|
+
return Object.values(styleSheets).join('\n');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const createKeyframes = (property, content)=>{
|
|
104
|
+
let keyframesRules = `${property} {\n`;
|
|
105
|
+
for(const key in content){
|
|
106
|
+
if (Object.prototype.hasOwnProperty.call(content, key)) {
|
|
107
|
+
const keyframeValue = content[key];
|
|
108
|
+
keyframesRules += ` ${key} {\n`;
|
|
109
|
+
for(const prop in keyframeValue){
|
|
110
|
+
if (Object.prototype.hasOwnProperty.call(keyframeValue, prop)) {
|
|
111
|
+
const CSSProp = build12x.camelToKebabCase(prop);
|
|
112
|
+
const value = keyframeValue[prop];
|
|
113
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
114
|
+
const applyValue = build12x.applyCssValue(value, CSSProp);
|
|
115
|
+
keyframesRules += ` ${CSSProp}: ${applyValue};\n`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
keyframesRules += ` }\n`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
keyframesRules += `}\n`;
|
|
123
|
+
return keyframesRules;
|
|
15
124
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
125
|
+
function transpiler(object, base36Hash, core) {
|
|
126
|
+
let styleSheet = '';
|
|
127
|
+
const mediaQueries = [];
|
|
128
|
+
const classNameType = (property)=>{
|
|
129
|
+
return core === '--global' ? property : `.${property}_${base36Hash}`;
|
|
130
|
+
};
|
|
131
|
+
const rules = (indent, rulesValue, property)=>{
|
|
132
|
+
if (typeof property !== 'string') return '';
|
|
133
|
+
const value = rulesValue[property];
|
|
134
|
+
const cssProp = build12x.camelToKebabCase(property);
|
|
135
|
+
return `${indent}${cssProp}: ${value};\n`;
|
|
136
|
+
};
|
|
137
|
+
const stringConverter = (className, properties, indentLevel = 0)=>{
|
|
138
|
+
const classSelector = {};
|
|
139
|
+
const indent = ''.repeat(indentLevel);
|
|
140
|
+
const innerIndent = ' '.repeat(indentLevel + 1);
|
|
141
|
+
let cssRule = '';
|
|
142
|
+
for(const property in properties){
|
|
143
|
+
if (Object.prototype.hasOwnProperty.call(properties, property)) {
|
|
144
|
+
const value = properties[property];
|
|
145
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
146
|
+
let CSSProp = build12x.camelToKebabCase(property);
|
|
147
|
+
if (property.startsWith('ms')) {
|
|
148
|
+
CSSProp = `-${CSSProp}`;
|
|
149
|
+
}
|
|
150
|
+
const applyValue = build12x.applyCssValue(value, CSSProp);
|
|
151
|
+
cssRule += ` ${CSSProp}: ${applyValue};\n`;
|
|
152
|
+
} else if (!property.startsWith('@')) {
|
|
153
|
+
const kebabPseudoSelector = build12x.camelToKebabCase(property.replace('&', ''));
|
|
154
|
+
const styles = stringConverter(className + kebabPseudoSelector, value, indentLevel);
|
|
155
|
+
Object.assign(classSelector, styles);
|
|
156
|
+
} else if (property.startsWith('@media') || property.startsWith('@container')) {
|
|
157
|
+
const mediaRule = property;
|
|
158
|
+
let nestedRules = '';
|
|
159
|
+
let regularRules = '';
|
|
160
|
+
for(const mediaProp in value){
|
|
161
|
+
if (Object.prototype.hasOwnProperty.call(value, mediaProp)) {
|
|
162
|
+
const mediaValue = value[mediaProp];
|
|
163
|
+
const isColon = mediaProp.startsWith(':');
|
|
164
|
+
const isAnd = mediaProp.startsWith('&');
|
|
165
|
+
if (isColon || isAnd) {
|
|
166
|
+
const kebabMediaProp = build12x.camelToKebabCase(mediaProp.replace('&', ''));
|
|
167
|
+
let pseudoClassRule = '';
|
|
168
|
+
if (typeof mediaValue === 'object' && mediaValue !== null) {
|
|
169
|
+
for(const pseudoProp in mediaValue){
|
|
170
|
+
if (Object.prototype.hasOwnProperty.call(mediaValue, pseudoProp)) {
|
|
171
|
+
const CSSProp = build12x.camelToKebabCase(pseudoProp);
|
|
172
|
+
const applyValue = build12x.applyCssValue(mediaValue[pseudoProp], CSSProp);
|
|
173
|
+
pseudoClassRule += rules(innerIndent + ' ', {
|
|
174
|
+
[pseudoProp]: applyValue
|
|
175
|
+
}, pseudoProp);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
nestedRules += `${innerIndent}${className}${kebabMediaProp} {\n${pseudoClassRule}${innerIndent}}\n`;
|
|
180
|
+
} else {
|
|
181
|
+
const CSSProp = build12x.camelToKebabCase(mediaProp);
|
|
182
|
+
const applyValue = build12x.applyCssValue(mediaValue, CSSProp);
|
|
183
|
+
regularRules += rules(innerIndent + ' ', {
|
|
184
|
+
[mediaProp]: applyValue
|
|
185
|
+
}, mediaProp);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (regularRules) {
|
|
190
|
+
mediaQueries.push({
|
|
191
|
+
media: mediaRule,
|
|
192
|
+
css: `${mediaRule} {\n${innerIndent}${className} {\n${regularRules} }\n${nestedRules}${indent}}${indent}\n`
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
mediaQueries.push({
|
|
196
|
+
media: mediaRule,
|
|
197
|
+
css: `${mediaRule} {\n${nestedRules}${indent}}\n`
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
classSelector[className] = cssRule;
|
|
204
|
+
return classSelector;
|
|
205
|
+
};
|
|
206
|
+
for(const property in object){
|
|
207
|
+
if (property.startsWith('@keyframes')) {
|
|
208
|
+
const keyframesContent = object[property];
|
|
209
|
+
styleSheet += createKeyframes(property, keyframesContent);
|
|
210
|
+
}
|
|
211
|
+
const classSelectors = stringConverter(classNameType(property), object[property], 1);
|
|
212
|
+
for(const selector in classSelectors){
|
|
213
|
+
if (!selector.startsWith('@keyframes') && classSelectors[selector]) {
|
|
214
|
+
styleSheet += selector + ' {\n' + classSelectors[selector] + '}\n';
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
mediaQueries.forEach(({ css })=>{
|
|
219
|
+
styleSheet += css;
|
|
220
|
+
});
|
|
221
|
+
return {
|
|
222
|
+
styleSheet
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
exports.applyCssValue = build12x.applyCssValue;
|
|
227
|
+
exports.build = build12x.build;
|
|
228
|
+
exports.camelToKebabCase = build12x.camelToKebabCase;
|
|
229
|
+
exports.isDevAndTest = build12x.isDevAndTest;
|
|
230
|
+
exports.isDevServer = build12x.isDevServer;
|
|
231
|
+
exports.isDevelopment = build12x.isDevelopment;
|
|
232
|
+
exports.isServer = build12x.isServer;
|
|
233
|
+
exports.genBase36Hash = genBase36Hash;
|
|
234
|
+
exports.getServerCSS = getServerCSS;
|
|
235
|
+
exports.injectClientCSS = injectClientCSS;
|
|
236
|
+
exports.injectClientGlobalCSS = injectClientGlobalCSS;
|
|
237
|
+
exports.injectServerCSS = injectServerCSS;
|
|
238
|
+
exports.transpiler = transpiler;
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,225 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { i as isServer, c as camelToKebabCase, a as applyCssValue } from './build-12x-B3dvmUcg.mjs';
|
|
2
|
+
export { b as build, e as isDevAndTest, f as isDevServer, d as isDevelopment } from './build-12x-B3dvmUcg.mjs';
|
|
3
|
+
|
|
4
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
5
|
+
function simpleHash(str) {
|
|
6
|
+
let hash = 0;
|
|
7
|
+
for(let i = 0; i < str.length; i++){
|
|
8
|
+
const char = str.charCodeAt(i);
|
|
9
|
+
hash = (hash << 5) - hash + char;
|
|
10
|
+
}
|
|
11
|
+
return Math.abs(hash);
|
|
12
|
+
}
|
|
13
|
+
function encodeBase36(num) {
|
|
14
|
+
let result = '';
|
|
15
|
+
do {
|
|
16
|
+
result = chars[num % 36] + result;
|
|
17
|
+
num = Math.floor(num / 36);
|
|
18
|
+
}while (num > 0)
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function getStartingChar(hash) {
|
|
22
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz';
|
|
23
|
+
return chars[hash % chars.length];
|
|
24
|
+
}
|
|
25
|
+
function genBase36Hash(object, n) {
|
|
26
|
+
const serialized = JSON.stringify(object);
|
|
27
|
+
const hash = simpleHash(serialized);
|
|
28
|
+
let base36Hash = encodeBase36(hash);
|
|
29
|
+
const startingChar = getStartingChar(hash);
|
|
30
|
+
while(base36Hash.length < n - 1){
|
|
31
|
+
base36Hash = chars[hash % chars.length] + base36Hash;
|
|
32
|
+
}
|
|
33
|
+
return startingChar + base36Hash.slice(0, n - 1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const styleSheets$1 = {};
|
|
37
|
+
const hashCache = {};
|
|
38
|
+
function createStyleElement(hash) {
|
|
39
|
+
if (document.getElementById(hash)) return null;
|
|
40
|
+
const styleElement = document.createElement('style');
|
|
41
|
+
styleElement.setAttribute('id', hash);
|
|
42
|
+
styleElement.setAttribute('type', 'text/css');
|
|
43
|
+
styleSheets$1[hash] = styleElement;
|
|
44
|
+
document.head.appendChild(styleElement);
|
|
45
|
+
return styleSheets$1[hash];
|
|
46
|
+
}
|
|
47
|
+
function injectClientCSS(hash, sheet) {
|
|
48
|
+
if (isServer) return;
|
|
49
|
+
requestAnimationFrame(()=>{
|
|
50
|
+
styleCleanUp();
|
|
51
|
+
});
|
|
52
|
+
hashCache[hash] = hash;
|
|
53
|
+
const styleElement = createStyleElement(hash);
|
|
54
|
+
if (styleElement == null) return;
|
|
55
|
+
styleElement.textContent = sheet;
|
|
56
|
+
}
|
|
57
|
+
function styleCleanUp() {
|
|
58
|
+
requestAnimationFrame(()=>{
|
|
59
|
+
for(const hash in hashCache){
|
|
60
|
+
const classElements = document.querySelectorAll(`[class*="${hash}"]`);
|
|
61
|
+
if (classElements.length === 0) {
|
|
62
|
+
removeStyleElement(hashCache[hash]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function removeStyleElement(hash) {
|
|
68
|
+
if (styleSheets$1[hash]) {
|
|
69
|
+
delete styleSheets$1[hash];
|
|
70
|
+
if (hashCache.hasOwnProperty.call(hashCache, hash)) {
|
|
71
|
+
delete hashCache[hash];
|
|
72
|
+
}
|
|
73
|
+
const styleElement = document.getElementById(hash);
|
|
74
|
+
if (styleElement) {
|
|
75
|
+
document.head.removeChild(styleElement);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function injectClientGlobalCSS(sheet, scoped) {
|
|
81
|
+
if (isServer) return;
|
|
82
|
+
const existingStyleElement = document.querySelector(`[data-scope="${scoped}"]`);
|
|
83
|
+
if (existingStyleElement instanceof HTMLStyleElement) {
|
|
84
|
+
existingStyleElement.textContent += sheet;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const styleElement = document.createElement('style');
|
|
88
|
+
styleElement.setAttribute('data-scope', scoped);
|
|
89
|
+
styleElement.setAttribute('type', 'text/css');
|
|
90
|
+
styleElement.textContent = sheet;
|
|
91
|
+
document.head.appendChild(styleElement);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const styleSheets = {};
|
|
95
|
+
function injectServerCSS(hash, sheet) {
|
|
96
|
+
styleSheets[hash] = sheet;
|
|
97
|
+
}
|
|
98
|
+
function getServerCSS() {
|
|
99
|
+
return Object.values(styleSheets).join('\n');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const createKeyframes = (property, content)=>{
|
|
103
|
+
let keyframesRules = `${property} {\n`;
|
|
104
|
+
for(const key in content){
|
|
105
|
+
if (Object.prototype.hasOwnProperty.call(content, key)) {
|
|
106
|
+
const keyframeValue = content[key];
|
|
107
|
+
keyframesRules += ` ${key} {\n`;
|
|
108
|
+
for(const prop in keyframeValue){
|
|
109
|
+
if (Object.prototype.hasOwnProperty.call(keyframeValue, prop)) {
|
|
110
|
+
const CSSProp = camelToKebabCase(prop);
|
|
111
|
+
const value = keyframeValue[prop];
|
|
112
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
113
|
+
const applyValue = applyCssValue(value, CSSProp);
|
|
114
|
+
keyframesRules += ` ${CSSProp}: ${applyValue};\n`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
keyframesRules += ` }\n`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
keyframesRules += `}\n`;
|
|
122
|
+
return keyframesRules;
|
|
123
|
+
};
|
|
124
|
+
function transpiler(object, base36Hash, core) {
|
|
125
|
+
let styleSheet = '';
|
|
126
|
+
const mediaQueries = [];
|
|
127
|
+
const classNameType = (property)=>{
|
|
128
|
+
return core === '--global' ? property : `.${property}_${base36Hash}`;
|
|
129
|
+
};
|
|
130
|
+
const rules = (indent, rulesValue, property)=>{
|
|
131
|
+
if (typeof property !== 'string') return '';
|
|
132
|
+
const value = rulesValue[property];
|
|
133
|
+
const cssProp = camelToKebabCase(property);
|
|
134
|
+
return `${indent}${cssProp}: ${value};\n`;
|
|
135
|
+
};
|
|
136
|
+
const stringConverter = (className, properties, indentLevel = 0)=>{
|
|
137
|
+
const classSelector = {};
|
|
138
|
+
const indent = ''.repeat(indentLevel);
|
|
139
|
+
const innerIndent = ' '.repeat(indentLevel + 1);
|
|
140
|
+
let cssRule = '';
|
|
141
|
+
for(const property in properties){
|
|
142
|
+
if (Object.prototype.hasOwnProperty.call(properties, property)) {
|
|
143
|
+
const value = properties[property];
|
|
144
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
145
|
+
let CSSProp = camelToKebabCase(property);
|
|
146
|
+
if (property.startsWith('ms')) {
|
|
147
|
+
CSSProp = `-${CSSProp}`;
|
|
148
|
+
}
|
|
149
|
+
const applyValue = applyCssValue(value, CSSProp);
|
|
150
|
+
cssRule += ` ${CSSProp}: ${applyValue};\n`;
|
|
151
|
+
} else if (!property.startsWith('@')) {
|
|
152
|
+
const kebabPseudoSelector = camelToKebabCase(property.replace('&', ''));
|
|
153
|
+
const styles = stringConverter(className + kebabPseudoSelector, value, indentLevel);
|
|
154
|
+
Object.assign(classSelector, styles);
|
|
155
|
+
} else if (property.startsWith('@media') || property.startsWith('@container')) {
|
|
156
|
+
const mediaRule = property;
|
|
157
|
+
let nestedRules = '';
|
|
158
|
+
let regularRules = '';
|
|
159
|
+
for(const mediaProp in value){
|
|
160
|
+
if (Object.prototype.hasOwnProperty.call(value, mediaProp)) {
|
|
161
|
+
const mediaValue = value[mediaProp];
|
|
162
|
+
const isColon = mediaProp.startsWith(':');
|
|
163
|
+
const isAnd = mediaProp.startsWith('&');
|
|
164
|
+
if (isColon || isAnd) {
|
|
165
|
+
const kebabMediaProp = camelToKebabCase(mediaProp.replace('&', ''));
|
|
166
|
+
let pseudoClassRule = '';
|
|
167
|
+
if (typeof mediaValue === 'object' && mediaValue !== null) {
|
|
168
|
+
for(const pseudoProp in mediaValue){
|
|
169
|
+
if (Object.prototype.hasOwnProperty.call(mediaValue, pseudoProp)) {
|
|
170
|
+
const CSSProp = camelToKebabCase(pseudoProp);
|
|
171
|
+
const applyValue = applyCssValue(mediaValue[pseudoProp], CSSProp);
|
|
172
|
+
pseudoClassRule += rules(innerIndent + ' ', {
|
|
173
|
+
[pseudoProp]: applyValue
|
|
174
|
+
}, pseudoProp);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
nestedRules += `${innerIndent}${className}${kebabMediaProp} {\n${pseudoClassRule}${innerIndent}}\n`;
|
|
179
|
+
} else {
|
|
180
|
+
const CSSProp = camelToKebabCase(mediaProp);
|
|
181
|
+
const applyValue = applyCssValue(mediaValue, CSSProp);
|
|
182
|
+
regularRules += rules(innerIndent + ' ', {
|
|
183
|
+
[mediaProp]: applyValue
|
|
184
|
+
}, mediaProp);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (regularRules) {
|
|
189
|
+
mediaQueries.push({
|
|
190
|
+
media: mediaRule,
|
|
191
|
+
css: `${mediaRule} {\n${innerIndent}${className} {\n${regularRules} }\n${nestedRules}${indent}}${indent}\n`
|
|
192
|
+
});
|
|
193
|
+
} else {
|
|
194
|
+
mediaQueries.push({
|
|
195
|
+
media: mediaRule,
|
|
196
|
+
css: `${mediaRule} {\n${nestedRules}${indent}}\n`
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
classSelector[className] = cssRule;
|
|
203
|
+
return classSelector;
|
|
204
|
+
};
|
|
205
|
+
for(const property in object){
|
|
206
|
+
if (property.startsWith('@keyframes')) {
|
|
207
|
+
const keyframesContent = object[property];
|
|
208
|
+
styleSheet += createKeyframes(property, keyframesContent);
|
|
209
|
+
}
|
|
210
|
+
const classSelectors = stringConverter(classNameType(property), object[property], 1);
|
|
211
|
+
for(const selector in classSelectors){
|
|
212
|
+
if (!selector.startsWith('@keyframes') && classSelectors[selector]) {
|
|
213
|
+
styleSheet += selector + ' {\n' + classSelectors[selector] + '}\n';
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
mediaQueries.forEach(({ css })=>{
|
|
218
|
+
styleSheet += css;
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
styleSheet
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export { applyCssValue, camelToKebabCase, genBase36Hash, getServerCSS, injectClientCSS, injectClientGlobalCSS, injectServerCSS, isServer, transpiler };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zss-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"description": "Zero-runtime Style Sheet Engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zero-runtime",
|
|
@@ -23,10 +23,12 @@
|
|
|
23
23
|
"main": "dist/index.js",
|
|
24
24
|
"module": "dist/index.mjs",
|
|
25
25
|
"types": "types/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/",
|
|
28
|
+
"types/"
|
|
29
|
+
],
|
|
26
30
|
"scripts": {
|
|
27
|
-
"build": "
|
|
28
|
-
"cjs": "tsc --project tsconfig.cjs.json",
|
|
29
|
-
"esm": "tsc --project tsconfig.esm.json && node build.esm.js",
|
|
31
|
+
"build": "rimraf dist types && bunchee",
|
|
30
32
|
"test": "jest"
|
|
31
33
|
},
|
|
32
34
|
"dependencies": {
|
|
@@ -34,12 +36,12 @@
|
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
38
|
"@types/jest": "^29.5.14",
|
|
37
|
-
"@types/node": "^22.
|
|
38
|
-
"
|
|
39
|
+
"@types/node": "^22.13.10",
|
|
40
|
+
"bunchee": "^6.4.0",
|
|
39
41
|
"jest": "^29.7.0",
|
|
40
42
|
"jest-environment-jsdom": "^29.7.0",
|
|
41
|
-
"
|
|
43
|
+
"rimraf": "^6.0.1",
|
|
42
44
|
"ts-jest": "^29.2.6",
|
|
43
|
-
"typescript": "^5.
|
|
45
|
+
"typescript": "^5.8.2"
|
|
44
46
|
}
|
|
45
47
|
}
|