robinweser / fela Goto Github PK
View Code? Open in Web Editor NEWState-Driven Styling in JavaScript
Home Page: http://fela.js.org
License: MIT License
State-Driven Styling in JavaScript
Home Page: http://fela.js.org
License: MIT License
Using Fela with React a lot one will usually pass the renderer via context and then use from within the Components itself. Though rendering keyframes always follows the following pattern (as you can't call the renderer from out of the component)
const keyframe = new Keyframe(props => ({
from: { color: 'red' },
to: { color: 'blue' }
}))
const selector = props => ({
animation: props.name + ' 2s infinite'
})
const className = renderer.render(selector, {
name: renderer.render(keyframe)
})
This will create unnecessary selectors as the static selector styles will output: animation: undefined 2s infinite
. We should therefore be able to to dangerously set a custom animation name.
Because with a fix animation name you can only use the last rendered keyframe variation. Also using this you're not safed from naming collisions.
Code Example:
const keyframe = new Keyframe(props => ({
from: { color: 'red' },
to: { color: 'blue' }
}), 'myanimation')
const selector = props => ({
animation: 'myanimation 2s infinite'
})
const className = renderer.render(selector)
A custom property that merges some styles based on a condition. It would be defined with an expression string such as:
const selector = props => {
color: 'red',
fontSize: '14px',
'isActive=true': {
color: 'blue',
backgroundColor: 'red'
}
}
render(selector, { isActive: true }) // => {font-size:14px;color:blue;background-color:red}
render(selector) // => {color:red;font-size:14px}
See https://github.com/rofrischmann/react-look/blob/develop/packages/react-look-core/modules/mixins/condition.js for an example implementation
We should warn if an invalid unit is passed to improve DX.
Environment: Both
Type: Feature
Right now there is no way to recalculate all the rule-props pairs as they get resolved and compressed once. After compression there is no way to conclude previously used props at all.
Code Example:
const renderer = createRenderer()
let someVar = 'red'
const rule = props => ({
color: props.color,
backgroundColor: someVar
})
renderer.renderRule(rule, { fontSize: '15px' }) // => 'c0 c0-foo'
// .c0 { background-color: red }
someVar = 'blue'
renderer.rehydrate()
// .c0 { background-color: blue }
As https://medium.com/@taion/the-problem-with-css-in-js-circa-mid-2016-14060e69bf68#.wv57un3dw describes there are several problems with not using selectors sometimes.
Actually we could solve this using Fela's props or using sth. like :nth-child
, but we might want to consider adding a special plugin or some default functionality to style child elements e.g. .btn > .child
as well as .btn .child
.
Perhaps its enough to allow the >
selector or use an explicit &
before adding selectors.
const rule = props => ({
color: 'blue',
':hover': {
color: 'red'
}
'& > button': {
color: 'red',
':last-child': {
paddingRight: 10
}
}
})
To be able to use Fela with React Native we need to improve the infrastructure.
generatePropsReference(props)
processStyle(style, meta, plugins)
diffStyle(style, base)
I really like your library and would like to contribute Angular 2 usage Docs and source-code examples.
So my questions:
I would provide you a pull request as soon as I am done. I would try to do a similar app like the current react example and provide a similar doc.
Do you have any other hints or wishes?
cheers,
Bernhard
The following list shows some ideas that we will investigate later this year. It is not said that these get implemented at all, but they for sure at least get considered.
Note: It's not about linting indentation and stuff, but rather about coding style and enforced best practices.
Type: Docs
Would be nice to provide deep detailed information with examples on how the styles are processed, clustered and cached as it is the most important core of Fela.
A lot of methods within StyleSheet are not actually directly bound to it and should be extracted into single utility files. Would also help fo clean up the tests and to improve readability.
We should have a proper build script, that iterates each package, builds UMD builds using Rollup and publishs to npm.
Using the Selector class for complex selectors including media styles is quite comfortable, but often one would just need simple style selectors without media settings at all.
Actually just a function of props that returns an object of styles would be enough - making the composer
a valid functional Selector itself.
This method would also completely remove the need for the basic Fela package itself as long as one is only using functional Selectors.
const selector = props => ({
color: props.color,
font-size: '12px'
})
const renderer = new FelaDOM.Renderer(node)
renderer.render(selector, { color: 'blue' })
DOMRenderer
must accept functional SelectorsenhanceWithPlugins
should also enhance functional SelectorsVersion: 1.0.0
Environment: DOM / Server
Type: Docs
Using Gitbook we were able to launch some initial documentation pages, but there are still a lot missing. Also there are some more topics we'd like to include in the near future.
Next to the DOMRenderer, Fela should also ship a ServerRender which allows to render into a string directly. While this can actually be achieve using a small HTMLElement mock, we should have a more convenient way to handle this.
const selector = new Selector(props => {
color: props.color,
fontSize: '12px'
})
const renderer = new FelaServer.Renderer()
// do some render calls
renderer.render(selector, { color: 'blue' })
renderer.render(selecotr, { color: 'red' })
// get the final CSS string
renderer.renderToString()
The best way to do both would be to pass a renderer into a application which does several .render()
calls. As the API is exactly the same there should not be any problem doing this. Afterwards one could call .renderToString()
to get the CSS output.
As we removed the forced style validation from Fela's core, it would be great to have a plugin that does this job. It should also be able to log and fix (delete) invalid styles.
Sharing static style declarations with all Selector variations could drastically reduce the markup size and improve performance. It would remove redundant styles in favor of reusing them.
e.g.
const selector = props => ({
color: props.color,
fontSize: '12px',
width: '20px',
justifyContent: 'center',
flexWrap: 'nowrap'
})
renderer.render(selector, { props: 'red' }) // => class1
renderer.render(selector, { props: 'blue' }) // => class2
produces the following CSS markup
.class1 {
color: red;
font-size: 12px;
width: 20px;
justify-content: center;
flex-wrap: nowrap
}
.class2 {
color: blue;
font-size: 12px;
width: 20px;
justify-content: center;
flex-wrap: nowrap
}
we could optimize the rendering process to have the following markup:
renderer.render(selector, { props: 'red' }) // => class1 class1-dyn1
renderer.render(selector, { props: 'blue' }) // => class1 class1-dyn2
.class1 {
font-size: 12px;
width: 20px;
justify-content: center;
flex-wrap: nowrap
}
.class1-dyn1 {
color: 'red'
}
.class1-dyn2 {
color: 'blue'
}
In order to get the best (DOM) rendering performance possible, we should generate some basic benchmark to test different methods of adding a new ruleset to a CSSStyleSheet.
node.sheet.insertRule(rule)
node.textContent = updatedCSS
node.textContent += rule
Type: General
We should consider replacing all ECMAScript 2015 Set/Map with plain objects. Map and Set are both great new features, but yet not supported by every major browser (especially older versions which will logically never get native support).
Version: 1.0.1
Environment: Both
Type: Bug
Please try to add as much detail as possible.
const renderer = createRenderer()
renderer.renderStatic({ color: 'red' }, 'div')
renderer.renderStatic({ fontSize: '12px' }, 'div')
Expected CSS output:
div {
color: red
}
div {
font-size: 12px
}
Actual CSS output:
div {
color: red
}
Not only use the selector as a cache reference, but the whole stringified style.
Environment: Both
Type: Feature
Would be great to have a plugin which allows (conditional) style object extension.
We could use the extend
key to specify styles used to extend.
Code Example:
// basic
const baseRules = { backgroundColor: 'red' }
const rule = props => ({
color: 'blue',
// might support multiple objects using arrays
extend: baseRules
})
// conditional
const rule = props => ({
color: 'blue',
// could also support multiple using arrays
extend: {
condition: props.bg === true,
style: {
backgroundColor: 'red'
}
}
})
A plugin that allows the use of custom properties (often refered to as mixins) e.g.
const plugin = customProperty({
size: size => ({
width: size,
height: size
})
})
const styles = {
size: '25px'
}
plugin(styles) // => { width: 25px, height: 25px }
Version: 1.0.0
Environment: DOM / Server
Type: General
As pointed out in #3 we should prefer using CSSOM's insertRule
instead of mutating textContent
. The performance difference can be huge.
@nathanmarks found out that using insertRule
will kill the Chrome DevTools which are very important for debugging though. Using textContent
on the other hand does not interrupt the DevTools.
In order to improve DX we should have a plugin to transform javascript-friendly pseudo class syntax into valid syntax. e.g. { onHover: { /* styles */ }}
would become { ':hover' : { /* styles */ }}
.
In order to get compatible CSS markup, we need to resolve arrays with fallback values into a single string. e.g. display: ['-webkit-flex', 'flex']
should become display:-webkit-flex;display:flex
.
There should be an easy way to do theming.
We could use an enhancer to add a theme as second parameter of each rendering method.
Yet one could also theme using the props or a simple Theme singleton as well.
const theme = {
PRIMARY: 'red',
SECONDARY: 'blue'
}
const renderer = createRenderer({
enhancers: [ theming(theme) ]
})
const rule = (props, theme) => ({
fontSize: props.fontSize,
color: props.color || theme.PRIMARY,
backgroundColor: theme.SECONDARY
})
renderer.renderRule(rule, { fontSize: '15px' }) // => 'c0 c0-foo'
renderer.renderRule(rule, { fontSize: '20px', color: 'green' }) // => 'c0 c0-bar'
.c0 {
color: red;
background-color: blue
}
.c0-foo {
font-size: 15px
}
.c0-bar {
font-size: 20px;
color: green;
}
const theme = {
PRIMARY: 'red',
SECONDARY: 'blue' ,
styles: {
button: {
color: 'blue',
lineHeight: '20px',
padding: '10px'
}
}
}
const rule = (props, theme) => ({
...theme.styles.button,
fontSize: props.fontSize,
backgroundColor: theme.SECONDARY
})
A common use case for a plugin is to add vendor prefixes. We should use inline-style-prefix-all for now and perhaps later add support for inline-style-prefixer as well.
We shoud use a proper warning module that removes all warnings on production build. e.g. Facebook's warning module.
The sort order should be:
:link
:visited
:hover
:active
To create advanced plugins it would be useful to have additional meta data available such as used props, type (keyframe, font, rule, static), rule/keyframe function, etc.
To even provide a better ecosystem, next to plugins we should also add some information on third-party tools and utilites useful for Fela.
Looks like a bug to me:
var fela = {
Selector: Selector,
enhanceWithPlugins: enhanceWithPlugins
};
This is a list of things that need to be done before releasing version 1.0 (first stable).
Fela actually is quite stable and produces correct, minimal and compressed markup. It is just very young (2 weeks~) and therefore not very matured.
(The list might be updated next days)
Most likely every application uses some global styles e.g. CSS resets. Also sometimes you need to render legacy or third-party CSS.
Allow strings and objects passed to a Renderer.
Code Example:
renderer.render('*{margin:0;padding:0}')
// or with ECMAScript 2015 template string
renderer.render(`
* {
margin: 0;
padding: 0
}`)
// object notation for multiple selectors and more readability
renderer.render({
'*': {
margin: 0,
padding: 0
},
'#someid': {
fontSize: '12px'
},
'div': {
display: 'flex'
}
})
Plugins should be allowed (and used) too, but the styles should not be validated so that it comes with the users risk actually.
Type: Docs
As the initial version of react-fela has just been released 🎉 we should link it everywhere talking about Fela + React.
We should somehow simplify how media styles are defined. The MediaSelector is kind of verbose and unhandy to read at all. We should include them into into the selector itself. This would also remove the need for MediaSelectors at all.
Nesting media queries inside selectors.
Code Example:
const selector = props => ({
color: 'red',
'@media (min-height: 300px)': {
color: 'blue'
}
})
It would introduce additional complexity. We would need to split the styles into media parts and afterwards split them into pseudo parts as well.
Actually when rendering fela styles on the server, the new created fela renderer overwrites the styles which are already in DOM.
This causes the browser to rerender all styles which leads to a slight flash of the hole window, because the styles disappear and appear again.
This is quiet annoying.
So in my opinion a solution would be to create two methods in renderer
which can export/import the renderer state.
Cheers
Dustin
As stylelint ships a node API which we could use for style linting.
A plugin that automatically adds units to values if needed. It must consider unitless properties and should also add units to strings like 34
.
Right now styles get clustered into a new object to be able to render them more easily. In order to improve performance we should remove that step completely and directly iterate and render the styles recursively.
Within this progress we should also get rid of the extra style extraction and do that on the fly.
Sorry this is just a question! I'm looking forward to working with Fela, but was wondering how to handle the addCSS
situation I with React-Look (or Radium) where I have an object that looks like:
import theme from 'theme';
const background = {
width: '100%',
height: '100%',
margin: 0,
backgroundColor: theme.greyScale5,
};
const global = {
html: {
...background,
fontSize: '10px',
},
'#root': background,
'#app': background,
body: {
...background,
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
fontSize: '14px',
},
'*': {
boxSizing: 'border-box !important',
outline: 'none !important',
},
a: {
color: theme.primary,
cursor: 'pointer',
},
h2: {
textTransform: 'capitalize',
fontWeight: 300,
margin: '0.5rem 0',
},
};
export default global;
And I want to render that into a global stylesheet. Is this no longer supported, or do I need to write this as a string of css (where I would like the theme values?
Thanks!
I promise to help on this project as soon as this Angular -> React migration is done!
We should remove invalid properties such as dynamic values that do not get a value passed and therefore remain undefined
. This would help to only produce valid CSS markup and to reduce the markup size.
At the moment our stylesheet will keep growing the more selectors we render. We should investigate if this becomes an issue and if so, how we can prevent this and maybe update selectors in-place instead of just adding new ones.
We should provide more examples. Especially at least one non-React example.
To simplify usage we might just pass enhancers to the createRenderer directly just like Redux middlewares can be applied directly.
When using custom fonts, Chrome tries to reload them each time the mountNode gets updated.
This happens for example when using a custom font in a React Component A. When another component gets mounted with new styles, the renderer triggers an update of the mountNode. This replaces all css and forces the browser to refetch the fonts and rerender all text on the website. The user can see this as slight flash of the hole screen (when some Text is on the page).
Maybe fonts should get rendered in a different way.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.