Comparing version
@@ -1,9 +0,1 @@ | ||
/** | ||
* Copyright (c) Nicolas Gallagher | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* | ||
*/ | ||
'use strict'; | ||
@@ -15,10 +7,8 @@ | ||
exports.styleq = void 0; | ||
var cache = new WeakMap(); | ||
var compiledKey = '$$css'; | ||
const cache = new WeakMap(); | ||
const compiledKey = '$$css'; | ||
function createStyleq(options) { | ||
var disableCache; | ||
var disableMix; | ||
var transform; | ||
let disableCache; | ||
let disableMix; | ||
let transform; | ||
if (options != null) { | ||
@@ -29,71 +19,51 @@ disableCache = options.disableCache === true; | ||
} | ||
return function styleq() { | ||
// Keep track of property commits to the className | ||
var definedProperties = []; // The className and inline style to build up | ||
var className = ''; | ||
var inlineStyle = null; // The current position in the cache graph | ||
var nextCache = disableCache ? null : cache; // This way of creating an array from arguments is fastest | ||
var styles = new Array(arguments.length); | ||
for (var i = 0; i < arguments.length; i++) { | ||
const definedProperties = []; | ||
let className = ''; | ||
let inlineStyle = null; | ||
let debugString = ''; | ||
let nextCache = disableCache ? null : cache; | ||
const styles = new Array(arguments.length); | ||
for (let i = 0; i < arguments.length; i++) { | ||
styles[i] = arguments[i]; | ||
} // Iterate over styles from last to first | ||
} | ||
while (styles.length > 0) { | ||
var possibleStyle = styles.pop(); // Skip empty items | ||
const possibleStyle = styles.pop(); | ||
if (possibleStyle == null || possibleStyle === false) { | ||
continue; | ||
} // Push nested styles back onto the stack to be processed | ||
} | ||
if (Array.isArray(possibleStyle)) { | ||
for (var _i = 0; _i < possibleStyle.length; _i++) { | ||
styles.push(possibleStyle[_i]); | ||
for (let i = 0; i < possibleStyle.length; i++) { | ||
styles.push(possibleStyle[i]); | ||
} | ||
continue; | ||
} // Process an individual style object | ||
var style = transform != null ? transform(possibleStyle) : possibleStyle; | ||
if (style.$$css) { | ||
// Build up the class names defined by this object | ||
var classNameChunk = ''; // Check the cache to see if we've already done this work | ||
} | ||
const style = transform != null ? transform(possibleStyle) : possibleStyle; | ||
if (style.$$css != null) { | ||
let classNameChunk = ''; | ||
if (nextCache != null && nextCache.has(style)) { | ||
// Cache: read | ||
var cacheEntry = nextCache.get(style); | ||
const cacheEntry = nextCache.get(style); | ||
if (cacheEntry != null) { | ||
classNameChunk = cacheEntry[0]; // $FlowIgnore | ||
classNameChunk = cacheEntry[0]; | ||
debugString = cacheEntry[2]; | ||
definedProperties.push.apply(definedProperties, cacheEntry[1]); | ||
nextCache = cacheEntry[2]; | ||
nextCache = cacheEntry[3]; | ||
} | ||
} // Update the chunks with data from this object | ||
else { | ||
// The properties defined by this object | ||
var definedPropertiesChunk = []; | ||
for (var prop in style) { | ||
var value = style[prop]; | ||
if (prop === compiledKey) continue; // Each property value is used as an HTML class name | ||
// { 'debug.string': 'debug.string', opacity: 's-jskmnoqp' } | ||
} else { | ||
const definedPropertiesChunk = []; | ||
for (const prop in style) { | ||
const value = style[prop]; | ||
if (prop === compiledKey) { | ||
const compiledKeyValue = style[prop]; | ||
if (compiledKeyValue !== true) { | ||
debugString = debugString ? compiledKeyValue + '; ' + debugString : compiledKeyValue; | ||
} | ||
continue; | ||
} | ||
if (typeof value === 'string' || value === null) { | ||
// Only add to chunks if this property hasn't already been seen | ||
if (!definedProperties.includes(prop)) { | ||
definedProperties.push(prop); | ||
if (nextCache != null) { | ||
definedPropertiesChunk.push(prop); | ||
} | ||
if (typeof value === 'string') { | ||
@@ -103,25 +73,16 @@ classNameChunk += classNameChunk ? ' ' + value : value; | ||
} | ||
} // If we encounter a value that isn't a string or `null` | ||
else { | ||
console.error("styleq: ".concat(prop, " typeof ").concat(String(value), " is not \"string\" or \"null\".")); | ||
} else { | ||
console.error(`styleq: ${prop} typeof ${String(value)} is not "string" or "null".`); | ||
} | ||
} // Cache: write | ||
} | ||
if (nextCache != null) { | ||
// Create the next WeakMap for this sequence of styles | ||
var weakMap = new WeakMap(); | ||
nextCache.set(style, [classNameChunk, definedPropertiesChunk, weakMap]); | ||
const weakMap = new WeakMap(); | ||
nextCache.set(style, [classNameChunk, definedPropertiesChunk, debugString, weakMap]); | ||
nextCache = weakMap; | ||
} | ||
} // Order of classes in chunks matches property-iteration order of style | ||
// object. Order of chunks matches passed order of styles from first to | ||
// last (which we iterate over in reverse). | ||
} | ||
if (classNameChunk) { | ||
className = className ? classNameChunk + ' ' + className : classNameChunk; | ||
} | ||
} // ----- DYNAMIC: Process inline style object ----- | ||
else { | ||
} else { | ||
if (disableMix) { | ||
@@ -131,26 +92,19 @@ if (inlineStyle == null) { | ||
} | ||
inlineStyle = Object.assign({}, style, inlineStyle); | ||
} else { | ||
var subStyle = null; | ||
for (var _prop in style) { | ||
var _value = style[_prop]; | ||
if (_value !== undefined) { | ||
if (!definedProperties.includes(_prop)) { | ||
if (_value != null) { | ||
let subStyle = null; | ||
for (const prop in style) { | ||
const value = style[prop]; | ||
if (value !== undefined) { | ||
if (!definedProperties.includes(prop)) { | ||
if (value != null) { | ||
if (inlineStyle == null) { | ||
inlineStyle = {}; | ||
} | ||
if (subStyle == null) { | ||
subStyle = {}; | ||
} | ||
subStyle[_prop] = _value; | ||
subStyle[prop] = value; | ||
} | ||
definedProperties.push(_prop); // Cache is unnecessary overhead if results can't be reused. | ||
definedProperties.push(prop); | ||
nextCache = null; | ||
@@ -160,3 +114,2 @@ } | ||
} | ||
if (subStyle != null) { | ||
@@ -168,10 +121,7 @@ inlineStyle = Object.assign(subStyle, inlineStyle); | ||
} | ||
var styleProps = [className, inlineStyle]; | ||
const styleProps = [className, inlineStyle, debugString]; | ||
return styleProps; | ||
}; | ||
} | ||
var styleq = createStyleq(); | ||
exports.styleq = styleq; | ||
const styleq = exports.styleq = createStyleq(); | ||
styleq.factory = createStyleq; |
{ | ||
"version": "0.1.3", | ||
"version": "0.2.0", | ||
"name": "styleq", | ||
@@ -17,3 +17,5 @@ "main": "styleq.js", | ||
"scripts": { | ||
"benchmark": "node test/benchmark.node.js", | ||
"benchmark:compare": "node benchmark/compare.js", | ||
"benchmark:perf": "npm run build && node benchmark/performance.js", | ||
"benchmark:size": "npm run build && node benchmark/size.js", | ||
"build": "babel src --out-dir dist --config-file ./configs/.babelrc", | ||
@@ -30,16 +32,21 @@ "flow": "flow --flowconfig-name ./configs/.flowconfig", | ||
"devDependencies": { | ||
"@babel/cli": "^7.13.10", | ||
"@babel/core": "^7.15.5", | ||
"@babel/eslint-parser": "^7.15.8", | ||
"@babel/plugin-syntax-flow": "^7.12.13", | ||
"@babel/preset-env": "^7.15.6", | ||
"@babel/preset-flow": "^7.14.5", | ||
"@babel/types": "^7.15.6", | ||
"@babel/cli": "^7.25.9", | ||
"@babel/core": "^7.26.0", | ||
"@babel/eslint-parser": "^7.25.9", | ||
"@babel/preset-env": "^7.25.4", | ||
"@babel/preset-flow": "^7.24.7", | ||
"@babel/types": "^7.26.0", | ||
"babel-plugin-syntax-hermes-parser": "^0.25.0", | ||
"benchmark": "^2.1.4", | ||
"eslint": "^7.32.0", | ||
"eslint-config-prettier": "^7.2.0", | ||
"eslint-plugin-flowtype": "^7.0.0", | ||
"flow-bin": "^0.195.2", | ||
"jest": "^27.2.4", | ||
"prettier": "^2.4.1" | ||
"brotli-size": "^4.0.0", | ||
"eslint": "^8.57.0", | ||
"eslint-config-prettier": "^8.9.0", | ||
"eslint-plugin-ft-flow": "^3.0.7", | ||
"flow-bin": "^0.252.0", | ||
"hermes-eslint": "^0.25.0", | ||
"jest": "^29.7.0", | ||
"prettier": "^3.3.3", | ||
"prettier-plugin-hermes-parser": "0.25.0", | ||
"terser": "^5.3.0", | ||
"yargs": "17.7.2" | ||
}, | ||
@@ -60,4 +67,20 @@ "jest": { | ||
"prettier": { | ||
"singleQuote": true | ||
"plugins": [ | ||
"prettier-plugin-hermes-parser" | ||
], | ||
"singleQuote": true, | ||
"trailingComma": "none", | ||
"overrides": [ | ||
{ | ||
"files": [ | ||
"*.js", | ||
"*.jsx", | ||
"*.flow" | ||
], | ||
"options": { | ||
"parser": "hermes" | ||
} | ||
} | ||
] | ||
} | ||
} |
@@ -37,3 +37,3 @@ # styleQ · [](https://github.com/necolas/styleq/blob/main/LICENSE) [](https://www.npmjs.com/package/styleq) [](https://github.com/necolas/styleq/actions) [](https://github.com/necolas/styleq/blob/master/.github/CONTRIBUTING.md) | ||
* Compiled styles must set the `$$css` property to `true`. | ||
* Compiled styles must set the `$$css` property to `true` for production. And may be a string for development. | ||
* Any style object without the `$$css` property is treated as an **inline style**. | ||
@@ -51,11 +51,17 @@ * Compiled styles must be static for best performance. | ||
$$css: true, | ||
// Debug classes | ||
'debug::file:styles.root': 'debug::file:styles.root', | ||
// Atomic CSS classes | ||
display: 'display-flex-class', | ||
alignItems: 'alignItems-center-class' | ||
} | ||
}, | ||
other: { | ||
// String values for $$css are concatenated and can be used for dev debugging. | ||
// Compilers are encouraged to provide file and line info. | ||
$$css: 'path/to/file:10', | ||
// Atomic CSS classes | ||
display: 'display-flex-class', | ||
alignItems: 'alignItems-center-class' | ||
}, | ||
}; | ||
const [ className, inlineStyle ] = styleq(styles.root, props.style); | ||
const [ className, inlineStyle, dataStyleSrc ] = styleq(styles.root, props.style); | ||
``` | ||
@@ -392,5 +398,5 @@ | ||
### Polyfilling logical properties and values | ||
### Polyfilling features at runtime | ||
A compiler might provide a polyfill for [CSS logical properties and values](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties). Using the `transform` option is one way to implement this functionality. | ||
A compiler might want to provide polyfills or other runtime transforms, e.g., [CSS logical properties and values](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties). Using the `transform` option is one way to implement this kind of functionality. | ||
@@ -439,4 +445,59 @@ Input: | ||
In this case, `useStyleq` is a function defined by the compiler which transforms `$$css` styles into the correct class name for a given writing direction. An example of this transform can be seen in the [`localizeStyle`](./src/transform-localize-style.js) module. Note how care is taken to memoize the transform so that the same result is always used in merges. | ||
In this case, `useStyleq` is a function defined by the compiler which transforms `$$css` styles into the correct class name for a given writing direction. Take care to memoize the transform so that the same result is always used in merges. For example: | ||
```js | ||
const cache = new WeakMap(); | ||
const markerProp = '$$css$localize'; | ||
/** | ||
* The compiler polyfills logical properties and values, generating a class | ||
* name for both writing directions. The style objects are annotated by | ||
* the compiler as needing this runtime transform. The results are memoized. | ||
* | ||
* { '$$css$localize': true, float: [ 'float-left', 'float-right' ] } | ||
* => { float: 'float-left' } | ||
*/ | ||
function compileStyle(style, isRTL) { | ||
// Create a new compiled style for styleq | ||
const compiledStyle = {}; | ||
for (const prop in style) { | ||
if (prop !== markerProp) { | ||
const value = style[prop]; | ||
if (Array.isArray(value)) { | ||
compiledStyle[prop] = isRTL ? value[1] : value[0]; | ||
} else { | ||
compiledStyle[prop] = value; | ||
} | ||
} | ||
} | ||
return compiledStyle; | ||
} | ||
export function localizeStyle(style, isRTL) { | ||
if (style[markerProp] != null) { | ||
const compiledStyleIndex = isRTL ? 1 : 0; | ||
// Check the cache in case we've already seen this object | ||
if (cache.has(style)) { | ||
const cachedStyles = cache.get(style); | ||
let compiledStyle = cachedStyles[compiledStyleIndex]; | ||
if (compiledStyle == null) { | ||
// Update the missing cache entry | ||
compiledStyle = compileStyle(style, isRTL); | ||
cachedStyles[compiledStyleIndex] = compiledStyle; | ||
cache.set(style, cachedStyles); | ||
} | ||
return compiledStyle; | ||
} | ||
// Create a new compiled style for styleq | ||
const compiledStyle = compileStyle(style, isRTL); | ||
const cachedStyles = new Array(2); | ||
cachedStyles[compiledStyleIndex] = compiledStyle; | ||
cache.set(style, cachedStyles); | ||
return compiledStyle; | ||
} | ||
return style; | ||
} | ||
``` | ||
### Implementing utility styles | ||
@@ -443,0 +504,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
556
12.32%26393
-6.58%19
35.71%6
-33.33%132
-45%1
Infinity%