-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for descendant selectors.
Summary: It turns out descendant selectors are kinda hard. In particular, it's difficult to let *descendants have unique classnames* for themselves, at the same time as allowing *merging between styles which contain descendant selectors*. This pull request attempts to do both of these things. The code is a bit messy, so I'll lay out what's going on in this pull request. Please ask questions, if something is confusing! The Aphrodite code is nice because it's all fairly easily understood, and I'm afraid that this adding too much complexity. An example of the syntax (and an example for the explanation in this commit message), consider: ```js const styles = StyleSheet.create({ parent: { '>>child': { color: "red" }, ':hover': { '>>child': { color: "blue" }, '>>otherchild': { color: "white" } }, }, altparent: { ':hover': { '>>child': { color: "green" } } } }); The basic flow of this diff is: 1. In `StyleSheet.create`, we recurse through the passed-in styles, and find each of the descendant selectors (which have keys that look like `>>blah`). In the example above, it would find `parent['>>child']`, `parent[':hover']['>>child']`, `parent[':hover']['>>otherchild']`, and `altparent[':hover']['>>child']`. In each place, we: - generate a class name for that descendant selector. This is based on the class name of the parent class, as well as the key name. For example, if the class name for `styles.parent` was `parent_abcdef`, we might generate the class name `parent_abcdef__child` for `parent['>>child']`. - tag the style by adding a `_names` object, with the class name as a key of the object. For example, `parent['>>child']` would end up looking like `{ color: "red", _names: { parent_abcdef__child: true } }`. - collect a map of each of the keys (without the `>>` bit) to their class names. For example, for `styles.parent`, we would generate a map that looks like `{ child: "parent_abcdef__child", otherchild: "parent_abcdef__otherchild" }`. We merge in the map from key to class name into the generated style, so that the class names can be accessed using a syntax like `styles.parent.child`. 2. When *parent* styles are passed into `css()`, their styles are merged together. If one style overrides another's descendant styling, the `_names` object will be merged together and will contain all of the associated class names. For example, when evaluating `css(styles.parent, styles.altparent)`, we would end up with merged styles looking like: ``` { '>>child': { color: "red", _names: { parent_abcdef__child: true }, }, ':hover': { '>>child': { color: "green", _names: { parent_abcdef__child: true, altparent_123456__child: true, }, }, '>>otherchild': { color: "white", _names: { parent_abcdef__otherchild: true }, } } } ``` We then generate a map from the descendent keys to all of the class names that could be associated with a given key by recursing and looking at each of the `_names` objects. For example, the map would look like: ``` { '>>child': ["parent_abcdef__child", "altparent_123456__child"], '>>otherchild': ["parent_abcdef__otherchild"] } ``` When generating the styles, we look at this map and then generate styles for each of the classnames listed. This is so that these styles will match up with uses of both `css(styles.parent.child)` and `css(styles.altparent.child)`. For example, when generating the `style[':hover']['>>child']` styles, we generate: ``` .parent_abcdef-o_O-altparent_123456:hover .parent_abcdef__child { ... } .parent_abcdef-o_O-altparent_123456:hover .altparent_123456__child { ... } ``` 3. When *descendant* styles are passed into `css()`, like `css(styles.parent.child)`, we simply return the associated class name (in this case, `"parent_abcdef__child"`) in the output. Fixes #10 Test Plan: - `npm run test` - `cd examples && npm run examples`, then visit http://localhost:4114/ and see that the last line starts green and when "Hover over me" is hovered, the other part turns blue. @zgotsch @jlfwong @kentcdodds @montemishkin
- Loading branch information
Showing
7 changed files
with
653 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.