Completely updated React, fixed #11, (hopefully)

This commit is contained in:
2018-03-04 19:11:49 -05:00
parent 6e0afd6e2a
commit 34e5f5139a
13674 changed files with 333464 additions and 473223 deletions

View File

@@ -1,530 +1,594 @@
## 8.1.0 / 2017-067-12
## 9.8.0 / 2018-02-08
- Added webpackbin examples
- Added size-limit tool
- Added SheetsManager
* Remove hyphenation from the core, moved it to jss-camel-case. Now any function values and `rule.prop()` will get hyphenation automatically.
## 9.7.0 / 2018-01-06
* Allow function values return falsy values in order to remove a property.
## 9.6.0 / 2018-01-28
* Added prettier
* Added a new, correct way of handling CSP
## 9.5.1 / 2018-01-08
* Added postinstall script with donation log.
## 9.5.0 / 2018-01-02
* Export `toCssValue` utility function for css-vendor package.
## 9.4.0 / 2017-12-16
* Added array values support when used with function values. It now also supports priority option "!important" (#629)
* Use classNamePrefix option in production mode (#638)
* Added onUpdate to docs and types, now officially supported
* Fixed class names collisions with multiple jss instances (#644)
## 9.3.3 / 2017-11-15
* Added CSS.escape fallback, so that polyfill is not required.
## 9.3.2 / 2017-11-14
* Don't put escaped class names into classes hash
## 9.3.1 / 2017-11-13
* Never use window object directly
## 9.3.0 / 2017-11-13
* Add CSS class name escaping for dev mode also we support emoji now! (#624)
* Added CSP over webpack (#559)
## 9.2.0 / 2017-11-06
* Allow empty rules when option {link: true} is used.
* Simplify internal logic for function values.
* Introduce function rules - similar to function values, now function can return the entire style object.
## 9.1.0 / 2017-10-31
* Added Observable rules. Now not only values can be an observable, but also the entire style object.
## 9.0.0 / 2017-09-30
* Added `SheetsManager.size` getter to get amount of items in `SheetsManager`.
* Refactored `StyleRule.selector` for better performance. Breaking change - it doesn't reregister rule in the classes map any more. It was used mainly in jss-isolate (#419).
* Method `jss.setup()` can now be called multiple times and will merge properly the options. Also it will avoid applying same plugins more than once by comparing the reference (#576).
* Fixed linker, which didn't work if selectors were escaped (#557).
* In production `createGenerateClassName()` option will now produce short selectors and warn about memory leaks. (#546)
* Update flow to v0.54.1.
* Support observable values (#442).
* Warn when dynamic properties update but link: true option is not set (#581)
## 8.1.0 / 2017-07-12
* Added webpackbin examples
* Added size-limit tool
* Added SheetsManager
## 8.0.0 / 2017-06-20
- Option `insertionPoint` can now accept a DOM node
- DOM node provided in `insertionPoint` can be inside of an iframe.
- Warn when an `insertionPoint` was specified but not found in the DOM.
* Option `insertionPoint` can now accept a DOM node
* DOM node provided in `insertionPoint` can be inside of an iframe.
* Warn when an `insertionPoint` was specified but not found in the DOM.
### Breaking changes for users
- Option `generateClassName` which was used in Jss constructor and `Jss.setup` has been removed. A new option is called `createGenerateClassName` which is a factory that returns the old `generateClassName`. We need this to reset counters on SSR for each request.
- Removed default `insertionPoint` value ("jss") in order to have warnings when insertionPoint is not found in the DOM. With the default one we simply don't know when to warn.
* Option `generateClassName` which was used in Jss constructor and `Jss.setup` has been removed. A new option is called `createGenerateClassName` which is a factory that returns the old `generateClassName`. We need this to reset counters on SSR for each request.
* Removed default `insertionPoint` value ("jss") in order to have warnings when insertionPoint is not found in the DOM. With the default one we simply don't know when to warn.
### Potentially breaking changes for plugins
- KeyframeRule has been renamed to KeyframesRule.
- KeyframeRule.type === 'keyframe' => KeyFrames.type === 'keyframes'.
- RegularRule has been renamed to StyleRule
- RegularRule.type === 'regular' => StyleRule.type === 'style'.
- RegularRule.name => RegularRule.key
- ConditionalRule.selector => ConditionalRule.key
- FontFaceRule.selector => FontFaceRule.key
- SimpleRule.name => SimpleRule.key
- ViewportRule.name => ViewportRule.key
- RulesContainer => RuleList
* KeyframeRule has been renamed to KeyframesRule.
* KeyframeRule.type === 'keyframe' => KeyFrames.type === 'keyframes'.
* RegularRule has been renamed to StyleRule
* RegularRule.type === 'regular' => StyleRule.type === 'style'.
* RegularRule.name => RegularRule.key
* ConditionalRule.selector => ConditionalRule.key
* FontFaceRule.selector => FontFaceRule.key
* SimpleRule.name => SimpleRule.key
* ViewportRule.name => ViewportRule.key
* RulesContainer => RuleList
## 7.1.7 / 2017-06-15
- Fix CSS flow types
* Fix CSS flow types
## 7.1.6 / 2017-06-14
- Fix dynamic values for conditional and keyframe rules
* Fix dynamic values for conditional and keyframe rules
## 7.1.5 / 2017-05-28
- Prevent duplicates in the sheets registry (#504)
- Optimize `sheets.add` for a big registry
* Prevent duplicates in the sheets registry (#504)
* Optimize `sheets.add` for a big registry
## 7.1.4 / 2017-05-27
- Fixed undefined rule support (#489)
* Fixed undefined rule support (#489)
## 7.1.3 / 2017-05-26
- Fixes flow error when updating to the latest version (#507)
- Fixes createStyleSheet type definitions error (#495)
- Fixes function values for for nested rules (#500)
* Fixes flow error when updating to the latest version (#507)
* Fixes createStyleSheet type definitions error (#495)
* Fixes function values for for nested rules (#500)
## 7.1.2 / 2017-05-12
- Fixes function values within keyframes (#471)
* Fixes function values within keyframes (#471)
## 7.1.1 / 2017-04-26
- Fixes rendering rules with function values only (#475)
* Fixes rendering rules with function values only (#475)
## 7.1.0 / 2017-04-21
- Support updating specific rule in `sheet.update(name, data)`
* Support updating specific rule in `sheet.update(name, data)`
## 7.0.3 / 2017-04-14
- Fix a bug when dynamically inserted rules disapeared after reattaching the sheet (#438)
* Fix a bug when dynamically inserted rules disapeared after reattaching the sheet (#438)
## 7.0.2 / 2017-04-14
- Remove temporarily jss-isolate from the tests
* Remove temporarily jss-isolate from the tests
## 7.0.1 / 2017-04-14
- Fix `getDynamicStyles` when nested object is in the same styles object (#467)
* Fix `getDynamicStyles` when nested object is in the same styles object (#467)
## 7.0.0 / 2017-04-10
- Perf improvement through removing of JSON.parse(JSON.stringify(style))
- New hook `onProcessStyle`
- New hook `onChangeValue`
* Perf improvement through removing of JSON.parse(JSON.stringify(style))
* New hook `onProcessStyle`
* New hook `onChangeValue`
### Bugfixes
- Run plugins over property names with function values (#441)
- Function values inside of nested rules (#445)
* Run plugins over property names with function values (#441)
* Function values inside of nested rules (#445)
### Breaking changes
- New signature of `generateClassName(rule, sheet)` option.
- Property `rule.originalStyle` is now available through `rule.options.parent.rules.raw[rule.name]`. It is longer but its a better place and is used in plugins only.
- Plugin signature for the hook `onProcessRule` shortcut `jss.use((rule) => {})` is not supported any more. Instead this hook is supported using its full name: `jss.use({onProcessRule: () => {}})`
* New signature of `generateClassName(rule, sheet)` option.
* Property `rule.originalStyle` is now available through `rule.options.parent.rules.raw[rule.name]`. It is longer but its a better place and is used in plugins only.
* Plugin signature for the hook `onProcessRule` shortcut `jss.use((rule) => {})` is not supported any more. Instead this hook is supported using its full name: `jss.use({onProcessRule: () => {}})`
## 6.5.0 / 2017-03-14
- Dynamic Sheets for theming and animations. #356
* Dynamic Sheets for theming and animations. #356
## 6.4.0 / 2017-03-10
- Reintroduced counter based class generation algorithm. #432
* Reintroduced counter based class generation algorithm. #432
## 6.3.0 / 2017-02-16
- Introduced new option `insertionPoint`.
- Reduced amount of files in the package, dropped .npmignore file.
- Removed babel-runtime from the build.
- Added a new hook `onProcessSheet`.
- Started a list of companies/products using JSS, see docs/users.md
* Introduced new option `insertionPoint`.
* Reduced amount of files in the package, dropped .npmignore file.
* Removed babel-runtime from the build.
* Added a new hook `onProcessSheet`.
* Started a list of companies/products using JSS, see docs/users.md
## 6.2.0 / 2017-01-15
- Added @viewport and @-ms-viewport support (used in bootstrap).
* Added @viewport and @-ms-viewport support (used in bootstrap).
## 6.1.1 / 2017-01-04
- Allow sheet.link() call when VirtualRenderer is used.
* Allow sheet.link() call when VirtualRenderer is used.
## 6.1.0 / 2016-12-26
- Add jss-cache to the tests suit.
- Don't run processors on a rule which has been processed already.
- Add test for onCreateRule arguments.
- Add sheet as a second argument to the onProcessRule hook.
* Add jss-cache to the tests suit.
* Don't run processors on a rule which has been processed already.
* Add test for onCreateRule arguments.
* Add sheet as a second argument to the onProcessRule hook.
## 6.0.2 / 2016-12-23
- Call `onCreateRule` for every rule type.
- RulesContainer is now exported for the plugins.
- Using babel-runtime for the lib build now.
- Using webpack 2 now.
- Preparation for the bugfix - nesting within @global (#380)
- Preparation for the bugfix - nested @media inside of a rule inside of @global (#387).
* Call `onCreateRule` for every rule type.
* RulesContainer is now exported for the plugins.
* Using babel-runtime for the lib build now.
* Using webpack 2 now.
* Preparation for the bugfix - nesting within @global (#380)
* Preparation for the bugfix - nested @media inside of a rule inside of @global (#387).
## 6.0.1 / 2016-12-10
- Don't insert empty rules #363.
* Don't insert empty rules #363.
## 6.0.0 / 2016-12-09
- Added flow types.
- Added a new plugins API. It is backwards compatible. See plugins section.
- Perf improvements.
* Added flow types.
* Added a new plugins API. It is backwards compatible. See plugins section.
* Perf improvements.
### Breaking changes
- Option "named" has been removed from JSS core and replaced by a jss-global plugin. From now on global styles are only possible using that plugin.
- Sheets are not added to the sheets registry automatically server-side any more. In order to prevent leaking styles between requests, you now need to create your own SheetsRegistry instance and add sheets to it manually. Make sure to create a new instance for each request. On the client, sheets are still automatically added to the registry.
* Option "named" has been removed from JSS core and replaced by a jss-global plugin. From now on global styles are only possible using that plugin.
* Sheets are not added to the sheets registry automatically server-side any more. In order to prevent leaking styles between requests, you now need to create your own SheetsRegistry instance and add sheets to it manually. Make sure to create a new instance for each request. On the client, sheets are still automatically added to the registry.
## 5.5.6 / 2016-11-03
- test suite
- new is-in-browser detection #305
- warning when using an unknown at-rule
- start using flow #296
* test suite
* new is-in-browser detection #305
* warning when using an unknown at-rule
* start using flow #296
## 5.5.5 / 2016-09-23
- remove rewire from build
- update roadmap
* remove rewire from build
* update roadmap
## 5.5.4 / 2016-09-19
- always use `cssRules.insertRule` when using addRule on attached sheet, mixing them results in weird overwrite of a rule added by insertRule by a media query rendered using text node.
- catch errors from `cssRules.insertRule` and use a warning in development
* always use `cssRules.insertRule` when using addRule on attached sheet, mixing them results in weird overwrite of a rule added by insertRule by a media query rendered using text node.
* catch errors from `cssRules.insertRule` and use a warning in development
## 5.5.3 / 2016-09-19
- add edge browser for browserstack
- fix addRule insertion order from plugins when sheet is attached
- fix @media insertion in IE
* add edge browser for browserstack
* fix addRule insertion order from plugins when sheet is attached
* fix @media insertion in IE
## 5.5.2 / 2016-09-9
- Skip empty values #307
* Skip empty values #307
## 5.5.1 / 2016-09-6
- Fix adding rules during the plugins loop
* Fix adding rules during the plugins loop
## 5.5.0 / 2016-09-6
- Fix wrong order of nested rules #285
- Add `index` option to `sheet.addRule` which allows to specify the order or added rules
- Add `<style>` node position control option `index` and insertion point comment
- Better browser detection by using `is-browser` package
* Fix wrong order of nested rules #285
* Add `index` option to `sheet.addRule` which allows to specify the order or added rules
* Add `<style>` node position control option `index` and insertion point comment
* Better browser detection by using `is-browser` package
## 5.4.0 / 2016-08-15
- More docs
- More benchmarks
- Make sheet.addRule accept options
* More docs
* More benchmarks
* Make sheet.addRule accept options
## 5.3.0 / 2016-08-06
- Added `jss.setup` method which accepts options like the contructor and can be used for presets
- Docs
- Create Rodamap
- Cleanup DomRenderer from IE8 code.
- Fix benchmark, use a new jss instance, because there is sheets registry
* Added `jss.setup` method which accepts options like the contructor and can be used for presets
* Docs
* Create Rodamap
* Cleanup DomRenderer from IE8 code.
* Fix benchmark, use a new jss instance, because there is sheets registry
## 5.2.0 / 2016-07-27
- Added `sheet.deleteRule` #266
* Added `sheet.deleteRule` #266
## 5.1.0 / 2016-07-13
- alternative syntax for space and comma separated values #264
* alternative syntax for space and comma separated values #264
## 5.0.0 / 2016-07-10
- new fallbacks api #256
- rule.applyTo doesn't support fallbacks any more
- support conditionals overwrite upfront #259, #180
- remove compatibility fix for babel 5, now you need to use `var jss = require('jss').default` in ES5
* new fallbacks api #256
* rule.applyTo doesn't support fallbacks any more
* support conditionals overwrite upfront #259, #180
* remove compatibility fix for babel 5, now you need to use `var jss = require('jss').default` in ES5
## 4.0.3 / 2016-07-05
- fixed bug when plugins called twice on createStyleSheet #258
- enable node 7 #248
* fixed bug when plugins called twice on createStyleSheet #258
* enable node 7 #248
## 4.0.2 / 2016-06-28
- allow adding rules to a detached sheet #253
* allow adding rules to a detached sheet #253
## 4.0.1 / 2016-06-23
- fix jss.version in lib
* fix jss.version in lib
## 4.0.0 / 2016-06-23
- user defined classname generation function
- deterministic class names generation
- run plugins separately when creating rules in a batch
* user defined classname generation function
* deterministic class names generation
* run plugins separately when creating rules in a batch
## 3.11.1 / 2016-05-11
- register children of a conditional in sheet.classes #81
* register children of a conditional in sheet.classes #81
## 3.11.0 / 2016-05-06
- added option element to .createStyleSheet #231
* added option element to .createStyleSheet #231
## 3.10.0 / 2016-05-02
- fix multiple @imports
- added benchmarks
- rewrote all tests with mocha
* fix multiple @imports
* added benchmarks
* rewrote all tests with mocha
## 3.9.1 / 2016-04-26
- fix multiple @media in one sheet
* fix multiple @media in one sheet
## 3.9.0 / 2016-04-24
- update linter eslint-config-jss@1.0.0
* update linter eslint-config-jss@1.0.0
## 3.8.0 / 2016-04-24
- added jss.version to the build (Daijiro Wachi)
* added jss.version to the build (Daijiro Wachi)
## 3.7.0 / 2016-04-21
- docs
- font-face rule can now handle array of font-faces (Ken Carpenter)
* docs
* font-face rule can now handle array of font-faces (Ken Carpenter)
## 3.6.3 / 2016-03-12
- fix rule registration in style sheet, previous commits resulted in a selector instead of class nem within sheet.classes map.
* fix rule registration in style sheet, previous commits resulted in a selector instead of class nem within sheet.classes map.
## 3.6.2 / 2016-04-12
- register rule when changed worked by setting selector
* register rule when changed worked by setting selector
## 3.6.1 / 2016-03-11
- Update StyleSheet#rules when modifying selector
* Update StyleSheet#rules when modifying selector
## 3.6.0 / 2016-04-08
- implement selector setter, now Rule#selector can be set, due to the fact not every browser implements selectorText setter, the entire sheet will be rerendered in such browsers. Should be used with caution.
* implement selector setter, now Rule#selector can be set, due to the fact not every browser implements selectorText setter, the entire sheet will be rerendered in such browsers. Should be used with caution.
## 3.5.0 / 2016-04-04
- fixed breaking change, which made exports of 3.4.0 incompatible with 3.3.0
- fix font-face rule type
* fixed breaking change, which made exports of 3.4.0 incompatible with 3.3.0
* fix font-face rule type
## 3.4.0 / 2016-04-03
- added style sheets registry accesible via jss.sheets
- updated babel to version 6
* added style sheets registry accesible via jss.sheets
* updated babel to version 6
## 3.3.0 / 2016-01-31
- fixed bug: nested rule inside of a @media conditional
- new docs
- trim empty rules (@wldcordeiro)
- support node 5 (@nikgraf)
* fixed bug: nested rule inside of a @media conditional
* new docs
* trim empty rules (@wldcordeiro)
* support node 5 (@nikgraf)
## 3.2.0 / 2015-11-27
- jss-debug is deprecated, rule name is inside of generated class name now
- no more "type" option for style sheet, its always set to text/css
- no more "title" option for style sheet, its not a part of the spec http://www.w3.org/TR/html-markup/style.html
- added meta option, now you can for e.g. set the name of your component and find it on style element.
- fixed bug when multiple conditionals used in one sheet
* jss-debug is deprecated, rule name is inside of generated class name now
* no more "type" option for style sheet, its always set to text/css
* no more "title" option for style sheet, its not a part of the spec http://www.w3.org/TR/html-markup/style.html
* added meta option, now you can for e.g. set the name of your component and find it on style element.
* fixed bug when multiple conditionals used in one sheet
## 3.1.1 / 2015-11-14
- added Rule#originalStyle property to access original style object from a plugin
* added Rule#originalStyle property to access original style object from a plugin
## 3.1.0 / 2015-11-12
- new testing infrastructure with browserstack and codeship
* new testing infrastructure with browserstack and codeship
## 3.0.0 / 2015-10-19
- internal rewrite for cleaner code (ConditionalRule, KeyframeRule, SimpleRule)
- moved all DOM related methods to dom.js module
- now child rules exist only in ConditionalRule, simplified Rule and StyleSheet logic
- fixed Named rules not generating when using @media only #81
- added support for @charset, @import, @namespace, @supports
- removed jss.Rule from public access, use jss.createRule() instead
- removed jss.Jss from public access, use jss.create() instead
- removed jss.StyleSheet from public access, use jss.createStyleSheet() instead
* internal rewrite for cleaner code (ConditionalRule, KeyframeRule, SimpleRule)
* moved all DOM related methods to dom.js module
* now child rules exist only in ConditionalRule, simplified Rule and StyleSheet logic
* fixed Named rules not generating when using @media only #81
* added support for @charset, @import, @namespace, @supports
* removed jss.Rule from public access, use jss.createRule() instead
* removed jss.Jss from public access, use jss.create() instead
* removed jss.StyleSheet from public access, use jss.createStyleSheet() instead
## 2.3.4 / 2015-09-21
- remove bower.json
- remove dist from repository
- add dist to npm package
- add cdnjs support
* remove bower.json
* remove dist from repository
* add dist to npm package
* add cdnjs support
## 2.3.3 / 2015-09-20
- remove xpkg, update npmignore and ingore list for bower
* remove xpkg, update npmignore and ingore list for bower
## 2.3.2 / 2015-09-19
- reference rule name on the rule instance to fix jss-debug
* reference rule name on the rule instance to fix jss-debug
## 2.3.1 / 2015-09-15
- use eslint-config-jss
* use eslint-config-jss
## 2.3.0 / 2015-09-10
- migrate to es6
- move examples to jss-examples repository
* migrate to es6
* move examples to jss-examples repository
## 2.2.1 / 2015-09-6
- remove @media from classes hash
* remove @media from classes hash
## 2.2.0 / 2015-09-6
- added support for named at-rules e.g. @media
* added support for named at-rules e.g. @media
## 2.1.6 / 2015-09-2
- removed invalid characters
* removed invalid characters
## 2.1.5 / 2015-08-20
- stop mutating original rules passed by user. expecting style to be a plaing object.
* stop mutating original rules passed by user. expecting style to be a plaing object.
## 2.1.4 / 2015-07-31
- add internal method uid.reset() for testing
* add internal method uid.reset() for testing
## 2.1.3 / 2015-07-31
- rename global reference to globalReference
* rename global reference to globalReference
## 2.1.2 / 2015-07-28
- avoid conflicts of jss ids when multiple jss versions are used on the same page
* avoid conflicts of jss ids when multiple jss versions are used on the same page
## 2.1.1 / 2015-07-20
- remove browser field from package.json, it makes webpack use dist version instead of src.
* remove browser field from package.json, it makes webpack use dist version instead of src.
## 2.1.0 / 2015-07-18
- create Jss constructor so that we can have multiple jss instances with different plugins, needed when you want to reuse jss lib from different standalone components which have own jss configuration and should not clash.
* create Jss constructor so that we can have multiple jss instances with different plugins, needed when you want to reuse jss lib from different standalone components which have own jss configuration and should not clash.
## 2.0.0 / 2015-06-17
- create jss-cli package, remove bin script from jss
* create jss-cli package, remove bin script from jss
## 1.0.8 / 2015-03-16
- fix bower package name
- make change condition to include any non-null value in Rule#prop (Stephen Saunders)
* fix bower package name
* make change condition to include any non-null value in Rule#prop (Stephen Saunders)
## 1.0.7 / 2015-02-26
- remove NO-BREAK SPACE chars
* remove NO-BREAK SPACE chars
## 1.0.6 / 2015-02-24
- add rule.toJSON()
* add rule.toJSON()
## 1.0.5 / 2015-02-17
- support any node version above 0.8
* support any node version above 0.8
## 1.0.4 / 2015-02-6
- allow rule options to be passed in internal rule#addRule method to allow nested rules to have different options than parent one (for now just "named")
* allow rule options to be passed in internal rule#addRule method to allow nested rules to have different options than parent one (for now just "named")
## 1.0.3 / 2015-01-31
- pass rule name to make debug plugin possible
* pass rule name to make debug plugin possible
## 1.0.2 / 2015-01-31
- fix duplicated rule rendering
* fix duplicated rule rendering
## 1.0.1 / 2015-01-31
- run plugins on inner rules of at-rules
* run plugins on inner rules of at-rules
## 1.0.0 / 2015-01-31
- styles have named: true option by default, this is backwards incompatible
- at-rules like @media can now also have named rules
* styles have named: true option by default, this is backwards incompatible
* at-rules like @media can now also have named rules
## 0.10.2 / 2015-01-31
- fixed #40 there is no colons in all at-rules with nested declarations
* fixed #40 there is no colons in all at-rules with nested declarations
## 0.10.1 / 2014-12-21
- fixed firefox issues
* fixed firefox issues
## 0.10.0 / 2014-12-21
- added rule.prop() for dynamic rule properties #15
* added rule.prop() for dynamic rule properties #15
## 0.9.0 / 2014-12-21
- added Rule#prop() for setting and getting rule props dynamically
- added `link` option in order to make .prop() work but still without to add perf overhead by default.
- added example for .prop()
* added Rule#prop() for setting and getting rule props dynamically
* added `link` option in order to make .prop() work but still without to add perf overhead by default.
* added example for .prop()
## 0.8.2 / 2014-12-17
- added build for "support non browser env #12"
- added calendar example
* added build for "support non browser env #12"
* added calendar example
## 0.8.1 / 2014-11-29
- supported non browser env #12
* supported non browser env #12
## 0.8.0 / 2014-11-29
- renamed Stylesheet to StyleSheet because its wrong.
* renamed Stylesheet to StyleSheet because its wrong.
## 0.7.0 / 2014-11-29
- moved jss to separate github organization
- moved all plugins to separate repositories (don't force people use plugins they don't need)
* moved jss to separate github organization
* moved all plugins to separate repositories (don't force people use plugins they don't need)
## 0.6.0 / 2014-11-28
- renamed processors to plugins
- added public .use function for registering plugins
* renamed processors to plugins
* added public .use function for registering plugins
## 0.5.0 / 2014-11-27
- supported multiple declarations with identical property names #22
* supported multiple declarations with identical property names #22
## 0.4.0 / 2014-11-23
- supported nested rules when using .addRule method #20
* supported nested rules when using .addRule method #20
## 0.3.2 / 2014-11-19
- rewrittn prefixer for feature testing using camel cased version because of firefox
* rewrittn prefixer for feature testing using camel cased version because of firefox
## 0.3.0 / 2014-11-19
- added vendor prefixes plugin for properties #21
* added vendor prefixes plugin for properties #21
## 0.2.10 / 2014-11-10
- supported nested extend
- added more complex topcoat example
* supported nested extend
* added more complex topcoat example
## 0.2.9 / 2014-11-03
- added @keyframes and @media support #16
* added @keyframes and @media support #16
## 0.2.8 / 2014-11-02
- added possibility write multi nested selector in one line #18
* added possibility write multi nested selector in one line #18
## 0.2.7 / 2014-11-02
- added @font-face to cli converter
- added @keyframes to cli converter
* added @font-face to cli converter
* added @keyframes to cli converter
## 0.2.6 / 2014-11-02
- createed perf comparence for bootstrap #13
* createed perf comparence for bootstrap #13
## 0.2.5 / 2014-11-02
- createed css->jss converter #11
* createed css->jss converter #11
## 0.2.4 / 2014-11-01
- made tests runnable from githubs gh-pages http://jsstyles.github.io/jss/test/
* made tests runnable from githubs gh-pages http://jsstyles.github.io/jss/test/
## 0.2.3 / 2014-11-01
- fixed test failing in firefox #14
* fixed test failing in firefox #14
## 0.2.2 / 2014-11-01
- Renamed param "generateClasses" to "named" in createStyleSheet
- If `named` is true, ss.rules[name] is accessible using the name.
- ss.addRules will render new rules after style element has been rendered too.
- document ss.addRules
* Renamed param "generateClasses" to "named" in createStyleSheet
* If `named` is true, ss.rules[name] is accessible using the name.
* ss.addRules will render new rules after style element has been rendered too.
* document ss.addRules
## 0.2.1 / 2014-10-29

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -23,7 +23,7 @@ declare interface CSSRuleBase<T> {
static REGION_STYLE_RULE: 16;
}
declare interface CSSStyleRule extends CSSRuleBase<{type: 1|1}> {
declare interface CSSStyleRule extends CSSRuleBase<{type: 1 | 1}> {
+type: 1;
+style: CSSStyleDeclaration;
selectorText: DOMString;
@@ -40,13 +40,13 @@ declare interface CSSGroupingRule<T> extends CSSRuleBase<T> {
deleteRule(index: number): void;
}
declare interface CSSKeyframeRule extends CSSRuleBase<{type: 8|8}> {
declare interface CSSKeyframeRule extends CSSRuleBase<{type: 8 | 8}> {
+type: 8;
+style: CSSStyleDeclaration;
keyText: DOMString;
}
declare interface CSSKeyframesRule extends CSSRuleBase<{type: 7|7}> {
declare interface CSSKeyframesRule extends CSSRuleBase<{type: 7 | 7}> {
+type: 7;
+cssRules: CSSRuleList;
name: DOMString;
@@ -55,7 +55,7 @@ declare interface CSSKeyframesRule extends CSSRuleBase<{type: 7|7}> {
findRule(key: DOMString): CSSKeyframeRule;
}
declare interface CSSMediaRule extends CSSGroupingRule<{type: 4|4}> {
declare interface CSSMediaRule extends CSSGroupingRule<{type: 4 | 4}> {
+type: 4;
+mediaList: {
+mediaText: DOMString,
@@ -63,10 +63,7 @@ declare interface CSSMediaRule extends CSSGroupingRule<{type: 4|4}> {
item?: DOMString,
appendMedium(medium: DOMString): void,
deleteMedium(medium: DOMString): void
}
};
}
declare type CSSOMRule =
| CSSStyleRule
| CSSMediaRule
| CSSKeyframesRule
declare type CSSOMRule = CSSStyleRule | CSSMediaRule | CSSKeyframesRule

View File

@@ -10,6 +10,10 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _isInBrowser = require('is-in-browser');
var _isInBrowser2 = _interopRequireDefault(_isInBrowser);
var _StyleSheet = require('./StyleSheet');
var _StyleSheet2 = _interopRequireDefault(_StyleSheet);
@@ -22,10 +26,22 @@ var _rules = require('./plugins/rules');
var _rules2 = _interopRequireDefault(_rules);
var _observables = require('./plugins/observables');
var _observables2 = _interopRequireDefault(_observables);
var _functions = require('./plugins/functions');
var _functions2 = _interopRequireDefault(_functions);
var _sheets = require('./sheets');
var _sheets2 = _interopRequireDefault(_sheets);
var _StyleRule = require('./rules/StyleRule');
var _StyleRule2 = _interopRequireDefault(_StyleRule);
var _createGenerateClassName = require('./utils/createGenerateClassName');
var _createGenerateClassName2 = _interopRequireDefault(_createGenerateClassName);
@@ -34,23 +50,38 @@ var _createRule2 = require('./utils/createRule');
var _createRule3 = _interopRequireDefault(_createRule2);
var _findRenderer = require('./utils/findRenderer');
var _DomRenderer = require('./renderers/DomRenderer');
var _findRenderer2 = _interopRequireDefault(_findRenderer);
var _DomRenderer2 = _interopRequireDefault(_DomRenderer);
var _VirtualRenderer = require('./renderers/VirtualRenderer');
var _VirtualRenderer2 = _interopRequireDefault(_VirtualRenderer);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var defaultPlugins = _rules2['default'].concat([_observables2['default'], _functions2['default']]);
var instanceCounter = 0;
var Jss = function () {
function Jss(options) {
_classCallCheck(this, Jss);
this.version = "8.1.0";
this.id = instanceCounter++;
this.version = "9.8.0";
this.plugins = new _PluginsRegistry2['default']();
this.options = {
createGenerateClassName: _createGenerateClassName2['default'],
Renderer: _isInBrowser2['default'] ? _DomRenderer2['default'] : _VirtualRenderer2['default'],
plugins: []
};
this.generateClassName = (0, _createGenerateClassName2['default'])();
// eslint-disable-next-line prefer-spread
this.use.apply(this, _rules2['default']);
this.use.apply(this, defaultPlugins);
this.setup(options);
}
@@ -59,13 +90,20 @@ var Jss = function () {
value: function setup() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var createGenerateClassName = options.createGenerateClassName || _createGenerateClassName2['default'];
this.generateClassName = createGenerateClassName();
this.options = _extends({}, options, {
createGenerateClassName: createGenerateClassName,
Renderer: (0, _findRenderer2['default'])(options)
// eslint-disable-next-line prefer-spread
});if (options.plugins) this.use.apply(this, options.plugins);
if (options.createGenerateClassName) {
this.options.createGenerateClassName = options.createGenerateClassName;
// $FlowFixMe
this.generateClassName = options.createGenerateClassName();
}
if (options.insertionPoint != null) this.options.insertionPoint = options.insertionPoint;
if (options.virtual || options.Renderer) {
this.options.Renderer = options.Renderer || (options.virtual ? _VirtualRenderer2['default'] : _DomRenderer2['default']);
}
// eslint-disable-next-line prefer-spread
if (options.plugins) this.use.apply(this, options.plugins);
return this;
}
@@ -90,6 +128,7 @@ var Jss = function () {
index: index
}));
this.plugins.onProcessSheet(sheet);
return sheet;
}
@@ -131,6 +170,11 @@ var Jss = function () {
if (!ruleOptions.generateClassName) ruleOptions.generateClassName = this.generateClassName;
if (!ruleOptions.classes) ruleOptions.classes = {};
var rule = (0, _createRule3['default'])(name, style, ruleOptions);
if (!ruleOptions.selector && rule instanceof _StyleRule2['default']) {
rule.selector = '.' + ruleOptions.generateClassName(rule);
}
this.plugins.onProcessRule(rule);
return rule;
@@ -150,8 +194,13 @@ var Jss = function () {
}
plugins.forEach(function (plugin) {
return _this.plugins.use(plugin);
// Avoids applying same plugin twice, at least based on ref.
if (_this.options.plugins.indexOf(plugin) === -1) {
_this.options.plugins.push(plugin);
_this.plugins.use(plugin);
}
});
return this;
}
}]);

View File

@@ -1,11 +1,16 @@
/* @flow */
import isInBrowser from 'is-in-browser'
import StyleSheet from './StyleSheet'
import PluginsRegistry from './PluginsRegistry'
import rulesPlugins from './plugins/rules'
import observablesPlugin from './plugins/observables'
import functionsPlugin from './plugins/functions'
import sheets from './sheets'
import StyleRule from './rules/StyleRule'
import createGenerateClassNameDefault from './utils/createGenerateClassName'
import createRule from './utils/createRule'
import findRenderer from './utils/findRenderer'
import DomRenderer from './renderers/DomRenderer'
import VirtualRenderer from './renderers/VirtualRenderer'
import type {
Rule,
RuleFactoryOptions,
@@ -20,40 +25,58 @@ import type {
declare var __VERSION__: string
const defaultPlugins = rulesPlugins.concat([observablesPlugin, functionsPlugin])
let instanceCounter = 0
export default class Jss {
id = instanceCounter++
version = __VERSION__
plugins = new PluginsRegistry()
options: InternalJssOptions
options: InternalJssOptions = {
createGenerateClassName: createGenerateClassNameDefault,
Renderer: isInBrowser ? DomRenderer : VirtualRenderer,
plugins: []
}
generateClassName: generateClassName
generateClassName: generateClassName = createGenerateClassNameDefault()
constructor(options?: JssOptions) {
// eslint-disable-next-line prefer-spread
this.use.apply(this, rulesPlugins)
this.use.apply(this, defaultPlugins)
this.setup(options)
}
setup(options?: JssOptions = {}): this {
const createGenerateClassName =
options.createGenerateClassName ||
createGenerateClassNameDefault
this.generateClassName = createGenerateClassName()
this.options = {
...options,
createGenerateClassName,
Renderer: findRenderer(options)
if (options.createGenerateClassName) {
this.options.createGenerateClassName = options.createGenerateClassName
// $FlowFixMe
this.generateClassName = options.createGenerateClassName()
}
if (options.insertionPoint != null)
this.options.insertionPoint = options.insertionPoint
if (options.virtual || options.Renderer) {
this.options.Renderer =
options.Renderer || (options.virtual ? VirtualRenderer : DomRenderer)
}
// eslint-disable-next-line prefer-spread
if (options.plugins) this.use.apply(this, options.plugins)
return this
}
/**
* Create a Style Sheet.
*/
createStyleSheet(styles: Object, options: StyleSheetFactoryOptions = {}): StyleSheet {
createStyleSheet(
styles: Object,
options: StyleSheetFactoryOptions = {}
): StyleSheet {
let index = options.index
if (typeof index !== 'number') {
index = sheets.index === 0 ? 0 : sheets.index + 1
@@ -67,6 +90,7 @@ export default class Jss {
index
})
this.plugins.onProcessSheet(sheet)
return sheet
}
@@ -82,7 +106,11 @@ export default class Jss {
/**
* Create a rule without a Style Sheet.
*/
createRule(name?: string, style?: JssStyle = {}, options?: RuleFactoryOptions = {}): Rule {
createRule(
name?: string,
style?: JssStyle = {},
options?: RuleFactoryOptions = {}
): Rule {
// Enable rule without name for inline styles.
if (typeof name === 'object') {
options = style
@@ -96,9 +124,15 @@ export default class Jss {
ruleOptions.jss = this
ruleOptions.Renderer = this.options.Renderer
if (!ruleOptions.generateClassName) ruleOptions.generateClassName = this.generateClassName
if (!ruleOptions.generateClassName)
ruleOptions.generateClassName = this.generateClassName
if (!ruleOptions.classes) ruleOptions.classes = {}
const rule = createRule(name, style, ruleOptions)
if (!ruleOptions.selector && rule instanceof StyleRule) {
rule.selector = `.${ruleOptions.generateClassName(rule)}`
}
this.plugins.onProcessRule(rule)
return rule
@@ -108,7 +142,14 @@ export default class Jss {
* Register plugin. Passed function will be invoked with a rule instance.
*/
use(...plugins: Array<Plugin>): this {
plugins.forEach(plugin => this.plugins.use(plugin))
plugins.forEach(plugin => {
// Avoids applying same plugin twice, at least based on ref.
if (this.options.plugins.indexOf(plugin) === -1) {
this.options.plugins.push(plugin)
this.plugins.use(plugin)
}
})
return this
}
}

View File

@@ -23,7 +23,8 @@ var PluginsRegistry = function () {
onProcessRule: [],
onProcessStyle: [],
onProcessSheet: [],
onChangeValue: []
onChangeValue: [],
onUpdate: []
/**
* Call `onCreateRule` hooks and return an object if returned by a hook.
@@ -89,6 +90,18 @@ var PluginsRegistry = function () {
}
}
/**
* Call `onUpdate` hooks.
*/
}, {
key: 'onUpdate',
value: function onUpdate(data, rule, sheet) {
for (var i = 0; i < this.hooks.onUpdate.length; i++) {
this.hooks.onUpdate[i](data, rule, sheet);
}
}
/**
* Call `onChangeValue` hooks.
*/

View File

@@ -9,13 +9,18 @@ export default class PluginsRegistry {
onProcessRule: [],
onProcessStyle: [],
onProcessSheet: [],
onChangeValue: []
onChangeValue: [],
onUpdate: []
}
/**
* Call `onCreateRule` hooks and return an object if returned by a hook.
*/
onCreateRule(name?: string, decl: JssStyle, options: RuleOptions): Rule|null {
onCreateRule(
name?: string,
decl: JssStyle,
options: RuleOptions
): Rule | null {
for (let i = 0; i < this.hooks.onCreateRule.length; i++) {
const rule = this.hooks.onCreateRule[i](name, decl, options)
if (rule) return rule
@@ -61,6 +66,15 @@ export default class PluginsRegistry {
}
}
/**
* Call `onUpdate` hooks.
*/
onUpdate(data: Object, rule: Rule, sheet: StyleSheet): void {
for (let i = 0; i < this.hooks.onUpdate.length; i++) {
this.hooks.onUpdate[i](data, rule, sheet)
}
}
/**
* Call `onChangeValue` hooks.
*/

View File

@@ -12,10 +12,6 @@ var _createRule = require('./utils/createRule');
var _createRule2 = _interopRequireDefault(_createRule);
var _updateRule = require('./utils/updateRule');
var _updateRule2 = _interopRequireDefault(_updateRule);
var _linkRule = require('./utils/linkRule');
var _linkRule2 = _interopRequireDefault(_linkRule);
@@ -24,6 +20,10 @@ var _StyleRule = require('./rules/StyleRule');
var _StyleRule2 = _interopRequireDefault(_StyleRule);
var _escape = require('./utils/escape');
var _escape2 = _interopRequireDefault(_escape);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
@@ -79,12 +79,22 @@ var RuleList = function () {
generateClassName: generateClassName
}, options);
if (!options.selector && this.classes[name]) options.selector = '.' + this.classes[name];
if (!options.selector && this.classes[name]) {
options.selector = '.' + (0, _escape2['default'])(this.classes[name]);
}
this.raw[name] = decl;
var rule = (0, _createRule2['default'])(name, decl, options);
this.register(rule);
var className = void 0;
if (!options.selector && rule instanceof _StyleRule2['default']) {
className = generateClassName(rule, sheet);
rule.selector = '.' + (0, _escape2['default'])(className);
}
this.register(rule, className);
var index = options.index === undefined ? this.index.length : options.index;
this.index.splice(index, 0, rule);
@@ -143,11 +153,11 @@ var RuleList = function () {
}, {
key: 'register',
value: function register(rule) {
value: function register(rule, className) {
this.map[rule.key] = rule;
if (rule instanceof _StyleRule2['default']) {
this.map[rule.selector] = rule;
this.classes[rule.key] = rule.selector.substr(1);
if (className) this.classes[rule.key] = className;
}
}
@@ -159,8 +169,10 @@ var RuleList = function () {
key: 'unregister',
value: function unregister(rule) {
delete this.map[rule.key];
delete this.classes[rule.key];
if (rule instanceof _StyleRule2['default']) delete this.map[rule.selector];
if (rule instanceof _StyleRule2['default']) {
delete this.map[rule.selector];
delete this.classes[rule.key];
}
}
/**
@@ -170,13 +182,17 @@ var RuleList = function () {
}, {
key: 'update',
value: function update(name, data) {
var _options2 = this.options,
plugins = _options2.jss.plugins,
sheet = _options2.sheet;
if (typeof name === 'string') {
(0, _updateRule2['default'])(this.get(name), data, RuleList);
plugins.onUpdate(data, this.get(name), sheet);
return;
}
for (var index = 0; index < this.index.length; index++) {
(0, _updateRule2['default'])(this.index[index], name, RuleList);
plugins.onUpdate(name, this.index[index], sheet);
}
}
@@ -187,9 +203,13 @@ var RuleList = function () {
}, {
key: 'link',
value: function link(cssRules) {
var map = this.options.sheet.renderer.getUnescapedKeysMap(this.index);
for (var i = 0; i < cssRules.length; i++) {
var cssRule = cssRules[i];
var rule = this.get(this.options.sheet.renderer.getSelector(cssRule));
var _key = this.options.sheet.renderer.getKey(cssRule);
if (map[_key]) _key = map[_key];
var rule = this.map[_key];
if (rule) (0, _linkRule2['default'])(rule, cssRule);
}
}
@@ -202,13 +222,16 @@ var RuleList = function () {
key: 'toString',
value: function toString(options) {
var str = '';
var sheet = this.options.sheet;
var link = sheet ? sheet.options.link : false;
for (var index = 0; index < this.index.length; index++) {
var rule = this.index[index];
var css = rule.toString(options);
// No need to render an empty rule.
if (!css) continue;
if (!css && !link) continue;
if (str) str += '\n';
str += css;

View File

@@ -1,6 +1,5 @@
/* @flow */
import createRule from './utils/createRule'
import updateRule from './utils/updateRule'
import linkRule from './utils/linkRule'
import StyleRule from './rules/StyleRule'
import type {
@@ -10,6 +9,7 @@ import type {
RuleOptions,
JssStyle
} from './types'
import escape from './utils/escape'
/**
* Contains rules objects and allows adding/removing etc.
@@ -53,14 +53,25 @@ export default class RuleList {
...options
}
if (!options.selector && this.classes[name]) options.selector = `.${this.classes[name]}`
if (!options.selector && this.classes[name]) {
options.selector = `.${escape(this.classes[name])}`
}
this.raw[name] = decl
const rule = createRule(name, decl, options)
this.register(rule)
const index = options.index === undefined ? this.index.length : options.index
let className
if (!options.selector && rule instanceof StyleRule) {
className = generateClassName(rule, sheet)
rule.selector = `.${escape(className)}`
}
this.register(rule, className)
const index =
options.index === undefined ? this.index.length : options.index
this.index.splice(index, 0, rule)
return rule
@@ -101,11 +112,11 @@ export default class RuleList {
/**
* Register a rule in `.map` and `.classes` maps.
*/
register(rule: Rule): void {
register(rule: Rule, className?: string): void {
this.map[rule.key] = rule
if (rule instanceof StyleRule) {
this.map[rule.selector] = rule
this.classes[rule.key] = rule.selector.substr(1)
if (className) this.classes[rule.key] = className
}
}
@@ -114,21 +125,24 @@ export default class RuleList {
*/
unregister(rule: Rule): void {
delete this.map[rule.key]
delete this.classes[rule.key]
if (rule instanceof StyleRule) delete this.map[rule.selector]
if (rule instanceof StyleRule) {
delete this.map[rule.selector]
delete this.classes[rule.key]
}
}
/**
* Update the function values with a new data.
*/
update(name?: string, data?: Object): void {
update(name?: string | Object, data?: Object): void {
const {jss: {plugins}, sheet} = this.options
if (typeof name === 'string') {
updateRule(this.get(name), data, RuleList)
plugins.onUpdate(data, this.get(name), sheet)
return
}
for (let index = 0; index < this.index.length; index++) {
updateRule(this.index[index], name, RuleList)
plugins.onUpdate(name, this.index[index], sheet)
}
}
@@ -136,9 +150,13 @@ export default class RuleList {
* Link renderable rules with CSSRuleList.
*/
link(cssRules: CSSRuleList): void {
const map = this.options.sheet.renderer.getUnescapedKeysMap(this.index)
for (let i = 0; i < cssRules.length; i++) {
const cssRule = cssRules[i]
const rule = this.get(this.options.sheet.renderer.getSelector(cssRule))
let key = this.options.sheet.renderer.getKey(cssRule)
if (map[key]) key = map[key]
const rule = this.map[key]
if (rule) linkRule(rule, cssRule)
}
}
@@ -148,13 +166,15 @@ export default class RuleList {
*/
toString(options?: ToCssOptions): string {
let str = ''
const {sheet} = this.options
const link = sheet ? sheet.options.link : false
for (let index = 0; index < this.index.length; index++) {
const rule = this.index[index]
const css = rule.toString(options)
// No need to render an empty rule.
if (!css) continue
if (!css && !link) continue
if (str) str += '\n'
str += css

View File

@@ -66,7 +66,7 @@ var SheetsManager = function () {
var index = this.keys.indexOf(key);
if (index === -1) {
// eslint-ignore-next-line no-console
(0, _warning2['default'])('SheetsManager: can\'t find sheet to unmanage');
(0, _warning2['default'])(false, "SheetsManager: can't find sheet to unmanage");
return;
}
if (this.refs[index] > 0) {
@@ -74,6 +74,11 @@ var SheetsManager = function () {
if (this.refs[index] === 0) this.sheets[index].detach();
}
}
}, {
key: 'size',
get: function get() {
return this.keys.length;
}
}]);
return SheetsManager;

View File

@@ -13,6 +13,10 @@ export default class SheetsManager {
keys: Array<Object> = []
get size(): number {
return this.keys.length
}
get(key: Object): StyleSheet {
const index = this.keys.indexOf(key)
return this.sheets[index]
@@ -44,7 +48,7 @@ export default class SheetsManager {
const index = this.keys.indexOf(key)
if (index === -1) {
// eslint-ignore-next-line no-console
warn('SheetsManager: can\'t find sheet to unmanage')
warn(false, "SheetsManager: can't find sheet to unmanage")
return
}
if (this.refs[index] > 0) {

View File

@@ -12,7 +12,9 @@ export default class SheetsRegistry {
* Current highest index number.
*/
get index(): number {
return this.registry.length === 0 ? 0 : this.registry[this.registry.length - 1].options.index
return this.registry.length === 0
? 0
: this.registry[this.registry.length - 1].options.index
}
/**

View File

@@ -3,7 +3,7 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.create = exports.sheets = exports.RuleList = exports.SheetsManager = exports.SheetsRegistry = exports.getDynamicStyles = undefined;
exports.create = exports.createGenerateClassName = exports.sheets = exports.RuleList = exports.SheetsManager = exports.SheetsRegistry = exports.toCssValue = exports.getDynamicStyles = undefined;
var _getDynamicStyles = require('./utils/getDynamicStyles');
@@ -14,6 +14,15 @@ Object.defineProperty(exports, 'getDynamicStyles', {
}
});
var _toCssValue = require('./utils/toCssValue');
Object.defineProperty(exports, 'toCssValue', {
enumerable: true,
get: function get() {
return _interopRequireDefault(_toCssValue)['default'];
}
});
var _SheetsRegistry = require('./SheetsRegistry');
Object.defineProperty(exports, 'SheetsRegistry', {
@@ -50,6 +59,15 @@ Object.defineProperty(exports, 'sheets', {
}
});
var _createGenerateClassName = require('./utils/createGenerateClassName');
Object.defineProperty(exports, 'createGenerateClassName', {
enumerable: true,
get: function get() {
return _interopRequireDefault(_createGenerateClassName)['default'];
}
});
var _Jss = require('./Jss');
var _Jss2 = _interopRequireDefault(_Jss);

View File

@@ -14,6 +14,11 @@ import type {JssOptions} from './types'
*/
export {default as getDynamicStyles} from './utils/getDynamicStyles'
/**
* Converts JSS array value to a CSS string.
*/
export {default as toCssValue} from './utils/toCssValue'
/**
* SheetsRegistry for SSR.
*/
@@ -34,6 +39,13 @@ export {default as RuleList} from './RuleList'
*/
export {default as sheets} from './sheets'
/**
* Class name generator creator.
*/
export {
default as createGenerateClassName
} from './utils/createGenerateClassName'
/**
* Creates a new instance of Jss.
*/

View File

@@ -0,0 +1,76 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _RuleList = require('../RuleList');
var _RuleList2 = _interopRequireDefault(_RuleList);
var _StyleRule = require('../rules/StyleRule');
var _StyleRule2 = _interopRequireDefault(_StyleRule);
var _createRule = require('../utils/createRule');
var _createRule2 = _interopRequireDefault(_createRule);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
// A symbol replacement.
var now = Date.now();
var fnValuesNs = 'fnValues' + now;
var fnStyleNs = 'fnStyle' + ++now;
exports['default'] = {
onCreateRule: function onCreateRule(name, decl, options) {
if (typeof decl !== 'function') return null;
var rule = (0, _createRule2['default'])(name, {}, options);
rule[fnStyleNs] = decl;
return rule;
},
onProcessStyle: function onProcessStyle(style, rule) {
var fn = {};
for (var prop in style) {
var value = style[prop];
if (typeof value !== 'function') continue;
delete style[prop];
fn[prop] = value;
}
rule = rule;
rule[fnValuesNs] = fn;
return style;
},
onUpdate: function onUpdate(data, rule) {
// It is a rules container like for e.g. ConditionalRule.
if (rule.rules instanceof _RuleList2['default']) {
rule.rules.update(data);
return;
}
if (!(rule instanceof _StyleRule2['default'])) return;
rule = rule;
// If we have a fn values map, it is a rule with function values.
if (rule[fnValuesNs]) {
for (var prop in rule[fnValuesNs]) {
rule.prop(prop, rule[fnValuesNs][prop](data));
}
}
rule = rule;
var fnStyle = rule[fnStyleNs];
// If we have a style function, the entire rule is dynamic and style object
// will be returned from that function.
if (fnStyle) {
var style = fnStyle(data);
for (var _prop in style) {
rule.prop(_prop, style[_prop]);
}
}
}
};

View File

@@ -0,0 +1,71 @@
/* @flow */
import RuleList from '../RuleList'
import StyleRule from '../rules/StyleRule'
import type {Rule, JssStyle, RuleOptions} from '../types'
import createRule from '../utils/createRule'
// A symbol replacement.
let now = Date.now()
const fnValuesNs = `fnValues${now}`
const fnStyleNs = `fnStyle${++now}`
type StyleRuleWithRuleFunction = StyleRule & {[key: string]: Function}
type StyleRuleWithFunctionValues = StyleRule & {
[key: string]: {
[key: string]: Function
}
}
export default {
onCreateRule(name: string, decl: JssStyle, options: RuleOptions): Rule | null {
if (typeof decl !== 'function') return null
const rule = ((createRule(name, {}, options): any): StyleRuleWithRuleFunction)
rule[fnStyleNs] = decl
return rule
},
onProcessStyle(style: JssStyle, rule: Rule): JssStyle {
const fn = {}
for (const prop in style) {
const value = style[prop]
if (typeof value !== 'function') continue
delete style[prop]
fn[prop] = value
}
rule = ((rule: any): StyleRuleWithFunctionValues)
rule[fnValuesNs] = fn
return style
},
onUpdate(data: Object, rule: Rule) {
// It is a rules container like for e.g. ConditionalRule.
if (rule.rules instanceof RuleList) {
rule.rules.update(data)
return
}
if (!(rule instanceof StyleRule)) return
rule = ((rule: any): StyleRuleWithFunctionValues)
// If we have a fn values map, it is a rule with function values.
if (rule[fnValuesNs]) {
for (const prop in rule[fnValuesNs]) {
rule.prop(prop, rule[fnValuesNs][prop](data))
}
}
rule = ((rule: any): StyleRuleWithRuleFunction)
const fnStyle = rule[fnStyleNs]
// If we have a style function, the entire rule is dynamic and style object
// will be returned from that function.
if (fnStyle) {
const style = fnStyle(data)
for (const prop in style) {
rule.prop(prop, style[prop])
}
}
}
}

View File

@@ -0,0 +1,63 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _StyleRule = require('../rules/StyleRule');
var _StyleRule2 = _interopRequireDefault(_StyleRule);
var _createRule = require('../utils/createRule');
var _createRule2 = _interopRequireDefault(_createRule);
var _isObservable = require('../utils/isObservable');
var _isObservable2 = _interopRequireDefault(_isObservable);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
exports['default'] = {
onCreateRule: function onCreateRule(name, decl, options) {
if (!(0, _isObservable2['default'])(decl)) return null;
// Cast `decl` to `Observable`, since it passed the type guard.
var style$ = decl;
var rule = (0, _createRule2['default'])(name, {}, options);
// TODO
// Call `stream.subscribe()` returns a subscription, which should be explicitly
// unsubscribed from when we know this sheet is no longer needed.
style$.subscribe(function (style) {
for (var prop in style) {
rule.prop(prop, style[prop]);
}
});
return rule;
},
onProcessRule: function onProcessRule(rule) {
if (!(rule instanceof _StyleRule2['default'])) return;
var styleRule = rule;
var style = styleRule.style;
var _loop = function _loop(prop) {
var value = style[prop];
if (!(0, _isObservable2['default'])(value)) return 'continue';
delete style[prop];
value.subscribe({
next: function next(nextValue) {
styleRule.prop(prop, nextValue);
}
});
};
for (var prop in style) {
var _ret = _loop(prop);
if (_ret === 'continue') continue;
}
}
};

View File

@@ -0,0 +1,43 @@
/* @flow */
import StyleRule from '../rules/StyleRule'
import createRule from '../utils/createRule'
import isObservable from '../utils/isObservable'
import type {Observable, Rule, RuleOptions, JssStyle} from '../types'
export default {
onCreateRule(name: string, decl: JssStyle, options: RuleOptions): Rule | null {
if (!isObservable(decl)) return null
// Cast `decl` to `Observable`, since it passed the type guard.
const style$ = (decl: Observable<{[string]: string | number}>)
const rule = ((createRule(name, {}, options): any): StyleRule)
// TODO
// Call `stream.subscribe()` returns a subscription, which should be explicitly
// unsubscribed from when we know this sheet is no longer needed.
style$.subscribe((style: JssStyle) => {
for (const prop in style) {
rule.prop(prop, style[prop])
}
})
return rule
},
onProcessRule(rule: Rule) {
if (!(rule instanceof StyleRule)) return
const styleRule = ((rule: any): StyleRule)
const {style} = styleRule
for (const prop in style) {
const value = style[prop]
if (!isObservable(value)) continue
delete style[prop]
value.subscribe({
next: nextValue => {
styleRule.prop(prop, nextValue)
}
})
}
}
}

View File

@@ -24,8 +24,7 @@ const classes = {
export default Object.keys(classes).map((key: string): Plugin => {
// https://jsperf.com/indexof-vs-substr-vs-regex-at-the-beginning-3
const re = new RegExp(`^${key}`)
const onCreateRule = (name: string, decl: JssStyle, options: RuleOptions): Rule|null => (
const onCreateRule = (name: string, decl: JssStyle, options: RuleOptions): Rule | null =>
re.test(name) ? new classes[key](name, decl, options) : null
)
return {onCreateRule}
})

View File

@@ -14,16 +14,35 @@ var _sheets = require('../sheets');
var _sheets2 = _interopRequireDefault(_sheets);
var _StyleRule = require('../rules/StyleRule');
var _StyleRule2 = _interopRequireDefault(_StyleRule);
var _toCssValue = require('../utils/toCssValue');
var _toCssValue2 = _interopRequireDefault(_toCssValue);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Get a style property.
* Cache the value from the first time a function is called.
*/
function getStyle(rule, prop) {
var memoize = function memoize(fn) {
var value = void 0;
return function () {
if (!value) value = fn();
return value;
};
};
/**
* Get a style property value.
*/
function getPropertyValue(cssRule, prop) {
try {
return rule.style.getPropertyValue(prop);
return cssRule.style.getPropertyValue(prop);
} catch (err) {
// IE may throw if property is unknown.
return '';
@@ -33,9 +52,20 @@ function getStyle(rule, prop) {
/**
* Set a style property.
*/
function setStyle(rule, prop, value) {
function setProperty(cssRule, prop, value) {
try {
rule.style.setProperty(prop, value);
var cssValue = value;
if (Array.isArray(value)) {
cssValue = (0, _toCssValue2['default'])(value, true);
if (value[value.length - 1] === '!important') {
cssRule.style.setProperty(prop, cssValue, 'important');
return true;
}
}
cssRule.style.setProperty(prop, cssValue);
} catch (err) {
// IE may throw if property is unknown.
return false;
@@ -43,10 +73,15 @@ function setStyle(rule, prop, value) {
return true;
}
function extractSelector(cssText) {
var from = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
return cssText.substr(from, cssText.indexOf('{') - 1);
/**
* Remove a style property.
*/
function removeProperty(cssRule, prop) {
try {
cssRule.style.removeProperty(prop);
} catch (err) {
(0, _warning2['default'])(false, '[JSS] DOMException "%s" was thrown. Tried to remove property "%s".', err.message, prop);
}
}
var CSSRuleTypes = {
@@ -54,46 +89,100 @@ var CSSRuleTypes = {
KEYFRAMES_RULE: 7
/**
* Get the selector.
* Get the CSS Rule key.
*/
};function getSelector(rule) {
if (rule.type === CSSRuleTypes.STYLE_RULE) return rule.selectorText;
if (rule.type === CSSRuleTypes.KEYFRAMES_RULE) {
var name = rule.name;
if (name) return '@keyframes ' + name;
};var getKey = function () {
var extractKey = function extractKey(cssText) {
var from = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
return cssText.substr(from, cssText.indexOf('{') - 1);
};
// There is no rule.name in the following browsers:
// - IE 9
// - Safari 7.1.8
// - Mobile Safari 9.0.0
var cssText = rule.cssText;
return function (cssRule) {
if (cssRule.type === CSSRuleTypes.STYLE_RULE) return cssRule.selectorText;
if (cssRule.type === CSSRuleTypes.KEYFRAMES_RULE) {
var name = cssRule.name;
return '@' + extractSelector(cssText, cssText.indexOf('keyframes'));
}
if (name) return '@keyframes ' + name;
return extractSelector(rule.cssText);
}
// There is no rule.name in the following browsers:
// - IE 9
// - Safari 7.1.8
// - Mobile Safari 9.0.0
var cssText = cssRule.cssText;
return '@' + extractKey(cssText, cssText.indexOf('keyframes'));
}
// Conditionals.
return extractKey(cssRule.cssText);
};
}();
/**
* Set the selector.
*/
function setSelector(rule, selectorText) {
rule.selectorText = selectorText;
function setSelector(cssRule, selectorText) {
cssRule.selectorText = selectorText;
// Return false if setter was not successful.
// Currently works in chrome only.
return rule.selectorText === selectorText;
return cssRule.selectorText === selectorText;
}
/**
* Gets the `head` element upon the first call and caches it.
*/
var getHead = function () {
var head = void 0;
return function () {
if (!head) head = document.head || document.getElementsByTagName('head')[0];
return head;
var getHead = memoize(function () {
return document.head || document.getElementsByTagName('head')[0];
});
/**
* Gets a map of rule keys, where the property is an unescaped key and value
* is a potentially escaped one.
* It is used to identify CSS rules and the corresponding JSS rules. As an identifier
* for CSSStyleRule we normally use `selectorText`. Though if original selector text
* contains escaped code points e.g. `:not(#\\20)`, CSSOM will compile it to `:not(# )`
* and so CSS rule's `selectorText` won't match JSS rule selector.
*
* https://www.w3.org/International/questions/qa-escapes#cssescapes
*/
var getUnescapedKeysMap = function () {
var style = void 0;
var isAttached = false;
return function (rules) {
var map = {};
// https://github.com/facebook/flow/issues/2696
if (!style) style = document.createElement('style');
for (var i = 0; i < rules.length; i++) {
var rule = rules[i];
if (!(rule instanceof _StyleRule2['default'])) continue;
var selector = rule.selector;
// Only unescape selector over CSSOM if it contains a back slash.
if (selector && selector.indexOf('\\') !== -1) {
// Lazilly attach when needed.
if (!isAttached) {
getHead().appendChild(style);
isAttached = true;
}
style.textContent = selector + ' {}';
var _style = style,
sheet = _style.sheet;
if (sheet) {
var cssRules = sheet.cssRules;
if (cssRules) map[cssRules[0].selectorText] = rule.key;
}
}
}
if (isAttached) {
getHead().removeChild(style);
isAttached = false;
}
return map;
};
}();
@@ -196,14 +285,24 @@ function insertStyle(style, options) {
getHead().insertBefore(style, prevNode);
}
/**
* Read jss nonce setting from the page if the user has set it.
*/
var getNonce = memoize(function () {
var node = document.querySelector('meta[property="csp-nonce"]');
return node ? node.getAttribute('content') : null;
});
var DomRenderer = function () {
function DomRenderer(sheet) {
_classCallCheck(this, DomRenderer);
this.getStyle = getStyle;
this.setStyle = setStyle;
this.getPropertyValue = getPropertyValue;
this.setProperty = setProperty;
this.removeProperty = removeProperty;
this.setSelector = setSelector;
this.getSelector = getSelector;
this.getKey = getKey;
this.getUnescapedKeysMap = getUnescapedKeysMap;
this.hasInsertedRules = false;
// There is no sheet when the renderer is used from a standalone StyleRule.
@@ -221,6 +320,8 @@ var DomRenderer = function () {
this.element.setAttribute('data-jss', '');
if (media) this.element.setAttribute('media', media);
if (meta) this.element.setAttribute('data-meta', meta);
var nonce = getNonce();
if (nonce) this.element.setAttribute('nonce', nonce);
}
/**
@@ -276,12 +377,12 @@ var DomRenderer = function () {
}, {
key: 'insertRule',
value: function insertRule(rule) {
value: function insertRule(rule, index) {
var sheet = this.element.sheet;
var cssRules = sheet.cssRules;
var index = cssRules.length;
var str = rule.toString();
if (!index) index = cssRules.length;
if (!str) return false;
@@ -291,7 +392,6 @@ var DomRenderer = function () {
(0, _warning2['default'])(false, '[JSS] Can not insert an unsupported rule \n\r%s', rule);
return false;
}
this.hasInsertedRules = true;
return cssRules[index];
@@ -303,17 +403,41 @@ var DomRenderer = function () {
}, {
key: 'deleteRule',
value: function deleteRule(rule) {
value: function deleteRule(cssRule) {
var sheet = this.element.sheet;
var cssRules = sheet.cssRules;
var index = this.indexOf(cssRule);
if (index === -1) return false;
sheet.deleteRule(index);
return true;
}
/**
* Get index of a CSS Rule.
*/
}, {
key: 'indexOf',
value: function indexOf(cssRule) {
var cssRules = this.element.sheet.cssRules;
for (var _index = 0; _index < cssRules.length; _index++) {
if (rule === cssRules[_index]) {
sheet.deleteRule(_index);
return true;
}
if (cssRule === cssRules[_index]) return _index;
}
return false;
return -1;
}
/**
* Generate a new CSS rule and replace the existing one.
*/
}, {
key: 'replaceRule',
value: function replaceRule(cssRule, rule) {
var index = this.indexOf(cssRule);
var newCssRule = this.insertRule(rule, index);
this.element.sheet.deleteRule(index);
return newCssRule;
}
/**

View File

@@ -2,7 +2,9 @@
import warning from 'warning'
import sheets from '../sheets'
import type StyleSheet from '../StyleSheet'
import type {Rule, InsertionPoint} from '../types'
import StyleRule from '../rules/StyleRule'
import type {Rule, JssValue, InsertionPoint} from '../types'
import toCssValue from '../utils/toCssValue'
type PriorityOptions = {
index: number,
@@ -10,13 +12,23 @@ type PriorityOptions = {
}
/**
* Get a style property.
* Cache the value from the first time a function is called.
*/
function getStyle(rule: HTMLElement|CSSStyleRule, prop: string): string {
try {
return rule.style.getPropertyValue(prop)
const memoize = <Value>(fn: () => Value): (() => Value) => {
let value
return () => {
if (!value) value = fn()
return value
}
catch (err) {
}
/**
* Get a style property value.
*/
function getPropertyValue(cssRule: HTMLElement | CSSStyleRule, prop: string): string {
try {
return cssRule.style.getPropertyValue(prop)
} catch (err) {
// IE may throw if property is unknown.
return ''
}
@@ -25,19 +37,41 @@ function getStyle(rule: HTMLElement|CSSStyleRule, prop: string): string {
/**
* Set a style property.
*/
function setStyle(rule: HTMLElement|CSSStyleRule, prop: string, value: string): boolean {
function setProperty(cssRule: HTMLElement | CSSStyleRule, prop: string, value: JssValue): boolean {
try {
rule.style.setProperty(prop, value)
}
catch (err) {
let cssValue = ((value: any): string)
if (Array.isArray(value)) {
cssValue = toCssValue(value, true)
if (value[value.length - 1] === '!important') {
cssRule.style.setProperty(prop, cssValue, 'important')
return true
}
}
cssRule.style.setProperty(prop, cssValue)
} catch (err) {
// IE may throw if property is unknown.
return false
}
return true
}
function extractSelector(cssText: string, from: number = 0) {
return cssText.substr(from, cssText.indexOf('{') - 1)
/**
* Remove a style property.
*/
function removeProperty(cssRule: HTMLElement | CSSStyleRule, prop: string) {
try {
cssRule.style.removeProperty(prop)
} catch (err) {
warning(
false,
'[JSS] DOMException "%s" was thrown. Tried to remove property "%s".',
err.message,
prop
)
}
}
const CSSRuleTypes = {
@@ -46,51 +80,99 @@ const CSSRuleTypes = {
}
/**
* Get the selector.
* Get the CSS Rule key.
*/
function getSelector(rule: CSSOMRule): string {
if (rule.type === CSSRuleTypes.STYLE_RULE) return rule.selectorText
if (rule.type === CSSRuleTypes.KEYFRAMES_RULE) {
const {name} = rule
if (name) return `@keyframes ${name}`
// There is no rule.name in the following browsers:
// - IE 9
// - Safari 7.1.8
// - Mobile Safari 9.0.0
const {cssText} = rule
return `@${extractSelector(cssText, cssText.indexOf('keyframes'))}`
const getKey = (() => {
const extractKey = (cssText: string, from: number = 0) =>
cssText.substr(from, cssText.indexOf('{') - 1)
return (cssRule: CSSOMRule): string => {
if (cssRule.type === CSSRuleTypes.STYLE_RULE) return cssRule.selectorText
if (cssRule.type === CSSRuleTypes.KEYFRAMES_RULE) {
const {name} = cssRule
if (name) return `@keyframes ${name}`
// There is no rule.name in the following browsers:
// - IE 9
// - Safari 7.1.8
// - Mobile Safari 9.0.0
const {cssText} = cssRule
return `@${extractKey(cssText, cssText.indexOf('keyframes'))}`
}
// Conditionals.
return extractKey(cssRule.cssText)
}
return extractSelector(rule.cssText)
}
})()
/**
* Set the selector.
*/
function setSelector(rule: CSSStyleRule, selectorText: string): boolean {
rule.selectorText = selectorText
function setSelector(cssRule: CSSStyleRule, selectorText: string): boolean {
cssRule.selectorText = selectorText
// Return false if setter was not successful.
// Currently works in chrome only.
return rule.selectorText === selectorText
return cssRule.selectorText === selectorText
}
/**
* Gets the `head` element upon the first call and caches it.
*/
const getHead = (() => {
let head
return (): HTMLElement => {
if (!head) head = document.head || document.getElementsByTagName('head')[0]
return head
const getHead = memoize(
(): HTMLElement => document.head || document.getElementsByTagName('head')[0]
)
/**
* Gets a map of rule keys, where the property is an unescaped key and value
* is a potentially escaped one.
* It is used to identify CSS rules and the corresponding JSS rules. As an identifier
* for CSSStyleRule we normally use `selectorText`. Though if original selector text
* contains escaped code points e.g. `:not(#\\20)`, CSSOM will compile it to `:not(# )`
* and so CSS rule's `selectorText` won't match JSS rule selector.
*
* https://www.w3.org/International/questions/qa-escapes#cssescapes
*/
const getUnescapedKeysMap = (() => {
let style
let isAttached = false
return (rules: Array<Rule>): Object => {
const map = {}
// https://github.com/facebook/flow/issues/2696
if (!style) style = (document.createElement('style'): any)
for (let i = 0; i < rules.length; i++) {
const rule = rules[i]
if (!(rule instanceof StyleRule)) continue
const {selector} = rule
// Only unescape selector over CSSOM if it contains a back slash.
if (selector && selector.indexOf('\\') !== -1) {
// Lazilly attach when needed.
if (!isAttached) {
getHead().appendChild(style)
isAttached = true
}
style.textContent = `${selector} {}`
const {sheet} = style
if (sheet) {
const {cssRules} = sheet
if (cssRules) map[cssRules[0].selectorText] = rule.key
}
}
}
if (isAttached) {
getHead().removeChild(style)
isAttached = false
}
return map
}
})()
/**
* Find attached sheet with an index higher than the passed one.
*/
function findHigherSheet(registry: Array<StyleSheet>, options: PriorityOptions): StyleSheet|null {
function findHigherSheet(registry: Array<StyleSheet>, options: PriorityOptions): StyleSheet | null {
for (let i = 0; i < registry.length; i++) {
const sheet = registry[i]
if (
@@ -107,7 +189,10 @@ function findHigherSheet(registry: Array<StyleSheet>, options: PriorityOptions):
/**
* Find attached sheet with the highest index.
*/
function findHighestSheet(registry: Array<StyleSheet>, options: PriorityOptions): StyleSheet|null {
function findHighestSheet(
registry: Array<StyleSheet>,
options: PriorityOptions
): StyleSheet | null {
for (let i = registry.length - 1; i >= 0; i--) {
const sheet = registry[i]
if (sheet.attached && sheet.options.insertionPoint === options.insertionPoint) {
@@ -120,7 +205,7 @@ function findHighestSheet(registry: Array<StyleSheet>, options: PriorityOptions)
/**
* Find a comment with "jss" inside.
*/
function findCommentNode(text: string): Comment|null {
function findCommentNode(text: string): Node | null {
const head = getHead()
for (let i = 0; i < head.childNodes.length; i++) {
const node = head.childNodes[i]
@@ -134,7 +219,7 @@ function findCommentNode(text: string): Comment|null {
/**
* Find a node before which we can insert the sheet.
*/
function findPrevNode(options: PriorityOptions): ?Node|null {
function findPrevNode(options: PriorityOptions): ?Node | null {
const {registry} = sheets
if (registry.length > 0) {
@@ -186,14 +271,26 @@ function insertStyle(style: HTMLElement, options: PriorityOptions) {
getHead().insertBefore(style, prevNode)
}
export default class DomRenderer {
getStyle = getStyle
/**
* Read jss nonce setting from the page if the user has set it.
*/
const getNonce = memoize((): ?string => {
const node = document.querySelector('meta[property="csp-nonce"]')
return node ? node.getAttribute('content') : null
})
setStyle = setStyle
export default class DomRenderer {
getPropertyValue = getPropertyValue
setProperty = setProperty
removeProperty = removeProperty
setSelector = setSelector
getSelector = getSelector
getKey = getKey
getUnescapedKeysMap = getUnescapedKeysMap
// HTMLStyleElement needs fixing https://github.com/facebook/flow/issues/2696
element: any
@@ -207,12 +304,14 @@ export default class DomRenderer {
if (sheet) sheets.add(sheet)
this.sheet = sheet
const {media, meta, element} = (this.sheet ? this.sheet.options : {})
const {media, meta, element} = this.sheet ? this.sheet.options : {}
this.element = element || document.createElement('style')
this.element.type = 'text/css'
this.element.setAttribute('data-jss', '')
if (media) this.element.setAttribute('media', media)
if (meta) this.element.setAttribute('data-meta', meta)
const nonce = getNonce()
if (nonce) this.element.setAttribute('nonce', nonce)
}
/**
@@ -252,22 +351,20 @@ export default class DomRenderer {
/**
* Insert a rule into element.
*/
insertRule(rule: Rule): false|CSSStyleRule {
insertRule(rule: Rule, index?: number): false | CSSStyleRule {
const {sheet} = this.element
const {cssRules} = sheet
const index = cssRules.length
const str = rule.toString()
if (!index) index = cssRules.length
if (!str) return false
try {
sheet.insertRule(str, index)
}
catch (err) {
} catch (err) {
warning(false, '[JSS] Can not insert an unsupported rule \n\r%s', rule)
return false
}
this.hasInsertedRules = true
return cssRules[index]
@@ -276,16 +373,33 @@ export default class DomRenderer {
/**
* Delete a rule.
*/
deleteRule(rule: CSSStyleRule): boolean {
deleteRule(cssRule: CSSStyleRule): boolean {
const {sheet} = this.element
const {cssRules} = sheet
const index = this.indexOf(cssRule)
if (index === -1) return false
sheet.deleteRule(index)
return true
}
/**
* Get index of a CSS Rule.
*/
indexOf(cssRule: CSSStyleRule): number {
const {cssRules} = this.element.sheet
for (let index = 0; index < cssRules.length; index++) {
if (rule === cssRules[index]) {
sheet.deleteRule(index)
return true
}
if (cssRule === cssRules[index]) return index
}
return false
return -1
}
/**
* Generate a new CSS rule and replace the existing one.
*/
replaceRule(cssRule: CSSStyleRule, rule: Rule): false | CSSStyleRule {
const index = this.indexOf(cssRule)
const newCssRule = this.insertRule(rule, index)
this.element.sheet.deleteRule(index)
return newCssRule
}
/**

View File

@@ -19,23 +19,26 @@ var VirtualRenderer = function () {
}
_createClass(VirtualRenderer, [{
key: 'setStyle',
value: function setStyle() {
key: 'setProperty',
value: function setProperty() {
return true;
}
}, {
key: 'getStyle',
value: function getStyle() {
key: 'getPropertyValue',
value: function getPropertyValue() {
return '';
}
}, {
key: 'removeProperty',
value: function removeProperty() {}
}, {
key: 'setSelector',
value: function setSelector() {
return true;
}
}, {
key: 'getSelector',
value: function getSelector() {
key: 'getKey',
value: function getKey() {
return '';
}
}, {
@@ -57,9 +60,19 @@ var VirtualRenderer = function () {
value: function deleteRule() {
return true;
}
}, {
key: 'replaceRule',
value: function replaceRule() {
return false;
}
}, {
key: 'getRules',
value: function getRules() {}
}, {
key: 'indexOf',
value: function indexOf() {
return -1;
}
}]);
return VirtualRenderer;

View File

@@ -5,16 +5,17 @@
* Rendering backend to do nothing in nodejs.
*/
export default class VirtualRenderer {
setStyle() {
setProperty() {
return true
}
getStyle() {
getPropertyValue() {
return ''
}
removeProperty() {}
setSelector() {
return true
}
getSelector() {
getKey() {
return ''
}
attach() {}
@@ -26,5 +27,11 @@ export default class VirtualRenderer {
deleteRule() {
return true
}
replaceRule() {
return false
}
getRules() {}
indexOf() {
return -1
}
}

View File

@@ -23,7 +23,7 @@ export default class SimpleRule implements BaseRule {
/**
* Generates a CSS string.
*/
// eslint-disable-next-line no-unused-vars
// eslint-disable-next-line no-unused-vars
toString(options?: ToCssOptions): string {
if (Array.isArray(this.value)) {
let str = ''

View File

@@ -4,10 +4,16 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _warning = require('warning');
var _warning2 = _interopRequireDefault(_warning);
var _toCss = require('../utils/toCss');
var _toCss2 = _interopRequireDefault(_toCss);
@@ -26,21 +32,19 @@ var StyleRule = function () {
this.type = 'style';
this.isProcessed = false;
var generateClassName = options.generateClassName,
sheet = options.sheet,
var sheet = options.sheet,
Renderer = options.Renderer,
selector = options.selector;
this.key = key;
this.options = options;
this.style = style;
this.selectorText = selector || '.' + generateClassName(this, sheet);
if (selector) this.selectorText = selector;
this.renderer = sheet ? sheet.renderer : new Renderer();
}
/**
* Set selector string.
* TODO rewrite this #419
* Attention: use this with caution. Most browsers didn't implement
* selectorText setter, so this may result in rerendering of entire Style Sheet.
*/
@@ -53,35 +57,38 @@ var StyleRule = function () {
/**
* Get or set a style property.
*/
value: function prop(name, nextValue) {
var $name = typeof this.style[name] === 'function' ? '$' + name : name;
var currValue = this.style[$name];
value: function prop(name, value) {
// It's a getter.
if (value === undefined) return this.style[name];
// Its a setter.
if (nextValue != null) {
// Don't do anything if the value has not changed.
if (currValue !== nextValue) {
nextValue = this.options.jss.plugins.onChangeValue(nextValue, name, this);
Object.defineProperty(this.style, $name, {
value: nextValue,
writable: true
});
// Defined if StyleSheet option `link` is true.
if (this.renderable) this.renderer.setStyle(this.renderable, name, nextValue);
}
// Don't do anything if the value has not changed.
if (this.style[name] === value) return this;
value = this.options.jss.plugins.onChangeValue(value, name, this);
var isEmpty = value == null || value === false;
var isDefined = name in this.style;
// Value is empty and wasn't defined before.
if (isEmpty && !isDefined) return this;
// We are going to remove this value.
var remove = isEmpty && isDefined;
if (remove) delete this.style[name];else this.style[name] = value;
// Renderable is defined if StyleSheet option `link` is true.
if (this.renderable) {
if (remove) this.renderer.removeProperty(this.renderable, name);else this.renderer.setProperty(this.renderable, name, value);
return this;
}
// Its a getter, read the value from the DOM if its not cached.
if (this.renderable && currValue == null) {
// Cache the value after we have got it from the DOM first time.
Object.defineProperty(this.style, $name, {
value: this.renderer.getStyle(this.renderable, name),
writable: true
});
}
var sheet = this.options.sheet;
return this.style[$name];
if (sheet && sheet.attached) {
(0, _warning2['default'])(false, 'Rule is not linked. Missing sheet option "link: true".');
}
return this;
}
/**
@@ -93,7 +100,7 @@ var StyleRule = function () {
value: function applyTo(renderable) {
var json = this.toJSON();
for (var prop in json) {
this.renderer.setStyle(renderable, prop, json[prop]);
this.renderer.setProperty(renderable, prop, json[prop]);
}return this;
}
@@ -109,8 +116,7 @@ var StyleRule = function () {
var json = {};
for (var prop in this.style) {
var value = this.style[prop];
var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);
if (type === 'function') json[prop] = this.style['$' + prop];else if (type !== 'object') json[prop] = value;else if (Array.isArray(value)) json[prop] = (0, _toCssValue2['default'])(value);
if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object') json[prop] = value;else if (Array.isArray(value)) json[prop] = (0, _toCssValue2['default'])(value);
}
return json;
}
@@ -122,39 +128,27 @@ var StyleRule = function () {
}, {
key: 'toString',
value: function toString(options) {
return (0, _toCss2['default'])(this.selector, this.style, options);
var sheet = this.options.sheet;
var link = sheet ? sheet.options.link : false;
var opts = link ? _extends({}, options, { allowEmpty: true }) : options;
return (0, _toCss2['default'])(this.selector, this.style, opts);
}
}, {
key: 'selector',
set: function set(selector) {
var sheet = this.options.sheet;
// After we modify a selector, ref by old selector needs to be removed.
if (sheet) sheet.rules.unregister(this);
if (selector === this.selectorText) return;
this.selectorText = selector;
if (!this.renderable) {
// Register the rule with new selector.
if (sheet) sheet.rules.register(this);
return;
}
if (!this.renderable) return;
var changed = this.renderer.setSelector(this.renderable, selector);
var hasChanged = this.renderer.setSelector(this.renderable, selector);
if (changed && sheet) {
sheet.rules.register(this);
return;
}
// If selector setter is not implemented, rerender the sheet.
// We need to delete renderable from the rule, because when sheet.deploy()
// calls rule.toString, it will get the old selector.
delete this.renderable;
if (sheet) {
sheet.rules.register(this);
sheet.deploy().link();
// If selector setter is not implemented, rerender the rule.
if (!hasChanged && this.renderable) {
var renderable = this.renderer.replaceRule(this.renderable, this);
if (renderable) this.renderable = renderable;
}
}
@@ -163,10 +157,6 @@ var StyleRule = function () {
*/
,
get: function get() {
if (this.renderable) {
return this.renderer.getSelector(this.renderable);
}
return this.selectorText;
}
}]);

View File

@@ -1,7 +1,15 @@
/* @flow */
import warning from 'warning'
import toCss from '../utils/toCss'
import toCssValue from '../utils/toCssValue'
import type {ToCssOptions, RuleOptions, Renderer as RendererInterface, JssStyle, BaseRule} from '../types'
import type {
ToCssOptions,
RuleOptions,
Renderer as RendererInterface,
JssStyle,
JssValue,
BaseRule
} from '../types'
export default class StyleRule implements BaseRule {
type = 'style'
@@ -21,50 +29,32 @@ export default class StyleRule implements BaseRule {
options: RuleOptions
constructor(key: string, style: JssStyle, options: RuleOptions) {
const {generateClassName, sheet, Renderer, selector} = options
const {sheet, Renderer, selector} = options
this.key = key
this.options = options
this.style = style
this.selectorText = selector || `.${generateClassName(this, sheet)}`
if (selector) this.selectorText = selector
this.renderer = sheet ? sheet.renderer : new Renderer()
}
/**
* Set selector string.
* TODO rewrite this #419
* Attention: use this with caution. Most browsers didn't implement
* selectorText setter, so this may result in rerendering of entire Style Sheet.
*/
set selector(selector: string): void {
const {sheet} = this.options
// After we modify a selector, ref by old selector needs to be removed.
if (sheet) sheet.rules.unregister(this)
if (selector === this.selectorText) return
this.selectorText = selector
if (!this.renderable) {
// Register the rule with new selector.
if (sheet) sheet.rules.register(this)
return
}
if (!this.renderable) return
const changed = this.renderer.setSelector(this.renderable, selector)
const hasChanged = this.renderer.setSelector(this.renderable, selector)
if (changed && sheet) {
sheet.rules.register(this)
return
}
// If selector setter is not implemented, rerender the sheet.
// We need to delete renderable from the rule, because when sheet.deploy()
// calls rule.toString, it will get the old selector.
delete this.renderable
if (sheet) {
sheet.rules.register(this)
sheet
.deploy()
.link()
// If selector setter is not implemented, rerender the rule.
if (!hasChanged && this.renderable) {
const renderable = this.renderer.replaceRule(this.renderable, this)
if (renderable) this.renderable = renderable
}
}
@@ -72,45 +62,45 @@ export default class StyleRule implements BaseRule {
* Get selector string.
*/
get selector(): string {
if (this.renderable) {
return this.renderer.getSelector(this.renderable)
}
return this.selectorText
}
/**
* Get or set a style property.
*/
prop(name: string, nextValue?: string): StyleRule|string {
const $name = typeof this.style[name] === 'function' ? `$${name}` : name
const currValue = this.style[$name]
prop(name: string, value?: JssValue): StyleRule | string {
// It's a getter.
if (value === undefined) return this.style[name]
// Its a setter.
if (nextValue != null) {
// Don't do anything if the value has not changed.
if (currValue !== nextValue) {
nextValue = this.options.jss.plugins.onChangeValue(nextValue, name, this)
Object.defineProperty(this.style, $name, {
value: nextValue,
writable: true
})
// Defined if StyleSheet option `link` is true.
if (this.renderable) this.renderer.setStyle(this.renderable, name, nextValue)
}
// Don't do anything if the value has not changed.
if (this.style[name] === value) return this
value = this.options.jss.plugins.onChangeValue(value, name, this)
const isEmpty = value == null || value === false
const isDefined = name in this.style
// Value is empty and wasn't defined before.
if (isEmpty && !isDefined) return this
// We are going to remove this value.
const remove = isEmpty && isDefined
if (remove) delete this.style[name]
else this.style[name] = value
// Renderable is defined if StyleSheet option `link` is true.
if (this.renderable) {
if (remove) this.renderer.removeProperty(this.renderable, name)
else this.renderer.setProperty(this.renderable, name, value)
return this
}
// Its a getter, read the value from the DOM if its not cached.
if (this.renderable && currValue == null) {
// Cache the value after we have got it from the DOM first time.
Object.defineProperty(this.style, $name, {
value: this.renderer.getStyle(this.renderable, name),
writable: true
})
const {sheet} = this.options
if (sheet && sheet.attached) {
warning(false, 'Rule is not linked. Missing sheet option "link: true".')
}
return this.style[$name]
return this
}
/**
@@ -118,7 +108,7 @@ export default class StyleRule implements BaseRule {
*/
applyTo(renderable: HTMLElement): this {
const json = this.toJSON()
for (const prop in json) this.renderer.setStyle(renderable, prop, json[prop])
for (const prop in json) this.renderer.setProperty(renderable, prop, json[prop])
return this
}
@@ -131,9 +121,7 @@ export default class StyleRule implements BaseRule {
const json = {}
for (const prop in this.style) {
const value = this.style[prop]
const type = typeof value
if (type === 'function') json[prop] = this.style[`$${prop}`]
else if (type !== 'object') json[prop] = value
if (typeof value !== 'object') json[prop] = value
else if (Array.isArray(value)) json[prop] = toCssValue(value)
}
return json
@@ -143,6 +131,9 @@ export default class StyleRule implements BaseRule {
* Generates a CSS string.
*/
toString(options?: ToCssOptions): string {
return toCss(this.selector, this.style, options)
const {sheet} = this.options
const link = sheet ? sheet.options.link : false
const opts = link ? {...options, allowEmpty: true} : options
return toCss(this.selector, this.style, opts)
}
}

View File

@@ -12,7 +12,13 @@ export type ToCssOptions = {
indent?: number
}
export type Rule = StyleRule|ConditionalRule|FontFaceRule|KeyframesRule|SimpleRule|ViewportRule
export type Rule =
| StyleRule
| ConditionalRule
| FontFaceRule
| KeyframesRule
| SimpleRule
| ViewportRule
export type generateClassName = (rule: Rule, sheet?: StyleSheet) => string
@@ -20,19 +26,30 @@ export type generateClassName = (rule: Rule, sheet?: StyleSheet) => string
// Find a way to declare all types: Object|string|Array<Object>
export type JssStyle = Object
export type JssValue =
| string
| number
| Array<string | number | Array<string | number> | '!important'>
export interface Renderer {
constructor(sheet?: StyleSheet): Renderer;
setStyle(rule: HTMLElement|CSSStyleRule, prop: string, value: string): boolean;
getStyle(rule: HTMLElement|CSSStyleRule, prop: string): string;
setSelector(rule: CSSStyleRule, selectorText: string): boolean;
getSelector(rule: CSSStyleRule): string;
constructor(sheet?: StyleSheet): void;
setProperty(
cssRule: HTMLElement | CSSStyleRule,
prop: string,
value: JssValue
): boolean;
getPropertyValue(cssRule: HTMLElement | CSSStyleRule, prop: string): string;
removeProperty(cssRule: HTMLElement | CSSStyleRule, prop: string): void;
setSelector(cssRule: CSSStyleRule, selectorText: string): boolean;
getKey(cssRule: CSSStyleRule): string;
attach(): void;
detach(): void;
deploy(sheet: StyleSheet): void;
insertRule(rule: Rule): false|CSSStyleRule;
deleteRule(rule: CSSStyleRule): boolean;
getRules(): CSSRuleList|void;
insertRule(rule: Rule): false | CSSStyleRule;
deleteRule(cssRule: CSSStyleRule): boolean;
replaceRule(cssRule: CSSStyleRule, rule: Rule): false | CSSStyleRule;
indexOf(cssRule: CSSStyleRule): number;
getRules(): CSSRuleList | void;
}
export type RuleFactoryOptions = {
@@ -61,7 +78,7 @@ export type RuleListOptions = {
Renderer: Class<Renderer>,
jss: Jss,
sheet: StyleSheet,
parent: ConditionalRule|KeyframesRule|StyleSheet
parent: ConditionalRule | KeyframesRule | StyleSheet
}
export interface BaseRule {
@@ -73,14 +90,23 @@ export interface BaseRule {
}
export type Plugin = {
onCreateRule?: (name: string, decl: JssStyle, options: RuleOptions) => Rule|null,
onCreateRule?: (
name: string,
decl: JssStyle,
options: RuleOptions
) => Rule | null,
onProcessRule?: (rule: Rule, sheet?: StyleSheet) => void,
onProcessStyle?: (style: JssStyle, rule: Rule, sheet?: StyleSheet) => JssStyle,
onProcessStyle?: (
style: JssStyle,
rule: Rule,
sheet?: StyleSheet
) => JssStyle,
onProcessSheet?: (sheet?: StyleSheet) => void,
onChangeValue?: (value: string, prop: string, rule: Rule) => string
onChangeValue?: (value: string, prop: string, rule: Rule) => string,
onUpdate?: (data: Object, rule: Rule, sheet?: StyleSheet) => void
}
export type InsertionPoint = string|HTMLElement
export type InsertionPoint = string | HTMLElement
type createGenerateClassName = () => generateClassName
@@ -94,7 +120,7 @@ export type JssOptions = {
export type InternalJssOptions = {
createGenerateClassName: createGenerateClassName,
plugins?: Array<Plugin>,
plugins: Array<Plugin>,
insertionPoint?: InsertionPoint,
Renderer: Class<Renderer>
}
@@ -105,7 +131,8 @@ export type StyleSheetFactoryOptions = {
index?: number,
link?: boolean,
element?: HTMLStyleElement,
generateClassName?: generateClassName
generateClassName?: generateClassName,
classNamePrefix?: string
}
export type StyleSheetOptions = {
@@ -115,6 +142,7 @@ export type StyleSheetOptions = {
element?: HTMLStyleElement,
index: number,
generateClassName: generateClassName,
classNamePrefix?: string,
Renderer: Class<Renderer>,
insertionPoint?: InsertionPoint,
jss: Jss
@@ -129,8 +157,28 @@ export type InternalStyleSheetOptions = {
insertionPoint?: InsertionPoint,
Renderer: Class<Renderer>,
generateClassName: generateClassName,
classNamePrefix?: string,
jss: Jss,
sheet: StyleSheet,
parent: ConditionalRule|KeyframesRule|StyleSheet,
parent: ConditionalRule | KeyframesRule | StyleSheet,
classes: Object
}
// These types are imported from indefinite-observable. They should probably
// be moved to flow-typed.
export type Observable<T> = {
subscribe(observerOrNext: ObserverOrNext<T>): Subscription
}
export type Observer<T> = {
next: NextChannel<T>
}
export type NextChannel<T> = (value: T) => void
export type ObserverOrNext<T> = Observer<T> | NextChannel<T>
export type Unsubscribe = () => void
export type Subscription = {
unsubscribe: Unsubscribe
}

View File

@@ -6,7 +6,14 @@ Object.defineProperty(exports, "__esModule", {
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.default = cloneStyle;
exports['default'] = cloneStyle;
var _isObservable = require('./isObservable');
var _isObservable2 = _interopRequireDefault(_isObservable);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var isArray = Array.isArray;
function cloneStyle(style) {
// Support empty values in case user ends up with them by accident.
@@ -14,11 +21,18 @@ function cloneStyle(style) {
// Support string value for SimpleRule.
var typeOfStyle = typeof style === 'undefined' ? 'undefined' : _typeof(style);
if (typeOfStyle === 'string' || typeOfStyle === 'number') return style;
if (typeOfStyle === 'string' || typeOfStyle === 'number' || typeOfStyle === 'function') {
return style;
}
// Support array for FontFaceRule.
if (isArray(style)) return style.map(cloneStyle);
// Support Observable styles. Observables are immutable, so we don't need to
// copy them.
if ((0, _isObservable2['default'])(style)) return style;
var newStyle = {};
for (var name in style) {
var value = style[name];

View File

@@ -1,3 +1,4 @@
import isObservable from './isObservable'
import type {JssStyle} from '../types'
const {isArray} = Array
@@ -8,11 +9,18 @@ export default function cloneStyle(style: JssStyle): JssStyle {
// Support string value for SimpleRule.
const typeOfStyle = typeof style
if (typeOfStyle === 'string' || typeOfStyle === 'number') return style
if (typeOfStyle === 'string' || typeOfStyle === 'number' || typeOfStyle === 'function') {
return style
}
// Support array for FontFaceRule.
if (isArray(style)) return style.map(cloneStyle)
// Support Observable styles. Observables are immutable, so we don't need to
// copy them.
if (isObservable(style)) return style
const newStyle = {}
for (const name in style) {
const value = style[name]

View File

@@ -4,13 +4,24 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
var _warning = require('warning');
var globalRef = typeof window === 'undefined' ? global : window;
var _warning2 = _interopRequireDefault(_warning);
var namespace = '__JSS_VERSION_COUNTER__';
if (globalRef[namespace] == null) globalRef[namespace] = 0;
// In case we have more than one JSS version.
var jssCounter = globalRef[namespace]++;
var _StyleSheet = require('../StyleSheet');
var _StyleSheet2 = _interopRequireDefault(_StyleSheet);
var _moduleId = require('./moduleId');
var _moduleId2 = _interopRequireDefault(_moduleId);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var maxRules = 1e10;
var env = process.env.NODE_ENV;
/**
* Returns a function which generates unique class names based on counters.
@@ -20,8 +31,27 @@ var jssCounter = globalRef[namespace]++;
exports['default'] = function () {
var ruleCounter = 0;
var defaultPrefix = env === 'production' ? 'c' : '';
return function (rule) {
return rule.key + '-' + jssCounter + '-' + ruleCounter++;
return function (rule, sheet) {
ruleCounter += 1;
if (ruleCounter > maxRules) {
(0, _warning2['default'])(false, '[JSS] You might have a memory leak. Rule counter is at %s.', ruleCounter);
}
var prefix = defaultPrefix;
var jssId = '';
if (sheet) {
prefix = sheet.options.classNamePrefix || defaultPrefix;
if (sheet.options.jss.id != null) jssId += sheet.options.jss.id;
}
if (env === 'production') {
return '' + prefix + _moduleId2['default'] + jssId + ruleCounter;
}
return prefix + rule.key + '-' + _moduleId2['default'] + (jssId && '-' + jssId) + '-' + ruleCounter;
};
};

View File

@@ -1,11 +1,12 @@
/* @flow */
import warning from 'warning'
import type {Rule, generateClassName} from '../types'
import StyleSheet from '../StyleSheet'
import moduleId from './moduleId'
const globalRef = typeof window === 'undefined' ? global : window
const namespace = '__JSS_VERSION_COUNTER__'
if (globalRef[namespace] == null) globalRef[namespace] = 0
// In case we have more than one JSS version.
const jssCounter = globalRef[namespace]++
const maxRules = 1e10
const env = process.env.NODE_ENV
/**
* Returns a function which generates unique class names based on counters.
@@ -14,6 +15,27 @@ const jssCounter = globalRef[namespace]++
*/
export default (): generateClassName => {
let ruleCounter = 0
const defaultPrefix = env === 'production' ? 'c' : ''
return (rule: Rule): string => `${rule.key}-${jssCounter}-${ruleCounter++}`
return (rule: Rule, sheet?: StyleSheet): string => {
ruleCounter += 1
if (ruleCounter > maxRules) {
warning(false, '[JSS] You might have a memory leak. Rule counter is at %s.', ruleCounter)
}
let prefix = defaultPrefix
let jssId = ''
if (sheet) {
prefix = sheet.options.classNamePrefix || defaultPrefix
if (sheet.options.jss.id != null) jssId += sheet.options.jss.id
}
if (env === 'production') {
return `${prefix}${moduleId}${jssId}${ruleCounter}`
}
return `${prefix + rule.key}-${moduleId}${jssId && `-${jssId}`}-${ruleCounter}`
}
}

View File

@@ -7,7 +7,11 @@ import cloneStyle from '../utils/cloneStyle'
/**
* Create a rule instance.
*/
export default function createRule(name: string = 'unnamed', decl: JssStyle, options: RuleOptions): Rule {
export default function createRule(
name: string = 'unnamed',
decl: JssStyle,
options: RuleOptions
): Rule {
const {jss} = options
const declCopy = cloneStyle(decl)

View File

@@ -0,0 +1,22 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var CSS = global.CSS;
var env = process.env.NODE_ENV;
var escapeRegex = /([[\].#*$><+~=|^:(),"'`])/g;
exports['default'] = function (str) {
// We don't need to escape it in production, because we are not using user's
// input for selectors, we are generating a valid selector.
if (env === 'production') return str;
if (!CSS || !CSS.escape) {
return str.replace(escapeRegex, '\\$1');
}
return CSS.escape(str);
};

View File

@@ -0,0 +1,17 @@
const CSS = (global.CSS: any)
const env = process.env.NODE_ENV
const escapeRegex = /([[\].#*$><+~=|^:(),"'`])/g
export default str => {
// We don't need to escape it in production, because we are not using user's
// input for selectors, we are generating a valid selector.
if (env === 'production') return str
if (!CSS || !CSS.escape) {
return str.replace(escapeRegex, '\\$1')
}
return CSS.escape(str)
}

View File

@@ -1,19 +0,0 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports['default'] = findClassNames;
var dotsRegExp = /[.]/g;
var classesRegExp = /[.][^ ,]+/g;
/**
* Get class names from a selector.
*/
function findClassNames(selector) {
var classes = selector.match(classesRegExp);
if (!classes) return '';
return classes.join(' ').replace(dotsRegExp, '');
}

View File

@@ -1,16 +0,0 @@
/* @flow */
const dotsRegExp = /[.]/g
const classesRegExp = /[.][^ ,]+/g
/**
* Get class names from a selector.
*/
export default function findClassNames(selector: string): string {
const classes = selector.match(classesRegExp)
if (!classes) return ''
return classes
.join(' ')
.replace(dotsRegExp, '')
}

View File

@@ -1,33 +0,0 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports['default'] = findRenderer;
var _isInBrowser = require('is-in-browser');
var _isInBrowser2 = _interopRequireDefault(_isInBrowser);
var _DomRenderer = require('../renderers/DomRenderer');
var _DomRenderer2 = _interopRequireDefault(_DomRenderer);
var _VirtualRenderer = require('../renderers/VirtualRenderer');
var _VirtualRenderer2 = _interopRequireDefault(_VirtualRenderer);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
/**
* Find proper renderer.
* Option `virtual` is used to force use of VirtualRenderer even if DOM is
* detected, used for testing only.
*/
function findRenderer() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
if (options.Renderer) return options.Renderer;
var useVirtual = options.virtual || !_isInBrowser2['default'];
return useVirtual ? _VirtualRenderer2['default'] : _DomRenderer2['default'];
}

View File

@@ -1,16 +0,0 @@
/* @flow */
import isInBrowser from 'is-in-browser'
import DomRenderer from '../renderers/DomRenderer'
import VirtualRenderer from '../renderers/VirtualRenderer'
import type {JssOptions, Renderer} from '../types'
/**
* Find proper renderer.
* Option `virtual` is used to force use of VirtualRenderer even if DOM is
* detected, used for testing only.
*/
export default function findRenderer(options: JssOptions = {}): Class<Renderer> {
if (options.Renderer) return options.Renderer
const useVirtual = options.virtual || !isInBrowser
return useVirtual ? VirtualRenderer : DomRenderer
}

View File

@@ -1,7 +1,7 @@
/**
* Extracts a styles object with only props that contain function values.
*/
export default (styles: Object): Object|null => {
export default (styles: Object): Object | null => {
// eslint-disable-next-line no-shadow
function extract(styles: Object): Object {
let to = null
@@ -13,8 +13,7 @@ export default (styles: Object): Object|null => {
if (type === 'function') {
if (!to) to = {}
to[key] = value
}
else if (type === 'object' && value !== null && !Array.isArray(value)) {
} else if (type === 'object' && value !== null && !Array.isArray(value)) {
const extracted = extract(value)
if (extracted) {
if (!to) to = {}

View File

@@ -0,0 +1,15 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _symbolObservable = require('symbol-observable');
var _symbolObservable2 = _interopRequireDefault(_symbolObservable);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
exports['default'] = function (value) {
return value && value[_symbolObservable2['default']] && value === value[_symbolObservable2['default']]();
};

View File

@@ -0,0 +1,3 @@
import $$observable from 'symbol-observable'
export default value => value && value[$$observable] && value === value[$$observable]()

View File

@@ -0,0 +1,13 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var ns = '2f1acc6c3a606b082e5eef5e54414ffb';
if (global[ns] == null) global[ns] = 0;
// Bundle may contain multiple JSS versions at the same time. In order to identify
// the current version with just one short number and use it for classes generation
// we use a counter. Also it is more accurate, because user can manually reevaluate
// the module.
exports['default'] = global[ns]++;

View File

@@ -0,0 +1,8 @@
const ns = '2f1acc6c3a606b082e5eef5e54414ffb'
if (global[ns] == null) global[ns] = 0
// Bundle may contain multiple JSS versions at the same time. In order to identify
// the current version with just one short number and use it for classes generation
// we use a counter. Also it is more accurate, because user can manually reevaluate
// the module.
export default global[ns]++

View File

@@ -53,32 +53,26 @@ function toCss(selector, style) {
}
}
}
}
// Object syntax {fallbacks: {prop: value}}
else {
for (var _prop in fallbacks) {
var _value = fallbacks[_prop];
if (_value != null) {
result += '\n' + indentStr(_prop + ': ' + (0, _toCssValue2['default'])(_value) + ';', indent);
}
} else {
// Object syntax {fallbacks: {prop: value}}
for (var _prop in fallbacks) {
var _value = fallbacks[_prop];
if (_value != null) {
result += '\n' + indentStr(_prop + ': ' + (0, _toCssValue2['default'])(_value) + ';', indent);
}
}
}
}
var hasFunctionValue = false;
for (var _prop2 in style) {
var _value2 = style[_prop2];
if (typeof _value2 === 'function') {
_value2 = style['$' + _prop2];
hasFunctionValue = true;
}
if (_value2 != null && _prop2 !== 'fallbacks') {
result += '\n' + indentStr(_prop2 + ': ' + (0, _toCssValue2['default'])(_value2) + ';', indent);
}
}
if (!result && !hasFunctionValue) return result;
// Allow empty style in this case, because properties will be added dynamically.
if (!result && !options.allowEmpty) return result;
indent--;
result = indentStr(selector + ' {' + result + '\n', indent) + indentStr('}', indent);

View File

@@ -38,9 +38,8 @@ export default function toCss(selector: string, style: JssStyle, options: Option
}
}
}
}
// Object syntax {fallbacks: {prop: value}}
else {
} else {
// Object syntax {fallbacks: {prop: value}}
for (const prop in fallbacks) {
const value = fallbacks[prop]
if (value != null) {
@@ -50,20 +49,15 @@ export default function toCss(selector: string, style: JssStyle, options: Option
}
}
let hasFunctionValue = false
for (const prop in style) {
let value = style[prop]
if (typeof value === 'function') {
value = style[`$${prop}`]
hasFunctionValue = true
}
const value = style[prop]
if (value != null && prop !== 'fallbacks') {
result += `\n${indentStr(`${prop}: ${toCssValue(value)};`, indent)}`
}
}
if (!result && !hasFunctionValue) return result
// Allow empty style in this case, because properties will be added dynamically.
if (!result && !options.allowEmpty) return result
indent--
result = indentStr(`${selector} {${result}\n`, indent) + indentStr('}', indent)

View File

@@ -4,8 +4,15 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports['default'] = toCssValue;
var joinWithSpace = function joinWithSpace(value) {
return value.join(' ');
var join = function join(value, by) {
var result = '';
for (var i = 0; i < value.length; i++) {
// Remove !important from the value, it will be readded later.
if (value[i] === '!important') break;
if (result) result += by;
result += value[i];
}
return result;
};
/**
@@ -13,14 +20,29 @@ var joinWithSpace = function joinWithSpace(value) {
*
* `margin: [['5px', '10px']]` > `margin: 5px 10px;`
* `border: ['1px', '2px']` > `border: 1px, 2px;`
* `margin: [['5px', '10px'], '!important']` > `margin: 5px 10px !important;`
* `color: ['red', !important]` > `color: red !important;`
*/
function toCssValue(value) {
var ignoreImportant = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (!Array.isArray(value)) return value;
// Support space separated values.
var cssValue = '';
// Support space separated values via `[['5px', '10px']]`.
if (Array.isArray(value[0])) {
return toCssValue(value.map(joinWithSpace));
for (var i = 0; i < value.length; i++) {
if (value[i] === '!important') break;
if (cssValue) cssValue += ', ';
cssValue += join(value[i], ' ');
}
} else cssValue = join(value, ', ');
// Add !important, because it was ignored.
if (!ignoreImportant && value[value.length - 1] === '!important') {
cssValue += ' !important';
}
return value.join(', ');
return cssValue;
}

View File

@@ -1,19 +1,42 @@
/* @flow */
const joinWithSpace = (value: Array<string|number>): string => value.join(' ')
const join = (value, by) => {
let result = ''
for (let i = 0; i < value.length; i++) {
// Remove !important from the value, it will be readded later.
if (value[i] === '!important') break
if (result) result += by
result += value[i]
}
return result
}
/**
* Converts array values to string.
*
* `margin: [['5px', '10px']]` > `margin: 5px 10px;`
* `border: ['1px', '2px']` > `border: 1px, 2px;`
* `margin: [['5px', '10px'], '!important']` > `margin: 5px 10px !important;`
* `color: ['red', !important]` > `color: red !important;`
*/
export default function toCssValue(value: any) {
export default function toCssValue(value: any, ignoreImportant: boolean = false) {
if (!Array.isArray(value)) return value
// Support space separated values.
let cssValue = ''
// Support space separated values via `[['5px', '10px']]`.
if (Array.isArray(value[0])) {
return toCssValue(value.map(joinWithSpace))
for (let i = 0; i < value.length; i++) {
if (value[i] === '!important') break
if (cssValue) cssValue += ', '
cssValue += join(value[i], ' ')
}
} else cssValue = join(value, ', ')
// Add !important, because it was ignored.
if (!ignoreImportant && value[value.length - 1] === '!important') {
cssValue += ' !important'
}
return value.join(', ')
return cssValue
}

View File

@@ -1,18 +0,0 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports['default'] = function (rule, data, RuleList) {
if (rule.type === 'style') {
for (var prop in rule.style) {
var value = rule.style[prop];
if (typeof value === 'function') {
rule.prop(prop, value(data));
}
}
} else if (rule.rules instanceof RuleList) {
rule.rules.update(data);
}
};

View File

@@ -1,16 +0,0 @@
import type RuleListType from '../RuleList'
import type {Rule} from './types'
export default (rule: Rule, data: Object, RuleList: RuleListType): void => {
if (rule.type === 'style') {
for (const prop in rule.style) {
const value = rule.style[prop]
if (typeof value === 'function') {
rule.prop(prop, value(data))
}
}
}
else if (rule.rules instanceof RuleList) {
rule.rules.update(data)
}
}

View File

@@ -0,0 +1,8 @@
The MIT License (MIT)
Copyright (c) 2014-present Oleg Slobodskoi
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,31 +1,46 @@
{
"name": "jss",
"description": "A lib for generating Style Sheets with JavaScript.",
"version": "8.1.0",
"_args": [
[
"jss@9.8.0",
"C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\goTorrentWebUI"
]
],
"_from": "jss@9.8.0",
"_id": "jss@9.8.0",
"_inBundle": false,
"_integrity": "sha512-1E9pn6k1Qd1BxKz845supoedukHuwMeBiqybCQV9l60v8JE7owkZSvVJfjw3wm50SjG1C/ABPtQ8PrGfhfrzLw==",
"_location": "/material-ui/jss",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "jss@9.8.0",
"name": "jss",
"escapedName": "jss",
"rawSpec": "9.8.0",
"saveSpec": null,
"fetchSpec": "9.8.0"
},
"_requiredBy": [
"/material-ui",
"/material-ui/react-jss"
],
"_resolved": "https://registry.npmjs.org/jss/-/jss-9.8.0.tgz",
"_spec": "9.8.0",
"_where": "C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\goTorrentWebUI",
"author": {
"name": "Oleg Slobodskoi",
"email": "oleg008@gmail.com"
},
"repository": {
"type": "git",
"url": "git@github.com:cssinjs/jss.git"
"bugs": {
"url": "https://github.com/cssinjs/jss/issues"
},
"keywords": [
"jss",
"style",
"sheet",
"stylesheet",
"css",
"components",
"composable",
"css in js",
"css-in-js"
],
"license": "MIT",
"main": "./lib/index.js",
"engines": {
"node": ">=4"
"dependencies": {
"is-in-browser": "^1.1.3",
"symbol-observable": "^1.1.0",
"warning": "^3.0.0"
},
"description": "A lib for generating Style Sheets with JavaScript.",
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-core": "^6.20.0",
@@ -43,25 +58,27 @@
"codecov": "^1.0.1",
"common-tags": "^1.4.0",
"cross-env": "^3.1.3",
"css.escape": "^1.5.1",
"detect-browser": "^1.5.0",
"es5-shim": "^4.5.9",
"eslint": "^3.11.1",
"eslint": "^3.19.0",
"eslint-config-airbnb": "^13.0.0",
"eslint-config-jss": "^3.0.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-flowtype": "^2.29.1",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.5.0",
"expect.js": "^0.3.1",
"flow-bin": "^0.47.0",
"flow-bin": "^0.57.3",
"flow-copy-source": "^1.1.0",
"json-loader": "^0.5.4",
"jss-cache": "^2.0.0",
"jss-camel-case": "^5.0.0",
"jss-camel-case": "^6.1.0",
"jss-compose": "^4.0.0",
"jss-default-unit": "^7.0.0",
"jss-expand": "^4.0.0",
"jss-extend": "^5.0.0",
"jss-extend": "^6.2.0",
"jss-global": "^2.0.0",
"jss-isolate": "^4.0.0",
"jss-nested": "^5.0.0",
@@ -80,33 +97,14 @@
"lint-staged": "^3.2.2",
"mocha": "^3.2.0",
"pre-commit": "^1.1.3",
"prettier": "^1.10.2",
"rimraf": "^2.5.4",
"size-limit": "^0.2.0",
"webpack": "^2.3.3"
"webpack": "^2.3.3",
"zen-observable": "^0.6.0"
},
"scripts": {
"all": "npm run lint && npm run flow && npm run test && npm run build && npm run size",
"build": "npm run clean && npm run build:lib && npm run build:max && npm run build:min && npm run build:tests",
"build:lib": "babel src --out-dir lib && npm run flow:copy-src",
"build:max": "cross-env NODE_ENV=development webpack src/index.js dist/jss.js",
"build:min": "cross-env NODE_ENV=production webpack src/index.js dist/jss.min.js",
"build:tests": "cross-env NODE_ENV=test webpack tests/index.js tmp/tests.js",
"clean": "rimraf '{lib,dist,tmp}/*'",
"flow": "flow --show-all-errors",
"flow:copy-src": "flow-copy-source -i './src/**' src lib",
"lint": "eslint ./src ./tests ./benchmark ./*.js && npm run flow",
"lint:staged": "lint-staged && npm run flow",
"prepublishOnly": "npm run all",
"test": "cross-env NODE_ENV=test karma start --single-run",
"test:watch": "cross-env NODE_ENV=test karma start",
"posttest": "[ -z \"$TRAVIS\" ] || codecov",
"codecov": "codecov",
"bench": "cross-env BENCHMARK=true karma start --single-run",
"size": "size-limit 5.8KB dist/jss.js"
},
"dependencies": {
"is-in-browser": "^1.0.2",
"warning": "^3.0.0"
"engines": {
"node": ">=4"
},
"files": [
"dist",
@@ -116,11 +114,55 @@
"changelog.md",
"LICENSE"
],
"homepage": "https://github.com/cssinjs/jss#readme",
"keywords": [
"jss",
"style",
"sheet",
"stylesheet",
"css",
"components",
"composable",
"css in js",
"css-in-js"
],
"license": "MIT",
"lint-staged": {
"./src ./tests ./benchmark ./*.js": [
"eslint",
"git add"
"**/*.{js,md,json}": [
"prettier"
],
"**/*.js": [
"eslint"
]
},
"pre-commit": "lint:staged"
"main": "./lib/index.js",
"name": "jss",
"pre-commit": "lint:staged",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/cssinjs/jss.git"
},
"scripts": {
"all": "npm run lint && npm run flow && npm run test && npm run build && npm run size",
"bench": "cross-env BENCHMARK=true karma start --single-run",
"build": "npm run clean && npm run build:lib && npm run build:max && npm run build:min && npm run build:tests",
"build:lib": "babel src --out-dir lib && npm run flow:copy-src",
"build:max": "cross-env NODE_ENV=development webpack src/index.js dist/jss.js",
"build:min": "cross-env NODE_ENV=production webpack src/index.js dist/jss.min.js",
"build:tests": "cross-env NODE_ENV=test webpack tests/index.js tmp/tests.js",
"clean": "rimraf '{lib,dist,tmp}/*'",
"codecov": "codecov",
"flow": "flow --show-all-errors",
"flow:copy-src": "flow-copy-source -i './src/**' src lib",
"format": "prettier --write */**/*",
"lint": "eslint ./src ./tests ./benchmark ./*.js && npm run flow && npm run format",
"lint:staged": "lint-staged && npm run flow",
"postinstall": "node -e \"console.log('\\u001b[35m\\u001b[1mLove JSS? You can now support us on open collective:\\u001b[22m\\u001b[39m\\n > \\u001b[34mhttps://opencollective.com/jss/donate\\u001b[0m')\"",
"posttest": "[ -z \"$TRAVIS\" ] || codecov",
"prepublishOnly": "npm run all",
"size": "size-limit 7.3KB dist/jss.js",
"test": "cross-env NODE_ENV=test karma start --single-run",
"test:watch": "cross-env NODE_ENV=test karma start"
},
"version": "9.8.0"
}

View File

@@ -7,25 +7,19 @@
[![OpenCollective](https://opencollective.com/jss/backers/badge.svg)](#backers)
[![OpenCollective](https://opencollective.com/jss/sponsors/badge.svg)](#sponsors)
[JSS is a more powerful abstraction](https://medium.com/@oleg008/jss-is-css-d7d41400b635) over CSS. It uses JavaScript as a language to describe styles in a declarative and maintainable way. It is a [high performance](https://github.com/cssinjs/jss/blob/master/docs/performance.md) JS to CSS compiler which works at runtime and server-side. This core library is low level and framework agnostic. It is about 6KB (minified and gzipped) and is extensible via [plugins](./docs/plugins.md) API.
[JSS is a better abstraction](https://medium.com/@oleg008/jss-is-css-d7d41400b635) over CSS. It uses JavaScript as a language to describe styles in a declarative and maintainable way. It is a [high performance](https://github.com/cssinjs/jss/blob/master/docs/performance.md) JS to CSS compiler which works at runtime and server-side. You can use it with [React](https://github.com/cssinjs/react-jss) or with any other library. It is about 5KB (minified and gzipped) and is extensible via [plugins](./docs/plugins.md) API.
Feel free to ask any JSS related questions on twitter by using hashtag `#cssinjs` and mentioning [@oleg008](https://twitter.com/oleg008), [watch my latest talk](https://www.youtube.com/watch?v=i3TIrcnMIng) about "Unique Value Proposition of CSSinJS" and try it on a [playground](https://codesandbox.io/s/z21lpmvv33).
## Integrations
### Official
- [React-JSS](https://github.com/cssinjs/react-jss) - HOC interface for React, try it on [webpackbin](https://www.webpackbin.com/bins/-Kn90iijPuAJO48ItgF-).
- [Styled-JSS](https://github.com/cssinjs/styled-jss) - styled components interface for React, try it on [webpackbin](https://www.webpackbin.com/bins/-KlrbQuwAZSK5eSzpCSy).
- [Aphrodite-JSS](https://github.com/cssinjs/aphrodite-jss) - aphrodite like API.
### External
- [Theme Reactor](https://github.com/nathanmarks/jss-theme-reactor) - experimental React integration with theming.
- [Aesthetic](https://github.com/milesj/aesthetic/tree/master/packages/aesthetic) - a React style abstraction layer with theme support.
* [React-JSS](https://github.com/cssinjs/react-jss) - HOC interface for React with theming, try it on [playground](https://codesandbox.io/s/j3l06yyqpw).
* [Styled-JSS](https://github.com/cssinjs/styled-jss) - styled components interface for React, try it on [playground](https://codesandbox.io/s/xl89zx8zz4).
* [Aphrodite-JSS](https://github.com/cssinjs/aphrodite-jss) - aphrodite like API.
## TOC
1. [Live examples](https://github.com/cssinjs/examples).
1. [Live examples](https://github.com/cssinjs/examples)
1. [Benefits](./docs/benefits.md)
1. [Setup](./docs/setup.md)
1. [JSON API (JSS Syntax)](./docs/json-api.md)
@@ -38,10 +32,9 @@
1. [CLI Converter](https://github.com/cssinjs/cli)
1. [Contributing](./contributing.md)
## Example
Try it out on [webpackbin](https://www.webpackbin.com/bins/-KlrNqkpZZmKIz0eYwIk).
Try it out on [playground](https://codesandbox.io/s/z21lpmvv33).
You need to [setup plugins](./docs/setup.md#setup-with-plugins) before.
You can use a [preset](https://github.com/cssinjs/jss-preset-default) for a quick setup with default plugins.
@@ -63,7 +56,9 @@ const styles = {
ctaButton: {
extend: 'button',
'&:hover': {
background: color('blue').darken(0.3).hex()
background: color('blue')
.darken(0.3)
.hex()
}
},
'@media (min-width: 1024px)': {
@@ -110,30 +105,35 @@ Result
<button class="ctaButton-789012">CTA Button</button>
</body>
```
## When should I use it?
- You build a JavaScript heavy application.
- You use components based architecture.
- You build a reusable UI library.
- You need a collision free CSS (external content, third-party UI components ...).
- You need code sharing between js and css.
- Minimal download size is important to you.
- Robustness and code reuse is important to you.
- Ease of maintenance is important to you.
- You just want to use any of its [benefits](./docs/benefits.md)
* You build a JavaScript heavy application.
* You use components based architecture.
* You build a reusable UI library.
* You need a collision free CSS (external content, third-party UI components ...).
* You need code sharing between js and css.
* Minimal download size is important to you.
* Robustness and code reuse is important to you.
* Ease of maintenance is important to you.
* You just want to use any of its [benefits](./docs/benefits.md)
## Roadmap
- ~~Make it easier for newcomers to setup jss with plugins (like presets).~~
- ~~Make JSON DSL even better, for e.g. [jss-expand](https://github.com/typical000/jss-expand).~~
- ~~Make it easy to see when changes in the core break plugins (integrate plugins test suite).~~
- Make community create plugins (better plugins API documentation, infrastructure).
- Do more benchmarking, include plugins, always track perf regressions.
- Introduce a way for theming with react-jss or replace it by [jss-theme-reactor](https://github.com/nathanmarks/jss-theme-reactor)
- Make SSR even better (vendor prefixer, smaller critical CSS)
- Make CLI tool better, allow integration of styles written in various preprocessing languages as well as pure css.
- React Native support.
- Add converters stylus, sass and co. to [cli](https://github.com/cssinjs/cli) with constants reuse.
* ~~Make it easier for newcomers to setup jss with plugins (like presets).~~
* ~~Make JSON DSL even better, for e.g. [jss-expand](https://github.com/typical000/jss-expand).~~
* ~~Make it easy to see when changes in the core break plugins (integrate plugins test suite).~~
* ~~Make community create plugins (better plugins API documentation, infrastructure).~~
* ~~Introduce a way for theming with react-jss~~
* Help release [material-ui](https://github.com/callemall/material-ui/tree/v1-alpha) alpha version.
* Use [ISTF](https://github.com/cssinjs/istf-spec)
* Better React Native support.
* Stylelint integration #490.
* Source maps #469
* Flow and typescript typings for the JSON DSL #375 #361
* Do more benchmarking, include plugins, always track perf regressions.
* Make SSR even better (vendor prefixer server-side, smaller critical CSS)
* Make CLI tool better: allow integration of styles written in various preprocessing languages as well as pure css #166
## Browsers Support
@@ -147,6 +147,8 @@ MIT
Thanks to [BrowserStack](https://www.browserstack.com) for providing the infrastructure that allows us to run our tests in real browsers and to all awesome [contributors](https://github.com/cssinjs/jss/graphs/contributors).
<a href="https://www.browserstack.com" target="_blank"><img src="https://www.browserstack.com/images/layout/logo.svg"></a>
### Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/jss#backer)]
@@ -184,6 +186,8 @@ Support us with a monthly donation and help us continue our activities. [[Become
### Sponsors
[![Chatgrape](https://ug-cdn.com/static/chatgrape/static/images/logo-grape-short-cg-fontrender.svg)](https://www.chatgrape.com/)
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/jss#sponsor)]
<a href="https://opencollective.com/jss/sponsor/0/website" target="_blank"><img src="https://opencollective.com/jss/sponsor/0/avatar.svg"></a>