Skip to content

Commit

Permalink
Scoped keyframes (#888)
Browse files Browse the repository at this point in the history
* added fallbacks test to fn rules

* only call onChangeValue if plugins: true

* enable removing props from fn rules

* shorter syntax with coercion

* wip full syntax support

* restore browsers.json

* changelog

* move hook call to the core

* isProcessed flag explanation

* added tests to fn rules

* remove media rule as a function test case

* added a test for #796, as part of #682

* tests for compose plugin

* observables

- move documentation to the package
- update docs, since plugins don't apply by default
- introduce option process: true to the plugin to enable plugins if user wants that

* move fn values docs

* wording

* scoped keyframes

* Added tests for using jss-plugin-syntax-expand with function rules and values

* Skip fn values with jss-expand for now

* use "keyframes-{name}" as a key in KeyFramesRule

Changed the key to a form where it can be used directly as-is for id generation, so we don't have to fake the rule when using generateClassName

* keyframes name parser with validation

* wip keyframes inside of global

* move container rules update to the core

* optimize onProcessStyle

onProcessStyle is invoked on each .update, but in this case we only need to do this once, because fn values can't be added

* put variables in the right scope

* changelog

* update tests with key keyframes name

* Update changelog.md

* Update docs/json-api.md

* Update changelog.md

* process: true always

* support multiple whitespaces after keyframes identifier

* move keyframe name generation to outside

* call external plugins first

we need to separate internal and external queues, queue 0 is external, 1 is internal and 1 is executed always after 0

* move keyframes rule to plugins

* move StyleRule to a plugin

Additionally stop rendering StyleRule when user passes a bad/unknown at-rule

* move viewport rule to plugins

* move simple rule to plugins

* move FontFace rule

* rename plugins to {rule}Rule schema

* beter types for queue

* Add support for animation property

* optimize perf, handle arrays

* fix tests, add more tests

* Fix

* Support arrays

* remove array support

* use global instead of window

* always run  stylerule plugin first, to avoid regexes of the at rules

* ensure to always use style rule as a first rule in plugins

flow started to complain with  "Unused suppression comment." so I removed them

* fix cache plugin

* test raw rule registration order

* rewrite internal plugins queue

* better logic in plugins.use()

* better types

* better types

* fix types

* keyframe inside of global

TODO
- Rethink BaseStyleRule
- Evtl move generateClassName to the rule models
- Evtl rename generateClassName to generateId

* default export in plugins

* move id generator to models

* update snapshots

* fix circular deps

* use CSSKeyframeRule

* generateClassName -> generateId

* added exampls with keyframes to global plugin

* docs, small syntactic changes
  • Loading branch information
kof authored Oct 22, 2018
1 parent a19c871 commit fc3773f
Show file tree
Hide file tree
Showing 83 changed files with 1,153 additions and 602 deletions.
5 changes: 4 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
## Next / 2018-09-16

- Fix multiple cases where linking CSS rules didn't work (#815, #710, #664)
- Added support for Typed CSSOM values (#882)
- Added scoped keyframes support (#346)
- Function values and function rules support now fallbacks, media queries, nesting, global styles (#682)
- Added support for Typed CSSOM values

### Breaking changes

- Observables, function values and rules are now standalone packages, not part of the core. They are still part of the default preset though.
- Function values, rules and observables apply plugins by default now, which means they can support all plugin defined syntaxes, but they are also slower by default. To speed them up use `sheet.update(data, {process: false})` for fn values/rules and `jss.use(pluginObservable({process: false}))` when setting up observables plugin. (#682)
- Rule @keyframes has now scoped name by default, which means that you can access it using `$ref` from the same sheet and generate global one as before using `@global` rule ((#346).
- Options `createGenerateClassName` and `generateClassName` are renamed to `createGenerateId` and `generateId` since th same function is now used to scope @keyframes rules. This affects both JSS and React-JSS.

## 9.8.7 / 2018-06-24

Expand Down
12 changes: 6 additions & 6 deletions docs/js-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default jss

Options:

- `createGenerateClassName` - a function which returns a function which generates unique class names.
- `createGenerateId` - a function which returns a function which generates unique class names.
- `plugins` - an array of functions, will be passed to `jss.use`.
- `virtual` - if true, JSS will use VirtualRenderer.
- `insertionPoint` - string value of a DOM comment node which marks the start of sheets or a rendered DOM node. Sheets rendered by this Jss instance are inserted after this point sequentially.
Expand Down Expand Up @@ -74,7 +74,7 @@ Options:
- `link` - link jss `Rule` instances with DOM `CSSRule` instances so that styles, can be modified dynamically, false by default because it has some performance cost.
- `element` - style element, will create one by default.
- `index` - 0 by default - determines DOM rendering order, higher number = higher specificity (inserted after).
- `generateClassName` - a function that generates a unique class name.
- `generateId` - a function that generates a unique class name.
- `classNamePrefix` - a string, which will be added at the beginning of the class name.

```javascript
Expand Down Expand Up @@ -358,22 +358,22 @@ console.log(sheet.toString())

## Generate your own class names

`createGenerateClassName`
`createGenerateId`

Option `createGenerateClassName` allows you to specify a function which returns a class name generator function `generateClassName(rule, sheet)`. This pattern is used to allow JSS reset the counter upon factory invocation, when needed. For example, it is used in [React-JSS](https://github.com/cssinjs/react-jss) to reset the counter on each request for server-side rendering.
Option `createGenerateId` allows you to specify a function which returns a class name generator function `generateId(rule, sheet)`. This pattern is used to allow JSS reset the counter upon factory invocation, when needed. For example, it is used in [React-JSS](https://github.com/cssinjs/react-jss) to reset the counter on each request for server-side rendering.

By default class names generator uses a simple counter to ensure uniqueness of the class names. It consists of `classNamePrefix` Style Sheet option + rule name + counter. **Note**: in production (`NODE_ENV=production`) it uses just the `c` + rules counter.

```javascript
import jss from 'jss'

const createGenerateClassName = () => {
const createGenerateId = () => {
let counter = 0

return (rule, sheet) => `pizza--${rule.key}-${counter++}`
}

jss.setup({createGenerateClassName})
jss.setup({createGenerateId})

const sheet = jss.createStyleSheet({
button: {
Expand Down
25 changes: 11 additions & 14 deletions docs/json-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,41 +69,38 @@ Compiles to:

## Keyframes Animation

Note: keyframe id is still global and may conflict.
Keyframes name will use the same id generator function as the class names. Animation name will be scoped by default. In order to access it within the same style sheet, you can use `$ref` syntax as a value of `animationName` or `animation` property.

```javascript
const styles = {
'@keyframes my-animation': {
from: {opacity: 0},
to: {opacity: 1}
}
}
```
Additionally generated name can be accessed through `sheet.keyframes.{name}` map.

### ES6 with generated keyframe id
In order to generate a global animation name, you can use `@global` rule.

```javascript
const animationId = Math.random()

const styles = {
[`@keyframes ${animationId}`]: {
'@keyframes slideRight': {
from: {opacity: 0},
to: {opacity: 1}
},
container: {
animationName: '$slideRight'
}
}
```

Compiles to:

```css
@keyframes my-animation {
@keyframes keyframes-slideRight-0-1-2 {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.container-0-1-3 {
animation-name: keyframes-slideRight-0-1-2;
}
```

## Fallbacks
Expand Down
24 changes: 12 additions & 12 deletions packages/jss-plugin-cache/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"dist/jss-plugin-cache.js": {
"bundled": 1058,
"minified": 515,
"gzipped": 330
"bundled": 1066,
"minified": 518,
"gzipped": 331
},
"dist/jss-plugin-cache.min.js": {
"bundled": 1058,
"minified": 515,
"gzipped": 330
"bundled": 1066,
"minified": 518,
"gzipped": 331
},
"dist/jss-plugin-cache.cjs.js": {
"bundled": 740,
"minified": 368,
"gzipped": 256
"bundled": 748,
"minified": 371,
"gzipped": 258
},
"dist/jss-plugin-cache.esm.js": {
"bundled": 658,
"minified": 299,
"gzipped": 213,
"bundled": 666,
"minified": 302,
"gzipped": 215,
"treeshaked": {
"rollup": {
"code": 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/jss-plugin-cache/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default function cachePlugin(): Plugin {
const cache = new WeakMap()

function onCreateRule(name, decl, {parent}) {
return parent ? cache.get(parent.rules.raw[name]) || null : null
return parent && name ? cache.get(parent.rules.raw[name]) || null : null
}

function onProcessRule(rule) {
Expand Down
2 changes: 1 addition & 1 deletion packages/jss-plugin-props-sort/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {create} from 'jss'
import propsSort from './index'

const settings = {
createGenerateClassName: () => rule => `${rule.key}-id`
createGenerateId: () => rule => `${rule.key}-id`
}

describe('jss-plugin-props-sort', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/jss-plugin-syntax-camel-case/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import functionPlugin from 'jss-plugin-syntax-rule-value-function'
import camelCase from './index'

const settings = {
createGenerateClassName: () => rule => `${rule.key}-id`
createGenerateId: () => rule => `${rule.key}-id`
}

describe('jss-plugin-syntax-camel-case', () => {
Expand Down
24 changes: 12 additions & 12 deletions packages/jss-plugin-syntax-compose/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"dist/jss-plugin-syntax-compose.js": {
"bundled": 3738,
"minified": 1342,
"gzipped": 756
"bundled": 3745,
"minified": 1345,
"gzipped": 761
},
"dist/jss-plugin-syntax-compose.min.js": {
"bundled": 2622,
"minified": 822,
"gzipped": 485
"bundled": 2629,
"minified": 825,
"gzipped": 487
},
"dist/jss-plugin-syntax-compose.cjs.js": {
"bundled": 2005,
"minified": 840,
"gzipped": 470
"bundled": 2012,
"minified": 843,
"gzipped": 471
},
"dist/jss-plugin-syntax-compose.esm.js": {
"bundled": 1787,
"minified": 668,
"gzipped": 381,
"bundled": 1794,
"minified": 671,
"gzipped": 385,
"treeshaked": {
"rollup": {
"code": 16,
Expand Down
2 changes: 1 addition & 1 deletion packages/jss-plugin-syntax-compose/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function registerClass(rule, className) {
*/
export default function jssCompose(): Plugin {
function onProcessStyle(style, rule) {
if (!style.composes) return style
if (!('composes' in style)) return style
registerClass(rule, style.composes)
// Remove composes property to prevent infinite loop.
delete style.composes
Expand Down
2 changes: 1 addition & 1 deletion packages/jss-plugin-syntax-compose/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import expect from 'expect.js'
import {create} from 'jss'
import compose from '.'

const settings = {createGenerateClassName: () => rule => `${rule.key}-id`}
const settings = {createGenerateId: () => rule => `${rule.key}-id`}

describe('jss-plugin-syntax-compose', () => {
let jss
Expand Down
8 changes: 4 additions & 4 deletions packages/jss-plugin-syntax-default-unit/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"dist/jss-plugin-syntax-default-unit.js": {
"bundled": 5874,
"bundled": 5916,
"minified": 2738,
"gzipped": 1051
},
"dist/jss-plugin-syntax-default-unit.min.js": {
"bundled": 5874,
"bundled": 5916,
"minified": 2738,
"gzipped": 1051
},
"dist/jss-plugin-syntax-default-unit.cjs.js": {
"bundled": 5183,
"bundled": 5221,
"minified": 2843,
"gzipped": 1020
},
"dist/jss-plugin-syntax-default-unit.esm.js": {
"bundled": 5103,
"bundled": 5141,
"minified": 2777,
"gzipped": 965,
"treeshaked": {
Expand Down
2 changes: 2 additions & 0 deletions packages/jss-plugin-syntax-default-unit/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function iterate(prop, value, options) {

if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
// $FlowFixMe
value[i] = iterate(prop, value[i], options)
}
} else if (typeof value === 'object') {
Expand Down Expand Up @@ -79,6 +80,7 @@ export default function defaultUnit(options: Options = {}): Plugin {
}

function onChangeValue(value, prop) {
// $FlowFixMe
return iterate(prop, value, camelCasedOptions)
}

Expand Down
6 changes: 3 additions & 3 deletions packages/jss-plugin-syntax-default-unit/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import functionPlugin from 'jss-plugin-syntax-rule-value-function'
import defaultUnit from './index'

const settings = {
createGenerateClassName: () => rule => `${rule.key}-id`
createGenerateId: () => rule => `${rule.key}-id`
}

describe('jss-plugin-syntax-default-unit', () => {
Expand Down Expand Up @@ -114,7 +114,7 @@ describe('jss-plugin-syntax-default-unit', () => {
border: 3
}
},
'@keyframes id': {
'@keyframes a': {
from: {top: 0},
'30%': {top: 30},
'60%, 70%': {top: 80}
Expand All @@ -134,7 +134,7 @@ describe('jss-plugin-syntax-default-unit', () => {
' border: 3px;\n' +
' }\n' +
'}\n' +
'@keyframes id {\n' +
'@keyframes keyframes-a-id {\n' +
' from {\n' +
' top: 0;\n' +
' }\n' +
Expand Down
2 changes: 1 addition & 1 deletion packages/jss-plugin-syntax-expand/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import observablePlugin from 'jss-plugin-syntax-rule-value-observable'
import expand from '.'

const settings = {
createGenerateClassName: () => rule => `${rule.key}-id`
createGenerateId: () => rule => `${rule.key}-id`
}

describe('jss-plugin-syntax-expand', () => {
Expand Down
24 changes: 12 additions & 12 deletions packages/jss-plugin-syntax-extend/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"dist/jss-plugin-syntax-extend.js": {
"bundled": 5265,
"minified": 1801,
"gzipped": 912
"bundled": 5328,
"minified": 1824,
"gzipped": 919
},
"dist/jss-plugin-syntax-extend.min.js": {
"bundled": 4149,
"minified": 1281,
"gzipped": 630
"bundled": 4212,
"minified": 1304,
"gzipped": 639
},
"dist/jss-plugin-syntax-extend.cjs.js": {
"bundled": 3447,
"minified": 1384,
"gzipped": 620
"bundled": 3504,
"minified": 1407,
"gzipped": 627
},
"dist/jss-plugin-syntax-extend.esm.js": {
"bundled": 3229,
"minified": 1216,
"gzipped": 551,
"bundled": 3286,
"minified": 1239,
"gzipped": 558,
"treeshaked": {
"rollup": {
"code": 16,
Expand Down
14 changes: 8 additions & 6 deletions packages/jss-plugin-syntax-extend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,15 @@ export default function jssExtend(): Plugin {
return null
}

// $FlowFixMe: This will be an object
for (const key in value) {
rule.prop(key, value[key])
}
if (typeof value === 'object') {
// $FlowFixMe: This will be an object
for (const key in value) {
rule.prop(key, value[key])
}

// $FlowFixMe: Flow complains because there is no indexer property in StyleRule
rule[valueNs] = value
// $FlowFixMe: Flow complains because there is no indexer property in StyleRule
rule[valueNs] = value
}

// Make sure we don't set the value in the core.
return null
Expand Down
2 changes: 1 addition & 1 deletion packages/jss-plugin-syntax-extend/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {create} from 'jss'
import extend from './index'

const settings = {
createGenerateClassName: () => rule => `${rule.key}-id`
createGenerateId: () => rule => `${rule.key}-id`
}

describe('jss-plugin-syntax-extend', () => {
Expand Down
Loading

0 comments on commit fc3773f

Please sign in to comment.