Comparing version 0.0.4 to 0.1.0
@@ -19,3 +19,3 @@ 'use strict'; | ||
/*:: type ClassName = string | number | { [key: string]: boolean } | ClassName[];*/ | ||
/*:: import type { MaybeClassName } from '../../types';*/ | ||
@@ -36,3 +36,3 @@ | ||
values.forEach(function (value /*: ClassName*/) { | ||
values.forEach(function (value /*: MaybeClassName*/) { | ||
// Empty value or failed condition | ||
@@ -39,0 +39,0 @@ if (!value) { |
@@ -39,3 +39,3 @@ 'use strict'; | ||
/* eslint-disable react/sort-comp */ | ||
/* eslint-disable react/sort-comp, react/no-unused-prop-types */ | ||
@@ -48,2 +48,6 @@ /*:: import type { | ||
} from '../../types';*/ | ||
/*:: type PropsAndState = { | ||
classNames?: ClassNames, | ||
theme?: string, | ||
};*/ | ||
function style(aesthetic /*: Aesthetic*/) /*: (WrappedComponent) => HOCComponent*/ { | ||
@@ -93,5 +97,26 @@ var defaultStyles /*: StyleOrCallback*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
value: function componentWillMount() { | ||
this.transformStyles(this.getTheme(this.props)); | ||
} | ||
// Re-transform if the theme changes | ||
}, { | ||
key: 'componentWillReceiveProps', | ||
value: function componentWillReceiveProps(nextProps /*: PropsAndState*/) { | ||
var theme = this.getTheme(nextProps); | ||
if (theme !== this.state[themePropName]) { | ||
this.transformStyles(theme); | ||
} | ||
} | ||
}, { | ||
key: 'getTheme', | ||
value: function getTheme(props /*: PropsAndState*/) /*: string*/ { | ||
return props[themePropName] || this.context.themeName || ''; | ||
} | ||
}, { | ||
key: 'transformStyles', | ||
value: function transformStyles(theme /*: string*/) { | ||
var _setState; | ||
var theme = this.props[themePropName] || this.context.themeName || ''; | ||
var classNames = aesthetic.transformStyles(styleName, theme); | ||
@@ -98,0 +123,0 @@ |
{ | ||
"name": "aesthetic", | ||
"version": "0.0.4", | ||
"version": "0.1.0", | ||
"description": "Abstract library to support a range of styling options for React components.", | ||
@@ -10,6 +10,3 @@ "keywords": [ | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/milesj/aesthetic.git" | ||
}, | ||
"repository": "https://github.com/milesj/aesthetic/tree/master/packages/aesthetic", | ||
"license": "MIT", | ||
@@ -16,0 +13,0 @@ "main": "./lib/index.js", |
695
README.md
@@ -1,47 +0,286 @@ | ||
# Aesthetic | ||
# Aesthetic v0.1.0 | ||
[![Build Status](https://travis-ci.org/milesj/aesthetic.svg?branch=master)](https://travis-ci.org/milesj/aesthetic) | ||
Abstract library to support a range of styling options for React components. | ||
Aesthetic is a powerful React library for styling components, whether it be CSS-in-JS | ||
using objects, importing stylesheets, or simply referencing external class names. | ||
Simply put, Aesthetic is an abstraction layer that utilizes higher-order-components for | ||
the compilation of styles via third-party libraries, all the while providing customizability, | ||
theming, and a unified syntax. | ||
## Usage | ||
```javascript | ||
import React, { PropTypes } from 'react'; | ||
import { classes, ClassNamesPropType } from 'aesthetic'; | ||
import style from '../path/to/styler'; | ||
How to use this library. | ||
class Carousel extends React.Component { | ||
static propTypes = { | ||
children: PropTypes.node, | ||
classNames: ClassNamesPropType, | ||
}; | ||
### Base Component | ||
// ... | ||
The base component, an abstract component with default styles, | ||
one which all consumers compose around. | ||
render() { | ||
const { children, classNames } = this.props; | ||
const { animating } = this.state; | ||
Is usually provided by a third-party library, like Toolkit, | ||
or simply defined and consumed directly within an application. | ||
return ( | ||
<div | ||
role="tablist" | ||
className={classes({ | ||
classNames.carousel, | ||
animating && classNames.carousel__animating, | ||
})} | ||
> | ||
<ul className={classNames.list}> | ||
{children} | ||
</ul> | ||
Say we're using a third-party library, like Toolkit, which provides | ||
and styles this reusable `Button` component. | ||
<button | ||
type="button" | ||
onClick={this.handlePrev} | ||
className={classes(classNames.button, classNames.prev)} | ||
> | ||
← | ||
</button> | ||
<button | ||
type="button" | ||
onClick={this.handleNext} | ||
className={classes(classNames.button, classNames.next)} | ||
> | ||
→ | ||
</button> | ||
</div> | ||
); | ||
} | ||
} | ||
export default style({ | ||
carousel: { | ||
position: 'relative', | ||
maxWidth: '100%', | ||
// ... | ||
}, | ||
carousel__animating: { ... }, | ||
list: { ... }, | ||
button: { ... }, | ||
prev: { ... }, | ||
next: { ... }, | ||
})(Carousel); | ||
``` | ||
Aesthetic was built for the sole purpose of solving the following scenarios, most of which | ||
competing styling libraries fail to solve. | ||
**Multiple styling patterns** | ||
Want to use external CSS or Sass files? Or maybe CSS modules? Or perhaps CSS-in-JS? | ||
What about JSS instead of Aphrodite? All of these patterns are supported through the | ||
use of [adapters](#style-adapters). However, inline styles *are not supported* | ||
as we prefer the more performant option of compiling styles and attaching them to the DOM. | ||
**Styling third-party libraries** | ||
Using a third-party provided UI component library has the unintended side-effect | ||
of hard-coded and non-customizable styles. Aesthetic solves this problem by allowing | ||
[unlocked styles](#creating-a-styler) to be overwritten by the consumer at most one time. | ||
It also has the added benefit of choosing the styling pattern, as mentioned previously. | ||
```javascript | ||
function Button({ children, styles }) { | ||
// Provider | ||
function Button() { | ||
// ... | ||
} | ||
export default style({ | ||
button: { ... }, | ||
}, { | ||
lockStyling: false, | ||
})(Button); | ||
// Consumer | ||
import Button from 'toolkit/components/Button'; | ||
Button.setStyles({ | ||
button: { ... }, | ||
}); | ||
``` | ||
## Installation | ||
Aesthetic requires React as a peer dependency. | ||
``` | ||
npm install aesthetic react --save | ||
// Or | ||
yarn add aesthetic react | ||
``` | ||
## Documentation | ||
* [Initial Setup](#initial-setup) | ||
* [Webpack](#webpack) | ||
* [Browserify](#browserify) | ||
* [Style Adapters](#style-adapters) | ||
* [Creating A Styler](#creating-a-styler) | ||
* [Defining Components](#defining-components) | ||
* [Overwriting Styles](#overwriting-styles) | ||
* [Combining Classes](#combining-classes) | ||
* [Styling Components](#styling-components) | ||
* [External Classes](#external-classes) | ||
* [Style Objects](#style-objects) | ||
* [Style Functions](#style-functions) | ||
* [Theming Components](#theming-components) | ||
* [Using Theme Styles](#using-theme-styles) | ||
* [Activating Themes](#activating-themes) | ||
* [Unified Syntax](#unified-syntax) | ||
* [Properties](#properties) | ||
* [Pseudos](#pseudos) | ||
* [Fallbacks](#fallbacks) | ||
* [Media Queries](#media-queries) | ||
* [Font Faces](#font-faces) | ||
* [Animations](#animations) | ||
* [Selectors](#selectors) | ||
* [Competitors Comparison](#competitors-comparison) | ||
* [Features](#features) | ||
* [Adapters](#adapters) | ||
### Initial Setup | ||
Aesthetic makes heavy use of `process.env.NODE_ENV` for logging errors in development. | ||
These errors will be entirely removed in production if the following build steps are configured. | ||
#### Webpack | ||
[DefinePlugin](https://webpack.github.io/docs/list-of-plugins.html#defineplugin) plugin | ||
is required when using Webpack. | ||
```javascript | ||
new webpack.DefinePlugin({ | ||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'), | ||
}), | ||
``` | ||
#### Browserify | ||
[Envify](https://github.com/hughsk/envify) transformer is required when using Browserify. | ||
```javascript | ||
envify({ | ||
NODE_ENV: process.env.NODE_ENV || 'production', | ||
}); | ||
``` | ||
### Style Adapters | ||
An adapter in the context of Aesthetic is a third-party library that supports CSS in JavaScript, | ||
whether it be injecting CSS styles based off JavaScript objects, importing CSS during a build | ||
process, or simply referencing CSS class names. | ||
The following libraries and their features are officially supported by Aesthetic. | ||
| Adapter | Unified Syntax | Pseudos | Fallbacks | Fonts | Animations | Media Queries | | ||
| :--- | :---: | :---: | :---: | :---: | :---: | :---: | | ||
| [CSS class names](#external-classes) | | ✓ | ✓ | ✓ | ✓ | ✓ | | ||
| [CSS modules][css-modules] | | ✓ | ✓ | ✓ | ✓ | ✓ | | ||
| [Aphrodite][aphrodite] | ✓ | ✓ | | ✓ | ✓ | ✓ | | ||
| [Glamor][glamor] | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | ||
| [JSS][jss] | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | ||
And the following libraries are not supported. | ||
* [CSSX](https://github.com/krasimir/cssx) - | ||
Does not generate unique class names during compilation and instead | ||
uses the literal class names and or tag names defined in the style declaration. | ||
This allows for global style collisions, which we want to avoid. | ||
### Creating A Styler | ||
To start using Aesthetic, a styler function must be created. This styler function | ||
acts as a factory for the creation of higher-order-components | ||
([HOC](https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e)). | ||
These HOC's are used in transforming styles via adapters and passing down CSS | ||
class names to the original wrapped component. | ||
To begin, we must create an instance of `Aesthetic` with an [adapter](#style-adapters), | ||
pass it to `createStyler`, and export the new function. I suggest doing this an a file | ||
that can be imported for reusability. | ||
```javascript | ||
import Aesthetic, { createStyler } from 'aesthetic'; | ||
import JSSAdapter from 'aesthetic-jss'; // Or your chosen adapter | ||
export default createStyler(new Aesthetic(new JSSAdapter())); | ||
``` | ||
Once we have a styler function, we can import it and wrap our React components. | ||
The styler function accepts a [style declaration](#styling-components) as its first argument, | ||
and an object of configurable options as the second. The following options are supported. | ||
* `styleName` (string) - The unique style name of the component. This name is primarily | ||
used in logging and caching. Defaults to the component name. | ||
* `lockStyling` (boolean) - Will lock styles from being written after the default styles | ||
have been set. Defaults to `true`. | ||
* `classNamesPropName` (string) - Name of the prop in which the compiled class names | ||
object is passed to. Defaults to `classNames`. | ||
* `themePropName` (string) - Name of the prop in which the theme name is passed to. | ||
Defaults to `theme`. | ||
```javascript | ||
export default style({ | ||
button: { ... }, | ||
}, { | ||
styleName: 'CustomButton', | ||
lockStyling: false, | ||
classNamesPropName: 'classes', | ||
themePropName: 'appTheme', | ||
})(Button); | ||
``` | ||
### Defining Components | ||
Now that we have a styler function, we can start styling our components by wrapping | ||
the component declaration with the styler function and passing an object of styles. | ||
When this component is rendered, the style object is transformed into an object of class names, | ||
and passed to the `classNames` prop. | ||
```javascript | ||
import React, { PropTypes } from 'react'; | ||
import { ClassNamesPropType } from 'aesthetic'; | ||
import style from '../path/to/styler'; | ||
function Button({ children, classNames, icon }) { | ||
return ( | ||
<button className={styles.button}>{children}</button> | ||
<button type="button" className={classNames.button}> | ||
{icon && ( | ||
<span className={classNames.icon}>{icon}</span> | ||
)} | ||
{children} | ||
</button> | ||
); | ||
} | ||
Button.propTypes = { | ||
children: PropTypes.node, | ||
classNames: ClassNamesPropType, | ||
icon: PropTypes.node, | ||
}; | ||
export default style({ | ||
button: { | ||
display: 'inline-block', | ||
padding: 5, | ||
}, | ||
button: { ... }, | ||
icon: { ... } | ||
})(Button); | ||
``` | ||
Now, if I consume this library, how can I customize the styles of this button? | ||
What if I want to use class names? Or change the name of existing class names? | ||
What about a theme? Etc. | ||
#### Overwriting Styles | ||
### Overriding Default Styles | ||
Since styles are isolated and colocated within a component, they can be impossible to | ||
customize, especially if the component comes from a third-party library. If a component | ||
hasn't been locked via the `lockStyling` option, styles can be customized by calling | ||
the static `setStyles` method on the wrapped component instance. | ||
All base components can have their styles overridden by the consumer, like so. | ||
This can only be done once in an effort to promote strict isolation and encapsulation. | ||
Style overriding can also be disabled all together. | ||
```javascript | ||
import Button from 'toolkit/components/Button'; | ||
import Button from '../Button'; | ||
@@ -52,30 +291,51 @@ Button.setStyles({ | ||
fontWeight: 'bold', | ||
// ... | ||
}, | ||
}); | ||
// Or merge with the default styles | ||
Button.mergeStyles({ ... }); | ||
``` | ||
And done. We now have a `Button` component that is styled to our application. | ||
Any previous styles that were overwritten will be available when using a | ||
[style function](#style-functions). | ||
We can take this a step further, if need be, by wrapping the base component | ||
with a custom component. | ||
> `setStyles` can only be called once, as styles are immediately locked. | ||
> This avoids unwanted style injections. | ||
### Composed Component | ||
#### Combining Classes | ||
Say we want to execute some logic, or prepare props, before rendering the base button. | ||
We can do this by wrapping the base component with our own component. | ||
When multiple class names need to be applied to a single element, the `classes` | ||
function provided by Aesthetic can be used. This function accepts an arbitrary | ||
number of arguments, all of which can be strings, arrays, or objects that evaluate to true. | ||
```javascript | ||
import BaseButton from 'toolkit/components/Button'; | ||
import { classes } from 'aesthetic'; | ||
// Set styles like before | ||
BaseButton.setStyles({ ... }); | ||
classes( | ||
'foo', | ||
expression && 'bar', | ||
{ | ||
baz: false, | ||
qux: true, | ||
}, | ||
); // foo qux | ||
``` | ||
export default function Button({ children, ...props }) { | ||
// Do something | ||
Using our button style examples above, let's add an active state and can combine classes | ||
like so. Specificity is important, so define styles from top to bottom! | ||
```javascript | ||
function Button({ children, classNames, icon, active = false }) { | ||
return ( | ||
<BaseButton {...props}>{children}</BaseButton> | ||
<button | ||
type="button" | ||
className={classes( | ||
classNames.button, | ||
active && classNames.button__active, | ||
)} | ||
> | ||
{icon && ( | ||
<span className={classNames.icon}>{icon}</span> | ||
)} | ||
{children} | ||
</button> | ||
); | ||
@@ -85,59 +345,342 @@ } | ||
## Adapters | ||
### Styling Components | ||
Only adapters that score a star in all categories are supported: https://github.com/MicheleBertoli/css-in-js | ||
As mentioned previously, to style a component, an object or function must be passed | ||
as the first argument to the [styler function](#creating-a-styler). This object | ||
represents a mapping of elements (and modifiers) to declarations. For example: | ||
### CSS Classes | ||
```javascript | ||
style({ | ||
foo: 'foo', | ||
bar: 'bar', | ||
})(Component); | ||
button: { ... }, | ||
button__active: { ... }, | ||
icon: { ... }, | ||
})(Button) | ||
``` | ||
### CSS Modules | ||
The following types of declarations are permitted. | ||
```css | ||
.foo { | ||
color: 'red'; | ||
display: 'inline'; | ||
} | ||
.bar { | ||
color: 'blue'; | ||
padding: 5px; | ||
} | ||
#### External Classes | ||
External CSS class names can be referenced by passing a string of the class name. | ||
```javascript | ||
style({ | ||
button: 'button', | ||
button__active: 'button--active', | ||
icon: 'button__icon', | ||
})(Button) | ||
``` | ||
To make use of class names, the provided `ClassNameAdapter` must be used. | ||
```javascript | ||
import styles from './styles.css'; | ||
import Aesthetic, { createStyler, ClassNameAdapter } from 'aesthetic'; | ||
style(styles)(Component); | ||
export default createStyler(new Aesthetic(new ClassNameAdapter())); | ||
``` | ||
### Aphrodite, JSS, Glamor, Fela, VStyle, Styletron, Babel CSS-In-JS | ||
#### Style Objects | ||
CSS styles can be defined using an object of properties to values. These objects are | ||
transformed using [adapters](#style-adapters) and optionally support the | ||
[unified syntax](#unified-syntax) defined by Aesthetic. | ||
```javascript | ||
style({ | ||
foo: { | ||
color: 'red', | ||
display: 'inline', | ||
button: { | ||
background: '#eee', | ||
// ... | ||
}, | ||
bar: { | ||
color: 'blue', | ||
padding: 5, | ||
button__active: { | ||
background: '#fff', | ||
// ... | ||
}, | ||
})(Component); | ||
icon: { | ||
display: 'inline-block', | ||
verticalAlign: 'middle', | ||
// ... | ||
}, | ||
})(Button) | ||
``` | ||
### Unsupported Adapters | ||
#### Style Functions | ||
* **CSSX** - Does not generate unique class names during compilation and instead | ||
uses the literal class names and or tag names defined in the style declaration. | ||
This allows for global style collisions, which we want to avoid. | ||
* **Radium** - Uses inline styles instead of compiling and attaching CSS styles | ||
to the DOM. | ||
Style functions are simply functions that return a style object. The benefits of using a | ||
function is that it provides the [current theme](#using-themes) as the first argument, | ||
and the [previous styles](#overwriting-styles) as the second argument. | ||
## Themes | ||
```javascript | ||
style(function (theme, prevStyles) { | ||
// ... | ||
})(Button) | ||
``` | ||
TODO | ||
### Theming Components | ||
Themes are great in that they enable components to be styled in different ways based | ||
on pre-defined style guide parameters, like font size, color hex codes, and more. | ||
To make use of a theme, register it through the `Aesthetic` instance using `registerTheme`. | ||
This method accepts a name, an object of parameters, and an optional | ||
[style object](#style-objects) used for globals (like font faces and animation keyframes). | ||
```javascript | ||
aesthetic.registerTheme('dark', { | ||
unit: 'em', | ||
unitSize: 8, | ||
spacing: 5, | ||
font: 'Roboto', | ||
}, { | ||
'@font-face': { | ||
roboto: { | ||
fontFamily: 'Roboto', | ||
fontStyle: 'normal', | ||
fontWeight: 'normal', | ||
src: "url('roboto.woff2') format('roboto')", | ||
}, | ||
}, | ||
}); | ||
``` | ||
> Global styles are immediately compiled and attached the DOM. Be wary of conflicts. | ||
#### Using Theme Styles | ||
Once a theme has been registered, we can access the style parameters by using a | ||
[style function](#style-functions). The parameters object is passed as the first | ||
argument to the function. | ||
```javascript | ||
style((theme) => ({ | ||
button: { | ||
fontSize: `${theme.unitSize}${theme.unit}`, | ||
fontFamily: theme.font, | ||
padding: theme.spacing, | ||
}, | ||
}))(Component); | ||
``` | ||
#### Activating Themes | ||
To activate and inform components to use a specific theme, we must use the `ThemeProvider`, | ||
which accepts a `name` of the theme. | ||
```javascript | ||
import { ThemeProvider } from 'aesthetic'; | ||
<ThemeProvider name="default"> | ||
// All components within here will use the "default" theme | ||
<ThemeProvider name="dark"> | ||
// And all components here will use "dark" | ||
</ThemeProvider> | ||
</ThemeProvider> | ||
``` | ||
Or by passing a `theme` prop to an individual component. | ||
```javascript | ||
<Button theme="dark">Save</Button> | ||
``` | ||
### Unified Syntax | ||
Aesthetic provides an optional, but enabled by default, unified CSS-in-JS syntax. | ||
This unified syntax permits easy [drop-in replacements](https://en.wikipedia.org/wiki/Drop-in_replacement) | ||
between adapters that utilize CSS-in-JS objects. | ||
**Pros** | ||
* Easily swap between CSS-in-JS adapters (for either performance or extensibility reasons) | ||
without having to rewrite all CSS style object syntax. | ||
* Only have to learn one form of syntax. | ||
**Cons** | ||
* Slight overhead (like milliseconds) converting the unified syntax to the adapters native | ||
syntax. However, Aesthetic caches heavily. | ||
* Must learn a new form of syntax (hopefully the last one). | ||
**Why a new syntax?** | ||
While implementing adapters and writing tests for all their syntax and use cases, I noticed | ||
that all adapters shared about 90-95% of the same syntax. That remaining percentage could | ||
easily be abstracted away by a library, and hence, this unified syntax was created. In the end, | ||
it was mostly for fun, but can easily be disabled if need be. | ||
**Why a different at-rule structure?** | ||
The major difference between the unified syntax and native adapters syntax, is that at-rules | ||
in the unified syntax are now multi-dimensional objects indexed by the name of the at-rule | ||
(`@media`), while at-rules in the native syntax are single objects indexed by the at-rule | ||
declaration (`@media (min-width: 100px)`). | ||
Supporting the native syntax incurred an linear (`O(n)`) lookup, as we would have to loop | ||
through each object recursively to find all at-rules, while the unified syntax is a simple | ||
constant (`O(1)`) lookup as we know the names ahead of time. This constant time lookup is | ||
what enables a fast conversion process between the unified and native syntaxes. | ||
**What if I want to use the adapter's syntax?** | ||
If you'd like to use the native syntax of your chosen adapter, simply call | ||
`disableUnifiedSyntax()` on the instance of your adapter. | ||
#### Properties | ||
Standard structure for defining properties. | ||
* Supports camel case property names. | ||
* Units can be written is literal numbers. | ||
```javascript | ||
button: { | ||
margin: 0, | ||
padding: 5, | ||
display: 'inline-block', | ||
lineHeight: 'normal', | ||
textAlign: 'center', | ||
cursor: 'pointer', | ||
backgroundColor: '#ccc', | ||
color: '#000', | ||
}, | ||
buttonGroup: { | ||
// ... | ||
}, | ||
``` | ||
> JSS requires the `jss-default-unit`, `jss-camel-case`, and `jss-nested` | ||
> plugins for unified syntax support. | ||
#### Pseudos | ||
Pseudo elements and classes are defined inside an element as nested objects. | ||
```javascript | ||
button: { | ||
// ... | ||
':hover': { | ||
backgroundColor: '#eee', | ||
}, | ||
'::before': { | ||
content: '"★"', | ||
display: 'inline-block', | ||
marginRight: 5, | ||
}, | ||
}, | ||
``` | ||
#### Fallbacks | ||
Property fallbacks for old browsers are defined under the `@fallbacks` object. | ||
Each property accepts a single value or an array of values. | ||
```javascript | ||
wrapper: { | ||
// ... | ||
background: 'linear-gradient(...)', | ||
display: 'flex', | ||
'@fallbacks': { | ||
background: 'red', | ||
display: ['box', 'flex-box'], | ||
}, | ||
}, | ||
``` | ||
> Aphrodite does not support fallback styles. | ||
#### Media Queries | ||
Media queries are defined inside an element using a `@media` object. | ||
```javascript | ||
tooltip: { | ||
// ... | ||
maxWidth: 300, | ||
'@media': { | ||
'(min-width: 400px)': { | ||
maxWidth: 'auto', | ||
}, | ||
}, | ||
}, | ||
``` | ||
#### Font Faces | ||
Font faces are defined outside the element using a `@font-face` object | ||
and are referenced by font family name. | ||
```javascript | ||
'@font-face': { | ||
roboto: { | ||
fontFamily: 'Roboto', | ||
fontStyle: 'normal', | ||
fontWeight: 'normal', | ||
src: "url('roboto.woff2') format('roboto')", | ||
}, | ||
}, | ||
button: { | ||
// ... | ||
fontFamily: 'Roboto', | ||
}, | ||
tooltip: { | ||
// ... | ||
fontFamily: 'Roboto, sans-serif', | ||
}, | ||
``` | ||
#### Animations | ||
Animation keyframes are defined outside the element using a `@keyframes` object | ||
and are referenced by animation name (the object key). | ||
```javascript | ||
'@keyframes': { | ||
fade: { | ||
from: { opacity: 0 }, | ||
to: { opacity: 1 }, | ||
}, | ||
}, | ||
button: { | ||
// ... | ||
animationName: 'fade', | ||
animationDuration: '3s', | ||
}, | ||
``` | ||
#### Selectors | ||
Parent, child, and sibling selectors are purposefully not supported. Use unique and | ||
isolated element names and style declarations instead. | ||
### Competitors Comparison | ||
A brief comparison of Aesthetic to competing React style abstraction libraries. | ||
#### Features | ||
| | aesthetic | [react-with-styles][react-with-styles] | [styled-components][styled-components] | [radium][radium] | | ||
| --- | :---: | :---: | :---: | :---: | | ||
| Abstraction | HOC | HOC | Template Literals | HOC | | ||
| Type | Classes | Classes, Inline styles | Classes | Inline styles | | ||
| Unified Syntax | ✓ | | | | | ||
| Caching | ✓ | | ✓ | N/A | | ||
| Themes | ✓ | ✓ | ✓ | | | ||
| Style Overwriting | ✓ | | | || | ||
#### Adapters | ||
| | aesthetic | [react-with-styles][react-with-styles] | [styled-components][styled-components] | [radium][radium] | | ||
| --- | :---: | :---: | :---: | :---: | | ||
| [CSS class names](#external-classes) | ✓ | | | | | ||
| [CSS Modules][css-modules] | ✓ | | | | | ||
| [Aphrodite][aphrodite] | ✓ | ✓ | | | | ||
| [Glamor][glamor] | ✓ | | ✓ | | | ||
| [JSS][jss] | ✓ | ✓ | | | | ||
| [React Native][react-native] | | ✓ | | || | ||
[css-modules]: https://github.com/milesj/aesthetic/tree/master/packages/aesthetic-css-modules | ||
[aphrodite]: https://github.com/milesj/aesthetic/tree/master/packages/aesthetic-aphrodite | ||
[glamor]: https://github.com/milesj/aesthetic/tree/master/packages/aesthetic-glamor | ||
[jss]: https://github.com/milesj/aesthetic/tree/master/packages/aesthetic-jss | ||
[radium]: https://github.com/FormidableLabs/radium | ||
[react-native]: https://github.com/facebook/react-native | ||
[react-with-styles]: https://github.com/airbnb/react-with-styles | ||
[styled-components]: https://github.com/styled-components/styled-components |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
68230
808
685
17