Comparing version 0.0.5 to 0.0.6
{ | ||
"name": "nscss", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "CSS for Components", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
345
README.md
@@ -1,74 +0,54 @@ | ||
# NSCSS | ||
# NSCSS - CSS for Components | ||
## CSS for Components Spec | ||
Styling library for composable components. | ||
### What is it? | ||
#### How it works? | ||
Static styles by source order, compose unique selectors for each scope that override the scoped subtree | ||
Stylesheet has namespace and defines semantic scope parts: | ||
Single declaration: | ||
### TBD | ||
* class - basic definition to build selectors from | ||
* typed class - root, scoped & component | ||
* selector - composed from defined parts | ||
* use class selector instead of element selector | ||
* use custom states inside the owner stylesheet | ||
* multiple different app context | ||
* Per StyleSheet Theme (TODO) | ||
### How it works? | ||
* Static styles by source order | ||
### Features | ||
* Scoped Stylesheet | ||
* Root definition with custom states | ||
* Customization of scoped and inner parts | ||
* Root definition | ||
* Typed selectors | ||
* Custom states | ||
* Complex selectors | ||
* Theme - Global Theme / Per StyleSheet Theme (TODO) | ||
* Theming | ||
* Framework Agnostic | ||
* Easy debugging - readable CSS Class Names, fail-fast evaluation time errors | ||
* Extract plain CSS | ||
* Easy debugging - readable CSS Class Names, fail-fast at evaluation time | ||
* No Runtime Errors 😜 | ||
### Native css support | ||
#### Native css support | ||
* @media query | ||
* @font-face | ||
* Animations (TODO) | ||
* Animations | ||
* Pseudo Elements / Pseudo Classes / Native States | ||
* Child & Attribute selectors | ||
* Child selectors | ||
* Attribute selectors | ||
### Syntax | ||
* Styles As Object Literals | ||
* As Template Literals? | ||
* TypeScript | ||
### React integration | ||
* Component integration | ||
* SSR | ||
### Plugins | ||
#### Plugins & 3rd party integration | ||
* Hooks to allow style transformations (vendor prefixing, etc.) | ||
* Extract plain CSS | ||
* React integration | ||
* IDE Plugins | ||
### Syntax | ||
* TypeScript | ||
* Styles As Object Literals | ||
## Basic Concepts | ||
## Concepts | ||
### Class definition | ||
### Namespace | ||
All Primitive part definitions are class definitions that are used to makeup the selectors. | ||
A class my implement another sheet interface and define states. | ||
Talk about namespace... | ||
### Stylesheet | ||
Stylesheet has namespace and defines semantic scope parts: | ||
Single declaration: | ||
* root - ? | ||
* class - ? can ne auto detected | ||
* component - ? | ||
* scoped - ? | ||
* selector - composed from defined parts | ||
## Usage | ||
### Scoping | ||
Namespace is prefixed to each class name in the stylesheet | ||
@@ -80,4 +60,4 @@ | ||
"@namespace": "App", | ||
"redButton": { color: "red" }, | ||
"blueButton": { color: "blue" } | ||
".redButton": { color: "red" }, | ||
".blueButton": { color: "blue" } | ||
}); | ||
@@ -91,9 +71,8 @@ ``` | ||
### Root definition with custom states | ||
### Root definition | ||
The main className that should be used as for the component root node. | ||
The main class for the component root node. | ||
* Defines component custom states. | ||
* Uses as namespace when namespace is not provided. | ||
* Used as default cascade parent for **component** and **scoped** classes. | ||
* Used as namespace when namespace is not provided | ||
* Used as default cascade parent for **component** and **scoped** classes | ||
@@ -107,3 +86,3 @@ Stylesheet with root: | ||
}, | ||
"root": { color: "red" } | ||
".root": { color: "red" } | ||
}); | ||
@@ -117,17 +96,21 @@ ``` | ||
#### Custom states | ||
### Typed selectors | ||
Custom states in nscss are just mapping between an attribute selector to a name. | ||
Special class definitions for build-in styling strategies. | ||
Root with custom states: | ||
#### Component class | ||
Define a class that build selectors that effect any instance of the component under current stylesheet subtree | ||
```js | ||
const Label = new Stylesheet(...); | ||
new Stylesheet({ | ||
"@define": { | ||
"Button": Stylesheet.root({ | ||
mouseHover: "[data-state-hover]", | ||
disabled: "[data-state-disabled]" | ||
}) | ||
"Button": Stylesheet.root(), | ||
"Label": Stylesheet.component(Label) | ||
}, | ||
"Button": { color: "red" }, | ||
"Button:mouseHover": { color: "green" } | ||
".Label": { color: "red" }, | ||
".Label:hover": { color: "green" }, | ||
".Button:hover .Label": { color: "blue" } | ||
}); | ||
@@ -137,18 +120,12 @@ ``` | ||
```css | ||
.Button◼Button { color: red; } | ||
.Button◼Button[data-state-hover] { color: "green" } | ||
.Button◼Button .Label◼Label { color: red; } | ||
.Button◼Button .Label◼Label:hover { color: green; } | ||
.Button◼Button:hover .Label◼Label { color: blue; } | ||
``` | ||
#### Cascade parent | ||
#### Scope class | ||
Only affects the output css when used with **component** and **scoped** classes. | ||
Define a class that build selectors that target only the component that they are passed to | ||
### Customization (override) | ||
Customization is a way to target component type within your stylesheet | ||
The way to do it is to get the a reference to a stylesheet and use it as **component** or **scoped** override | ||
Customize all labels under root stylesheet using **component**: | ||
```js | ||
//this can be imported from the label stylesheet file. | ||
const Label = new Stylesheet(...); | ||
@@ -159,31 +136,52 @@ | ||
"Button": Stylesheet.root(), | ||
"Label": Stylesheet.component(Label) // use it as a component | ||
"Label": Stylesheet.scoped(Label) | ||
}, | ||
"Label": { color: "red" }, | ||
"Label:hover": { color: "green" }, | ||
"Button:hover Label": { color: "blue" } | ||
".Label": { color: "red" }, | ||
".Label:hover": { color: "green" }, | ||
".Button:hover > .Label": { color: "blue" } | ||
}); | ||
``` | ||
Possible markup (JSX) | ||
```html | ||
<button className="Button"> | ||
<Label/> | ||
<Label className="Label"/> | ||
<button> | ||
``` | ||
CSS output: | ||
```css | ||
.Button◼Button .Label◼Label { color: red; } | ||
.Button◼Button .Label◼Label:hover { color: green; } | ||
.Button◼Button:hover > .Label◼Label { color: blue; } | ||
.Button◼Button .Button◼Label { color: red; } | ||
.Button◼Button .Button◼Label:hover { color: green; } | ||
.Button◼Button:hover > .Button◼Label { color: blue; } | ||
``` | ||
#### Customization of inner parts | ||
Customize with local class that will be place on any of the components **scoped** | ||
When using typed classes, it is possible to style the inner parts with the `::` operator. | ||
This ability can be chained for as many level as needed. | ||
```js | ||
//this can be imported from the label stylesheet file. | ||
const Label = new Stylesheet(...); | ||
const Label = new Stylesheet({ | ||
"@define": { | ||
"Label": Stylesheet.root(), | ||
"Text": Stylesheet.scoped(), | ||
}, | ||
"Text": { color: "red" } // label inner text class | ||
}); | ||
const Button = new Stylesheet({ | ||
"@define": { | ||
"Button": Stylesheet.root(), | ||
"Label": Stylesheet.scoped(Label), | ||
} | ||
}); | ||
new Stylesheet({ | ||
"@define": { | ||
"Button": Stylesheet.root(), | ||
"Label": Stylesheet.scoped(Label) // use it as a scoped | ||
"MyForm": Stylesheet.root(), | ||
"Button": Stylesheet.component(Button), | ||
"SubmitButton": Stylesheet.scoped(Button) | ||
}, | ||
"Label": { color: "red" }, | ||
"Label:hover": { color: "green" }, | ||
"Button:hover > Label": { color: "blue" } | ||
".Button::Label::Text": { color: "green" }, | ||
".SubmitButton::Label::Text": { color: "blue" } | ||
}); | ||
@@ -193,33 +191,79 @@ ``` | ||
```css | ||
.Button◼Button .Button◼Label { color: red; } | ||
.Button◼Button .Button◼Label:hover { color: green; } | ||
.Button◼Button:hover .Button◼Label { color: blue; } | ||
.Label◼Text { color: red; } | ||
.MyForm◼MyForm .Button◼Button .Button◼Label .Label◼Text { color: green; } | ||
.MyForm◼MyForm .MyForm◼SubmitButton.Button◼Button .Button◼Label .Label◼Text { color: blue; } | ||
``` | ||
### Custom states | ||
Custom states are mapping between an attribute selector to a name. | ||
Any class definition can accept states that can be used to build selectors. | ||
#### Customization of inner parts | ||
Root with custom states: | ||
```js | ||
new Stylesheet({ | ||
"@define": { | ||
"Button": Stylesheet.root('div', { | ||
mouseHover: "[data-state-hover]", | ||
disabled: "[data-state-disabled]" | ||
}) | ||
}, | ||
".Button": { color: "red" }, | ||
".Button:mouseHover": { color: "green" } | ||
}); | ||
``` | ||
CSS output: | ||
```css | ||
.Button◼Button { color: red; } | ||
.Button◼Button[data-state-hover] { color: "green" } | ||
``` | ||
Customization of inner parts is done with the :: operator and can be chained as many level that needed. | ||
#### Custom states auto mapping | ||
Requires integration with stylesheet instance to generate state attributes in the default format of `data-${namespace}-${stateName}`. | ||
Target text class inside the label component: | ||
Root with auto states: | ||
```js | ||
//this can be imported from the label stylesheet file. | ||
const Label = new Stylesheet({ | ||
const sheet = new Stylesheet({ | ||
"@define": { | ||
"Label": Stylesheet.root(), | ||
"Button": Stylesheet.root('div', ["mouseHover", "disabled"]) | ||
}, | ||
"text": { color: "red" } // label inner text class | ||
".Button": { color: "red" }, | ||
".Button:mouseHover": { color: "green" } | ||
}); | ||
// possible react use case | ||
function Button(){ | ||
return <button {...sheet.cssStates({mouseHover: true, disabled: false})}></button> | ||
} | ||
``` | ||
CSS output: | ||
```css | ||
.Button◼Button { color: red; } | ||
.Button◼Button[data-Button-mouseHover] { color: "green" } | ||
``` | ||
#### Extend stylesheet | ||
When a stylesheet definition root extends another stylesheet*, it automatically extends states. | ||
* view should have a root component matching the extended sheet. | ||
```js | ||
const Button = new Stylesheet({ | ||
"@define": { | ||
"Button": Stylesheet.root('button', ["hover", "focus"]) | ||
} | ||
}); | ||
new Stylesheet({ | ||
"@define": { | ||
"Button": Stylesheet.root(), | ||
"Label": Stylesheet.component(Label), // target with component | ||
"MyLabel": Stylesheet.scoped(Label) // target with scoped | ||
"ToggleButton": Stylesheet.root(Button, ["toggled", "focus"]) | ||
}, | ||
//target the ::text part | ||
"Label::text": { color: "green" }, | ||
"MyLabel::text": { color: "blue" } | ||
".ToggleButton:active": { color: "black" }, | ||
".ToggleButton:hover": { color: "red" }, | ||
".ToggleButton:toggled": { color: "green" }, | ||
".ToggleButton:focus": { color: "blue" } | ||
}); | ||
@@ -229,7 +273,12 @@ ``` | ||
```css | ||
.Button◼Button .Label◼Label .Label◼text { color: red; } | ||
.Button◼Button .Button◼MyLabel .Label◼text { color: green; } | ||
/* active state is not overrided and default to native */ | ||
.ToggleButton◼ToggleButton:active { color: black; } | ||
/* hover state is not overrided and namespaced by the Button */ | ||
.ToggleButton◼ToggleButton[data-Button-hover] { color: red; } | ||
/* toggled state is new and namespaced by the ToggleButton */ | ||
.ToggleButton◼ToggleButton[data-ToggleButton-toggled] { color: green; } | ||
/* focus state is overriden and namespaced by the ToggleButton */ | ||
.ToggleButton◼ToggleButton[data-ToggleButton-focus] { color: blue; } | ||
``` | ||
### Complex Selectors | ||
@@ -242,21 +291,25 @@ | ||
"@define": { | ||
"Button": Stylesheet.root() | ||
"App": Stylesheet.root() | ||
}, | ||
"container": { ... }, | ||
"btn": { ... }, | ||
"container btn": { | ||
".Button": { | ||
color: "red" | ||
}, | ||
"container[data-active] > label:hover": { | ||
color: "red" | ||
".Container .Button": { | ||
color: "blue" | ||
}, | ||
".Container[data-active] > .Button:hover": { | ||
color: "green" | ||
} | ||
}); | ||
``` | ||
Possible markup | ||
Possible markup (JSX) | ||
```html | ||
<div class="Button"> | ||
<div data-active class="container"> | ||
<button class="btn"></button> | ||
<div className="App"> | ||
<div data-active className="Container"> | ||
<button className="Button"></button> | ||
</div> | ||
<button class="btn"></button> | ||
<div className="Container"> | ||
<button className="Button"></button> | ||
</div> | ||
<button className="Button"></button> | ||
<div> | ||
@@ -268,5 +321,5 @@ ``` | ||
... | ||
/* this is complex part only */ | ||
.Button◼container .Button◼btn { color: blue; } | ||
.Button◼container[data-active] > .Button◼btn:hover { color: blue; } | ||
.App◼Button { color: red; } | ||
.App◼Container .App◼Button { color: blue; } | ||
.App◼Container[data-active] > .App◼Button:hover { color: green; } | ||
``` | ||
@@ -283,5 +336,5 @@ | ||
"@define": { | ||
"Button": Stylesheet.root() | ||
"Button": Stylesheet.root() | ||
}, | ||
"Button": { | ||
".Button": { | ||
color: "{{primaryColor}}" // this will be injected | ||
@@ -300,1 +353,41 @@ } | ||
``` | ||
### Mixins | ||
Mixins are recipes to apply complex rule sets and selectors with simplified interface. | ||
using mixins is very straight forward: | ||
```js | ||
new StyleSheet({ | ||
"@define": { | ||
"Container": StyleSheet.root() | ||
}, | ||
".Container": { | ||
...GridMixin({ itemsPerRow: 3, gutter: '50px' }) | ||
} | ||
}) | ||
``` | ||
CSS output: | ||
```css | ||
.Container◼Container { /* rules for grid container */ } | ||
.Container◼Container > * { /* rules for grid item */ } | ||
``` | ||
### React integration | ||
* Component integration | ||
* SSR | ||
### TBD | ||
* target stylesheet selector part | ||
* multiple different app context -write example | ||
* Per StyleSheet Theme (TODO) | ||
* change `component` class to `subtree` class? | ||
* change `scope` class to `class` class? | ||
* auto internal part `::content` to reference root if not used | ||
* separate stylesheet schema/interface from selector definition for shared interface between sheets | ||
* define stylesheet from css | ||
* order of scoped override in css and dom for readability (.A◼A.B◼B vs .B◼B.A◼A) |
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
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
9798
382