Open efoken opened 1 year ago
I thought about this. There several different improvements that have to be made:
ThemeProvider
inside Atomico. The same like styled-components has it:<ThemeProvider theme={...}>
// ...
</ThemeProvider>
And then it's possible to use the theme with a hook and in the styles:
const theme = useTheme()
// and
component.styles = (theme) => css`
:host {
color: ${theme.colors.brand};
}
`
And for TypeScript support it should be possible to use declaration merging to extend the theme type:
declare module 'atomico' {
export interface DefaultTheme {
colors: {
brand: string;
};
}
}
css
function from Atomico should be extended to allow passing JS objects to the template string or directly, like it can be done with styled-components:const textStyle = {
marginBottom: 16,
color: 'red',
};
component.styles = css`
:host {
${textStyle}
}
`
Use directly with an object instead of a template string:
const textStyle = {
marginBottom: 16,
color: 'red',
};
component.styles = css({
':host': textStyle,
});
We already did this in our code by extending the css
function from Atomico, I can contribute this. We currently use Stylis to also support Sass-like syntax and nested styles, but I want to refactor this regarding the bundle-size.
Here is how Goober is doing it with only a few lines of code: https://github.com/cristianbote/goober/blob/master/src/css.js https://github.com/cristianbote/goober/blob/master/src/core/parse.js
This leads us to the third improvement:
css
:component.styles = css`
a {
color: red;
&:hover {
color: blue;
}
}
`
Goober is also supporting this with the link above, with only a few lines of code.
That's it for now 😃 What do you think about this?
In the meantime I created this: https://github.com/efoken/atomico-styled
I think the approach of using context to customize appearance is interesting, I personally recommend using customProperties vs the context callack (color:${(theme)=>theme.color.brand}
), since then the css does not need to be reactive, example:
import { styled, Theme } from "atomico-styled";
const Div = style("div")`
:host {
font-size: 200px;
color: var(--color-brand);
}
`;
<Theme value={{ color: { brand: "black" } }}>
<Div>Black</Div>
</Theme>;
This is just theoretical, but it could work
const Styled: Component = () => {
const theme = useContext(Theme);
const props = useAttributes();
Object.assign(props, { theme });
useCssLightDom( cssTransformNested( styles ), `:host{ ${ objectToCustomProperties(props) } }` );
return h("host", null);
};
Atomico core for now only focuses on native CSS support, but we can contribute to its implementation to achieve a more decorated css pre-processing
Sure it is possible to use CSS custom properties, but as I mentioned we cannot use them because we share styles with React Native. Besides that there are also some other disadvantages using CSS custom properties:
theme.text.body
containing fontSize, fontWeight, lineHeight, we would have to use all single values instead of just using object spreading:(theme) => css({
':host': {
...theme.text.body,
color: '#000',
}
})
The theme should only change for example when switching from LightMode to DarkMode. The props used for styling also do only change in rare cases and not all the time – so reactivations should be not that often. Even though my feature request only is for using callback as styles where we have access to the theme context, and not to the props of the component – that's another thing 😄
Anyway the first thing that would be amazing, when the css
function can support nested styles and also passing styles as objects. That should be easy to do with a small amount of code, if you like I can contribute this.
There is an undocumented functionality in Atomico, for confusions with the SSR, the trick is the following:
https://studio.webcomponents.dev/edit/AzdHHrVHCzGQMMbWtkGI/src/theme.jsx?p=stories
from the example above highlighted
index.js
myCounter.styles = css`
* {
font-size: ${"200%"};
}
span {
width: 4rem;
display: inline-block;
text-align: center;
}
button {
width: 4rem;
height: 4rem;
border: none;
border-radius: 10px;
background-color: ${(theme) => theme.color.brand};
color: white;
}
`;
index.stories.js
export const story1 = () => html`
<my-theme value=${{ color: { brand: "black" } }}>
<my-counter></my-counter>
<my-theme> </my-theme
></my-theme>
`;
it's just a prototype, it would be nice to add support for sugar syntax and TS types. \
How is this possible? Atomico allows the component.styles object to be given an Element, internally Atomico will duplicate it at the time of mounted, this helps us internally to support CSSStyleSheet in firefox.
Is your feature request related to a problem? Please describe. Now that the Context API is available in Atomico, it would be very nice to be able to pass callbacks to
component.styles
.Describe the solution you'd like I would like to support the following:
I know there are CSS variables, but as we share our theme with React Native components we cannot use CSS variables. And besides that our theme contains a lot more than just colors, there are even objects containing text styles or shadows.
The question is, how to tell the
Button
component above to useThemeContext
?!Maybe:
or even: