cxs-css / cxs Goto Github PK
View Code? Open in Web Editor NEWfast af css-in-js in 0.7kb
License: MIT License
fast af css-in-js in 0.7kb
License: MIT License
var cxs = require('cxs').default
Otherwise folks who write JavaScript get an error:
csx is not a function
Related threepointone/glamor#201
Use case is using cxs
but to populate an iframe
, currently the parent document is being polluted with CSS.
Since you've moved away from glamor, I was curious if you would be willing to support a plugin system similar to theirs?
I do something similar to your styled-system library with glamor's plugin system right now:
const designSystemPlugins = [
flex,
position,
size,
space,
border,
typography,
color,
elevation,
misc,
fixVerticalRhythm,
]
designSystemPlugins.forEach(func => {
glamor.plugins.add(({ selector, style }) => ({
selector,
style: func(style),
}))
})
It would be awesome if we could do something like this with CXS, where any value I pass like cxs({ elevation: 2 })
would know how to get resolved. This would be similar to something like PostCSS where you can parse styles in one spot and not have to import them every time. I think this could also help with vendor prefixing and being able to handle this in one spot as well.
Hello, guys!
The lib is great. I like it
But, can you, please, explain how to use css animations in cxs function?
So a style like this doesn't appear to correctly produce any pseudo elements:
const style = {
':before': {
content: 'wat',
color: 'red'
},
':after': {
content: 'dafuq',
color: 'blue'
}
}
There are cases where a border declaration to specify color is overridden if the base border style ends up later in the included styles. Here is an example of output (via axs
):
<style type="text/css">
.m-0{margin:0px}.box-sizing-border-box{box-sizing:border-box}.bc-6872e0{background-color:#6872e0}.c-fff{color:#fff}.p-8{padding:8px}@media screen and (min-width:40em){._19tr68s{padding:8px}}@media screen and (min-width:52em){._eov9nk{padding:16px}}@media screen and (min-width:64em){._1ikqg2r{padding:32px}}.fs-24{font-size:24px}@media screen and (min-width:40em){._1wdkpsw{font-size:32px}}@media screen and (min-width:52em){._1ry5oku{font-size:48px}}@media screen and (min-width:64em){._kl9u05{font-size:64px}}.h-6{height:6px}.bc-fff{background-color:#fff}.w-64{width:64px}.mt-8{margin-top:8px}.mb-16{margin-bottom:16px}.border-color-ebedee{border-color:#ebedee}.border-1px_solid{border:1px solid}.cursor-pointer{cursor:pointer}.text-decoration-none{text-decoration:none}._1hjd5bo{transition:transform .25s ease-in-out}._bpjteq:focus{text-decoration:underline}._k2lktg:focus{transform:scale(1.25)}._atw0tk:hover{text-decoration:underline}._j1mkku:hover{transform:scale(1.25)}.c-6872e0{color:#6872e0}
</style>
The problematic portion is near the end of the above blob:
.border-color-ebedee {
border-color: #ebedee;
}
.border-1px_solid {
border: 1px solid;
}
Resulting in the following application of styling (Chrome):
I have time later today to dig into getting a PR together, though perhaps I should wait for the monorepo work to complete?
I have been using styled-jsx but go interested to convert my little project to cxs.
So far, so good. It looks like everything is working but one thing.
I had the following global styles defined that I can't seem to be able to convert to cxs:
body::before {
background-color: #5f00a8;
background: linear-gradient(135deg, #5f00a8 35%, #ed005f 100%);
content: '';
display: block;
height: 3px;
position: fixed;
top: 0;
width: 100%;
z-index: 1;
}
html, body, #root {
height: 100%;
}
Is there any way I can apply styles to the html and body tags of the container page ?
Hey guys!
Awesome work on V3, the modes idea is awesome!
I'm having some problems with animations though..
I've tried using animationName
and @keyframes
but none are outputing css.
cxs({
animationName: {
from: {
background: 'red',
},
to: {
background: 'blue',
},
},
});
or
cxs({
animationName: 'test',
'@keyframes test': {
from: {
background: 'red',
},
to: {
background: 'blue',
},
},
});
Can you guys have a look into it?
Thanks in advance!
This would allow all contributors to use the same version of prettier.
For a specific example of how not doing this complicates PRs, see #86.
Last time I checked (a few months ago) formatting was still changing a decent bit between updates to prettier. Regardless, there's no guarantee it won't change again.
Aloha @jxnblk ๐
First off, thanks a lot for putting your ideas together in cxs
. In a lot of ways, this package powers some of the nice UI abstractions I am building recently.
However, looking at #98, it seems cxs
is not going to be maintained in future. Considering some users (like myself) might still be interested in a small size package that satisfies their styling needs, I started working on a forked version of cxs
in klick
While klick
, attempts to abstract lot of other things (vdom, state container, etc.), the relevant code for styling solution is here. In general, the dist bundle for klick
is tree-shakable, so other features shouldn't be taxing while importing css
from klick
Few areas klick
differs from cxs
klick
uses auto incrementing atomic classnames. I've found this to be generating much smaller class names. Specially helpful in SSR scenarios.klick
is framework agnostic. We support all frameworks by supporting none.klick
attempts to be framework agnostic, it does not have dynamic component styling yet. This is however on my roadmap.Please feel free to close this issue if it seems irrelevant for this repo. I just wanted to get the word out.
Hi there ๐. Great module, I love it!
I just wanted to let you know that I've hacked myself a small setup where I'm able to extract the CXS styles into separated CSS files for production builds with webpack. The benefit of this approach is that webpack will generate a CSS file for each chunk with just the styles that are required.
The setup consists of a custom loader (not published yet) and the extract-text-webpack-plugin.
The loader source:
// exportCssLoader.js
const exportCss = `module.exports = ((cxs, oldExports) => {
const newExports = [[module.id, cxs.getCss()]];
Object.assign(newExports, oldExports);
newExports.locals = oldExports;
cxs.reset();
return newExports;
})(require("cxs"), module.exports);`;
module.exports = function (source, sourceMaps) {
this.callback(null, source + ";" + exportCss, sourceMaps);
};
The webpack config:
// webpack.config.js
...
// loader config
{
test: /\.css\.js$/,
use: ExtractTextPlugin.extract([
// the babel-loader is only required if you use
// ES features that node isn't able to understand
{
loader: "babel-loader",
options: {
cacheDirectory: true,
sourceMaps: false,
},
},
{
loader: require.resolve(
"../tools/webpack/exportCssLoader"
),
},
]),
},
...
// plugin config
new ExtractTextPlugin({
filename: "[name].[contenthash].css",
disable: isDev,
}),
There are maybe some edge cases I haven't thought about yet, but that's the gist. What do you think? Should the loader be published separately or together with this repository?
for npm page
Is there any way or any plans to allow global css creation? Sorry, another feature of glamor that I'm missing and think could be beneficial here ๐
I run into some projects where I need to create html or body styles, or even reset CSS. It'd be nice to stay in one place and be able to do that without creating a stylesheet. I was curious if some things could be tweaked to expose some internal helper to do this?
Also, since I'm on the topic of glamor features, I was wondering if things like fontFace and keyframes features could be added for CXS as well? I'd be happy to submit PR's. I think we could get away with separate packages like import fontFace from 'cxs/font-face'
.
is there a way to do this w/ ::before
and ::after
on the same line to save writing display: "block"
twice?
":hover": {
"::before": {
display: "block"
},
"::after": {
display: "block"
}
}
Code to reproduce
var cxsMonolithic = require('cxs/monolithic').default
cxsMonolithic({ color: ['red', 'rgba(255, 0, 0, 1)']}) //_1ucgkjp
cxsMonolithic.getCss() //'._1ucgkjp{}._1ucgkjp color{0:red;1:rgba(255, 0, 0, 1)}'
I have a few components that are built separately as different bundles. They come with their own styles and get merged into an app.
However, I am not sure cxs supports that kind of use case. Since style tags are added to the parent HTML document there are collisions.
in src/cxs/index.js
, line 20 we have this: const className = 'x' + (rules.length).toString(36)
'x' is a hardcoded prefix. What if we allow alternative prefixes to be passed? Ideally once at initialization of the library.
That way we could define separate prefixes in different projects and when they get mashed up (at runtime for example), the written styles do not collide.
Still having some issues despite my recent PR. If I comment out all the common declarations, all my styles work flawlessly.
As of now, the dist files served by unpkg.com/cxs can't be used (it is in commonjs format) .So, it requires a change in the build system ..Wondering, whether you'll accept a PR ?
Ref: https://mobile.twitter.com/asvny_/status/1037474295822278656
Per #33 (review)
Hello,
Our team have been an user of cxs
for a few months and we like its simplicity and light size. Perfect when shipping simple widgets.
We would love to use it for larger apps and this is why having optional extra features that one could use on top of the library would be great.
I see a few great PRs are waiting to be merged and 2-3 are spot on what we have been looking for.
I do understand that maintaining many open source projects like you do is a super consuming exercise. But instead of having people fork this project to add the bits and pieces they need, it would be great if we could grow this repo. and benefit everybody.
If you are looking for co-maintainers to help out with this library, just give us a shout. As for one would be glad to help out.
Thanks.
You're using a global cache & stylesheet, so why bother including a hash dependency when you control collisions anyway. Your cache is already a hash table, so you could simply use an auto-incrementing global index (ala cxs-{idx}
). An (small) additional benefit beyond the reduced bytes from hash dependency would be the reduced bytes per class name. You could even reset the index via your reset method, for consistent class names when server-side rendering.
Am I missing something?
Great module!!
It appears that the diffing or appending isn't working perfectly.
For CSS rules, properties that can take a number, if you give a number a px
will be appended automatically. It does work with common properties like height
, width
... But it adds unwanted px
for z-index
or flex
for example.
We could document that a workaround to this is to use strings instead of numbers like so for those properties: flex: '1'
or zIndex: '1'
to prevent a px
to be appended.
When using the same media query and style between multiple components the styles are grouped into one media query and class name at the point the first component is rendered. This causes styles in the second component to overwrite the styles used in the media query. In the following example both buttons should be green when the screen width is above 900px:
Hi there, very cool project! ๐
I was just curious what your reasoning was for using insertRule
over something like:
styleTag.appendChild(document.createTextNode(css))
I'm guessing insertRule
probably has better performance (maybe?), but one possible downside I've noticed is it looks like the styles contained in the stylesheet aren't visible when inspecting the style element.
Here's the DOM node:
<h1 data-component="Heading" data-kind="page" class="ff-'Handlee'__cursive">Lacqueristas</h1>
Here's the styling sheet per Chrome:
element.style {
}
@media (min-width: 550px)
h1 {
font-size: 5.0rem;
}
h1 {
font-size: 4.0rem;
line-height: 1.2;
letter-spacing: -.1rem;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 2rem;
font-weight: 300;
}
h1 {
font-size: 2em;
margin: 0.67em 0;
}
Here's the style object:
const headingsStyle = {
page: {fontFamily: "'Handlee', cursive"},
}
Here's the static CSS generated server side:
.ff-'Handlee'__cursive {
font-family: 'Handlee', cursive
}
maybe I'm blind, but it doesn't seem like either of these are used anywhere.
can they be removed? It looks like #80 may address this
While I really love the idea and all, I see the repository hasn't been updated in a very long time. That is kind of a show stopper.
I'm experiencing a lot of issues with media queries and out-of-order/conflicting rules.
Does cxs handle media queries intelligently, ie: are the rules generated in the order provided by the properties? I'm defining these media queries from smallest to largest.
Sometimes it seems adding a property to a media query ends up affecting unrelated things. I haven't been able to pinpoint a specific case, it all feels very arbitrary (although I'm sure there's a good reason as to why it's happening).
Not sure whether this is possible, but think it would have been great if cxs
supported composing of classes. Something like this:
const className = cxs.compose('pa4 code white bg-blue mb2 ba b--black-10')
So that a new class name that will compose all these styles will be created.
Hello,
As far as I know cxs
doesn't support vendor prefixing. When you use "advanced" CSS features this can become a problem for any older browser.
I was wondering if there was a plan to add support for that (increasing the library size) or if there was a way to maybe post-process the CSS generated by cxs
.
In that category I was looking at stylis
that styled-jsx
uses: it is very fast and does prefixing among a few other things. But integration is likely big changes.
If you know of any solution or workaround to use on top of cxs
that we could use today, that would be helpful.
better editor feedback without being aidsy than pretty much every other style library (at least imo)
import React from 'react'
import { HTMLProps, CSSProperties } from 'react'
const h = React.createElement
//new CSSRuleList() //items, length
//let r = new CSSStyleRule
//was using this like this, jus took context out though idk, deal later
//{theme: defined(context.theme, props.theme, pallete: 'none')}
const defined = (...args) => {
for (var i = 0; i < args.length; i++) {
if (args[i] !== undefined) return args[i]
}
}
let cache = {}
let prefix = 'x'
const rules: CSSStyleRule[] = [] //[]
let insert = (rule: CSSStyleRule) => void rules.push(rule as CSSStyleRule)
const hyph = s => s.replace(/[A-Z]|^ms/g, '-$&').toLowerCase()
const mx = (rule, media) => (media ? `${media}{${rule}}` : rule)
const rx = (cn, prop, val) => `.${cn}{${hyph(prop)}:${val}}`
const noAnd = s => s.replace(/&/g, '')
const parse = (obj, child = '', media?) =>
Object.keys(obj)
.map(key => {
const val = obj[key]
if (val === null) return ''
if (typeof val === 'object') {
const m2 = /^@/.test(key) ? key : null
const c2 = m2 ? child : child + key
return parse(val, c2, m2 || media)
}
const _key = key + val + child + media
if (cache[_key]) return cache[_key]
const className = prefix + rules.length.toString(36)
insert(mx(rx(className + noAnd(child), key, val), media))
cache[_key] = className
return className
})
.join(' ')
function cxs(...styles) {
return styles
.map(style => parse(style))
.join(' ')
.trim()
}
cxs.css = () => rules.sort().join('')
cxs.reset = () => {
cache = {}
while (rules.length) rules.pop()
}
cxs.prefix = val => (prefix = val)
if (typeof document !== 'undefined') {
const sheet = document.head.appendChild(document.createElement('style')).sheet as CSSStyleSheet
insert = (rule: CSSStyleRule & string) => {
rules.push(rule as CSSStyleRule)
sheet.insertRule(rule, sheet.cssRules.length)
}
}
type DomProps = Partial<HTMLProps<any>>
type CSX = { css?: CSSProperties }
type StyledCSX = DomProps & CSX
type Proptional<P> = CSSProperties | ((...args: P[]) => CSSProperties)
function styled<P>(C) {
return (...args: Proptional<P>[]) => {
const Comp = (props: P & StyledCSX) => {
const stylePropKeys = [...Object.keys({}), 'css']
//const styleProps = Object.assign({ theme: defined(context.theme, props.theme, {}) }, props)
const next: any = {}
for (let key in props) {
if (stylePropKeys.includes(key)) continue
next[key] = props[key]
}
next.className = [
next.className,
...args
.map(proptional => (typeof proptional === 'function' ? proptional(props) : proptional))
.filter(s => !!s)
.map(s => cxs(s)),
cxs(props.css || {}),
]
.join(' ')
.trim()
return h(C, next)
}
return Comp
}
}
styled.css = cxs.css
styled.reset = cxs.reset
export { cxs }
export { styled }
export default styled
// export function styledComponentWithProps<T, U extends HTMLElement = HTMLElement>(styledFunction: StyledFunction<React.HTMLProps<U>>): StyledFunction<T & React.HTMLProps<U>> {
// return styledFunction as any;
// }
// thanks microsoft, please teach our youth how to read, i think you've got it figured out
// type Unpacked<T> = T extends (infer U)[]
// ? U
// : T extends (...args: any[]) => infer U
// ? U
// : T extends Promise<infer U>
// ? U
// : T
// type T0 = Unpacked<string> // string
// type T1 = Unpacked<string[]> // string
// type T2 = Unpacked<() => string> // string
// type Foo<T> = T extends { a: infer U; b: infer U } ? U : never
// type T10 = Foo<{ a: string; b: string }> // string
// type T11 = Foo<{ a: string; b: number }> // string | number
//type CC = (...args: CSSProperties[]) => infer R ? R : CSSProperties
//type ReturnType<T> = (...args) => T ? T : CSSProperties
// im going to space mountain charley fml
// function styled1(C) {
// return (...args) => {
// const Comp = (props, context: any = {}) => {
// const stylePropKeys = [...Object.keys({}), 'css']
// const styleProps = Object.assign({ theme: defined(context.theme, props.theme, {}) }, props)
// const next: any = {}
// for (let key in props) {
// if (stylePropKeys.includes(key)) continue
// next[key] = props[key]
// }
// next.className = [
// next.className,
// ...args
// .map(a => (typeof a === 'function' ? a(styleProps) : a))
// .filter(s => !!s)
// .map(s => cxs(s)),
// cxs(props.css || {}),
// ]
// .join(' ')
// .trim()
// return h(C, next)
// }
// return Comp
// }
// }
usage
import React from 'react'
import { styled } from './styled'
type Props = {
color: 'green' | 'black'
}
let MyButton = styled<Props>('button')(props => ({
backgroundColor: (props.color && props.color) || 'green',
}))
let NoPropsButton = styled('button')({
backgroundColor: 'green',
})
export { MyButton, NoPropsButton }
let Demo = props => <MyButton onClick={e => console.log('hi')} color={'black'}/>
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.