Jss: Support full syntax in function rules and values

Created on 12 Feb 2018  Â·  21Comments  Â·  Source: cssinjs/jss

Currently the only plugin that we run over function values/rules is jss-default-unit. The problem with running every plugin over it is that we would add performance overhead to something that is supposed to be usable for animations.

Originates in https://github.com/cssinjs/react-jss/issues/185

Cases:

  • [x] fallbacks in fn rules
  • [x] media queries inside of function rules
  • [x] media query as a fn rule nested
  • [x] function values inside of media rules
  • [x] jss-nested inside of fn rules
  • [x] jss-nested as a fn rule
  • [x] jss-global should support function values and rules
  • [x] jss-compose should support linking function rules
  • [x] jss-compose should support linking rules with fn values
  • [x] jss.use(pluginObservable({process: false})), test for disabling plugins
high feature request important

Most helpful comment

Hi,

I'm using [email protected] and can't figure out how to make @global and dynamic values work together (I'm not sure this is the right thread, but similar issues points to this one).

I've been able to do it easily with jss only, like you can see in this pen: https://codesandbox.io/s/jss-dynamic-global-value-7n9rb

But I'm not able to achieve the same behaviour with react-jss: https://codesandbox.io/s/react-jss-dynamic-global-value-j552b. I've checked the doc: am I missing something obvious?

I've found a workaround by importing the jss instance (import { jss } from "react-jss";), but this doesn't seem right.

Thanks! I love this project.

All 21 comments

I got an idea what we can do here: due to the fact that other cssinjs libs have also functions and they don't expect those to be updatable at 60 FPS we can do this:

  1. We assume that mainstream use case doesn't need to update at 60FPS
  2. We allow all required plugins to react on the values/rules changes like they do for normal values
  3. Introduce a modified interface for "fast" functions:
{
  button: {
   // If value is an array and first item is a function, we got a function value.
    top: [props => props.top]
  }
}
{
   // If rule is an array and first item is a function, we got a fast function rule.
  button: [(props) => ({
    top: props.top
  })
}

Additionally we could allow passing options:

{
  button: {
   // Second array value is an options object.
    top: [props => props.top, {someOptions}]
  }
}

Another interface idea:

// This function name could be something else…
import {fast} from 'jss'
{
  // fast() will mark the function with a flag that allows to distinguish "fast" functions without plugins.
  button: fast((props) => ({
    top: props.top
  }))  
}    

I am open for any other interface suggestions.

Fast functions being ones that require updates at 60fps?

Fast functions being ones which can be updated frequently using .update() method without being slow for animations or other types of frequent updates.

Basically current function values/rules implementation IS the "fast" version, which is why I couldn't add all plugins to the results they return, because that would slow them down.

So we need a way to use the entire JSS syntax for more "static" use cases, where static doesn't mean it can be done only once, but it shouldn't be updated frequently. This is the way styled-components is using them. At the same time I want to keep the "fast" version for frequent updates.

So we need to distinguish those 2 versions somehow.

@kof I got another idea according to "fast" functions. Maybe better to revert your idea, and use such kind of wrapper for function values/rules only if needed to isolate block (class name) from root scope? Let's say this would be named as "slow" function. It will be executed separately with all of the plugins enabled by a user.

@AleshaOleg people expect all rules to work the same way with fn values, because other libraries support this. JSS is the only one with "fast" functions, thats why I think we should go by default for slow version and make fast optional. Another reason is that having animations is also not the most popular use cases compared to props based regular styling.

Idea: we can make function values/rules "slow" by default and only keep Observables as fast by default. The reasons are:

  1. Animations is not a very popular use case and it can still be done with passing an option to sheet.update()
  2. Observables is a nice interface and requires only a minimal polyfill to get started, one doesn't necessarily need a reactive library.

The benefits are

  1. There will be no confusion about fast/slow functions
  2. It will be easier to get typings done, since return value from function values/rules will be the same as the main declaration syntax.

That being said, we can reintroduce fast functions later on if there is a need as a new feature, since it requires a new interface now anyways.

Removed #474 and #796 from description, they require more work related to react-jss, too big for this task.

Implemented in #878

how can we right the JSS for the below example :

<Collapsible trigger="Start here">
    <p>This is the collapsible content. It can be any element or React component you like.</p>
  </Collapsible>

CSS is:

.Collapsible__trigger {
display: block;
font-weight: 600;
text-decoration: none;
color: #ffffff;
position: relative;
border: 1px solid white;
padding: 10px;
background: #f3f4f4;
color: black;
}
.Collapsible__trigger:after {
font-family: 'FontAwesome';
content: 'f107';
position: absolute;
right: 10px;
top: 10px;
display: block;
transition: transform 300ms;
}
.Collapsible__trigger.is-open:after {
transform: rotateZ(180deg);
}
.Collapsible__trigger.is-disabled {
opacity: 0.5;
background-color: grey; }

Can You please any one help me about this

You will need to use jss-nested for that: https://cssinjs.org/jss-nested?v=v6.0.1

i've done like this.....
but still im not able to get that

refineContainer: {
border: '1px solid',
'@global': {
'& > span > & .Collapsible__trigger': {
display: 'block',
fontWeight: '600',
textDecoration: 'none',
position: 'relative',
border: '1px solid white',
padding: '10px',
background: '#f3f4f4',
color: 'black',
'&::after': {
fontFamily: 'FontAwesome',
content: 'f107',
position: 'absolute',
right: '10px',
top: '10px',
display: 'block',
transition: ' transform 300ms',
},
'&::is-open:after': {
transform: ' rotateZ(180deg)',
},
'&::is-disabled': {
opacity: '0.5',
backgroundColor: 'grey',
},
},
},
},

Please create a seperate issue, this is not the topic of the issue.

Please create a seperate issue, this is not the topic of the issue.

You will need to use jss-nested for that: https://cssinjs.org/jss-nested?v=v6.0.1

i tried that but am not able to get that

Implemented in #878

When will this be made publicly available? There have been no releases since July. 😢

You can help doing it, otherwise just wait and watch issues, we are working on a big release.

Hi,

I'm using [email protected] and can't figure out how to make @global and dynamic values work together (I'm not sure this is the right thread, but similar issues points to this one).

I've been able to do it easily with jss only, like you can see in this pen: https://codesandbox.io/s/jss-dynamic-global-value-7n9rb

But I'm not able to achieve the same behaviour with react-jss: https://codesandbox.io/s/react-jss-dynamic-global-value-j552b. I've checked the doc: am I missing something obvious?

I've found a workaround by importing the jss instance (import { jss } from "react-jss";), but this doesn't seem right.

Thanks! I love this project.

@monsieur-z have you found a way?

Hi,

I'm using [email protected] and can't figure out how to make @global and dynamic values work together (I'm not sure this is the right thread, but similar issues points to this one).

I've been able to do it easily with jss only, like you can see in this pen: https://codesandbox.io/s/jss-dynamic-global-value-7n9rb

But I'm not able to achieve the same behaviour with react-jss: https://codesandbox.io/s/react-jss-dynamic-global-value-j552b. I've checked the doc: am I missing something obvious?

I've found a workaround by importing the jss instance (import { jss } from "react-jss";), but this doesn't seem right.

Thanks! I love this project.

Can you explain more about your workaround using jss instance? I encountered same issue and still can't find a solution

There's no more to it than what's in this pen: https://codesandbox.io/s/jss-dynamic-global-value-7n9rb

So I got dynamic global styles working by wrapping it in a function.

import { createUseStyles as createJssUseStyles } from 'react-jss'
import React from 'react'
import ReactDOM from 'react-dom'

const createUseStyles = ({ color }) => {
  return createJssUseStyles({
    test: {
      height: 30
    },
    // you need to have the local class outside of \@global and @global styles must come after
    // eslint-disable-next-line sort-keys
    '@global': {
      '.wrapper': {
        '& $test': {
          background: color
        }
      }
    }
  })
}

const Test = ({ color }) => {
  const classes = createUseStyles({ color })()

  return (
    <div className='wrapper'>
      <div className={classes.test}>TESTO</div>
    </div>
  )
}

Some observations:

  1. You need to have the local class outside of @global and @global styles must come after
  2. There needs to be at least ONE global class wrapping the local class.
  3. You need to write the classes in separate lines at least for the first two classes including @global. You can't do '@global': { '.wrapper & $test': {...}}}

@sam-m-m this is going to generate styles every time component updates, don't recommend doing this

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brianmhunt picture brianmhunt  Â·  5Comments

trusktr picture trusktr  Â·  6Comments

brianmhunt picture brianmhunt  Â·  5Comments

mg901 picture mg901  Â·  3Comments

glowkeeper picture glowkeeper  Â·  5Comments