@smartface/contx
Advanced tools
Comparing version 1.1.2 to 1.2.0
@@ -175,3 +175,3 @@ (function (global, factory) { | ||
var oldState = _this.state; | ||
_this.state = Object.assign({}, state); | ||
_this.state = state; | ||
// this.propagateAll(state, oldState); | ||
@@ -193,10 +193,5 @@ } | ||
this.dispatch = function (action, target) { | ||
// if(!this.getReducer()){ | ||
// console.log("Reducer cannot be empty! "+this.getReducer()); | ||
// return; | ||
// } | ||
try { | ||
var state = _this.getReducer()(_this, action, target); | ||
var reducer = _this.getReducer(); | ||
var state = reducer(_this, action, target, _this.state || {}); | ||
_this.setState(state); | ||
@@ -203,0 +198,0 @@ } catch (e) { |
@@ -107,4 +107,3 @@ (function (global, factory) { | ||
function createPageContext(component, name) { | ||
var classMap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
var reducers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
var reducers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
@@ -185,5 +184,5 @@ var styleContext = (0, _fromSFComponent2.default)(component, name, | ||
var _contextReducer = reducers ? function (context, action, target) { | ||
contextReducer(context, action, target); | ||
reducers(context, action, target); | ||
var _contextReducer = reducers ? function (context, action, target, state) { | ||
var newState = contextReducer(context, action, target, state); | ||
return reducers(context, action, target, newState || state); | ||
} : contextReducer; | ||
@@ -205,6 +204,4 @@ | ||
function contextReducer(context, action, target) { | ||
var state = context.getState(); | ||
function contextReducer(context, action, target, state) { | ||
var newState = Object.assign({}, state); | ||
// console.log("page context : "+JSON.stringify(action)); | ||
@@ -261,2 +258,3 @@ switch (action.type) { | ||
case 'pushClassNames': | ||
if (!action.classNames) throw new Error("Classnames must not be null or undefined"); | ||
context.find(target).pushClassNames(action.classNames); | ||
@@ -263,0 +261,0 @@ |
@@ -72,3 +72,3 @@ (function (global, factory) { | ||
var COLOR_PROPS = ["color", "backgroundColor", "textColor", "borderColor", "titleColor", "thumbOffColor", "thumbOnColor", "toggleOffColor", "toggleOnColor", "hintTextColor", "minTrackColor", "maxTrackColor", "thumbColor", "itemColor"]; | ||
var COLOR_PROPS = ["color", "backgroundColor", "textColor", "borderColor", "titleColor", "thumbOffColor", "thumbOnColor", "toggleOffColor", "toggleOnColor", "hintTextColor", "minTrackColor", "maxTrackColor", "thumbColor", "itemColor", "shadowColor"]; | ||
@@ -75,0 +75,0 @@ var IMAGE_PROPS = ["image", "backgroundImage", "thumbImage", "inactiveImage", "maxTrackImage", "minTrackImage", "backIndicatorImage", "icon"]; |
@@ -50,10 +50,5 @@ (function (global, factory) { | ||
// context reducer | ||
function contextUpdater(context, action, target) { | ||
var state = context.getState(); | ||
var newState = state; | ||
function contextUpdater(context, action, target, state) { | ||
var newState = Object.assign({}, state); | ||
if (target || action.type == _constants.INIT_CONTEXT_ACTION_TYPE) { | ||
newState = reducer(context, action, target); | ||
} | ||
switch (action.type) { | ||
@@ -82,2 +77,3 @@ case 'updateContext': | ||
if (target && action.type !== _constants.INIT_CONTEXT_ACTION_TYPE) { | ||
newState = reducer(context, action, target, state); | ||
// state is not changed | ||
@@ -84,0 +80,0 @@ if (newState === state) { |
@@ -168,10 +168,7 @@ (function (global, factory) { | ||
function themesReducer(context, action, target) { | ||
var state = context.getState(); | ||
var newState = state; | ||
function themesReducer(context, action, target, state) { | ||
var newState = Object.assign({}, state); | ||
switch (action.type) { | ||
case 'addThemeable': | ||
// make declarative | ||
var actor = new Themeable(action.pageContext, action.name); | ||
@@ -185,12 +182,7 @@ context.add(actor, action.name); | ||
break; | ||
return newState; | ||
case 'removeThemeable': | ||
context.remove(action.name); | ||
break; | ||
return newState; | ||
case 'changeTheme': | ||
// const current = themesCollection.find(theme => theme.isDefault()); | ||
// context.map((actor) => { | ||
// actor.changeStyling(current.asStyler()); | ||
// }); | ||
themesCollection.forEach(function (theme) { | ||
@@ -210,5 +202,5 @@ if (theme.name === action.theme) { | ||
}); | ||
default: | ||
return newState; | ||
} | ||
return state; | ||
} | ||
@@ -215,0 +207,0 @@ |
{ | ||
"name": "@smartface/contx", | ||
"version": "1.1.2", | ||
"version": "1.2.0", | ||
"description": "Context Manager", | ||
@@ -5,0 +5,0 @@ "scripts": { |
264
README.md
@@ -1,2 +0,3 @@ | ||
[](https://opensource.org/licenses/MIT) | ||
[](https://twitter.com/smartface_io) | ||
[](https://github.com/smartface/contxjs/blob/master/LICENSE) | ||
 | ||
@@ -7,185 +8,24 @@ | ||
## Styling | ||
You may want to take a look at styler [documentation](https://github.com/smartface/styler/blob/master/README.md) | ||
to have a better understanding of how Context works. | ||
### Style Objects | ||
A style object is similar to a CSS definition. We create style objects with selectors then we can use whenever we want to assign them to components. For example: | ||
### Selectors | ||
Styling selectors are also similar to the CSS selectors. There are 2 kinds of selectors. | ||
- "." ClassName selector | ||
- "#" Element ID selector (Just a convention, in fact it's completely same with the classname selector) | ||
```js | ||
const styleObject = { | ||
".calendar":{ | ||
"right":0, | ||
"left":0, | ||
"top":0, | ||
"height":360, | ||
"paddingLeft":0, | ||
"paddingRight":0 | ||
}, | ||
"#articleHeader":{ | ||
"textColor":"#1775D0" | ||
} | ||
} | ||
``` | ||
## Styling Directives and Rules | ||
#### Nested Selectors | ||
```js | ||
const styleObject = { | ||
//base classname | ||
".calendar":{ | ||
// sub classname of .calendar, it interits all styles from base-className .calendar. Usage: .calendar.size | ||
".size":{ | ||
right:0, | ||
left:0, | ||
top:0, | ||
height:360, | ||
paddingLeft:0, | ||
paddingRight:0 | ||
// sub classname of .size, it interits all styles from base-className .calendar.size. Usage: .calendar.size.big | ||
".big": { | ||
height: 600 | ||
} | ||
} | ||
}; | ||
``` | ||
Different from CSS, nested selectors inherit properties from parents and override them if they contain same properties. | ||
#### "&" Parent Selector | ||
Parent selector is a useful tool. For instance you want to use naming conventions like BEM(Block, Element, Modifier) then parent selector helps you to create well documented selectors. For example: | ||
I have a component that name is header and it contains other components that are named **navbar**, **yearLabel** and **arrow**. In the BEM convention, **header** component is our block and these nested components are its elements. Then we can create style object as below. | ||
```js | ||
const styleObject = { | ||
"#header":{ | ||
"&_monthLabel":{ | ||
"textColor":"#1775D0" | ||
}, | ||
"&_yearLabel":{ | ||
"textColor":"#B1B1B4" | ||
}, | ||
"&_arrow":{ | ||
"flexProps":{ | ||
"flexGrow":1, | ||
"textColor":"#B1B1B4" | ||
} | ||
} | ||
} | ||
``` | ||
### Build-time Directives | ||
Build-time directives are run once style-objects are compiled by Styler. | ||
#### @extend Rule | ||
Extend rule provides inheritance between selectors so that selectors can inherit properties from another selectors. **@extend** rule affects all nested-selectors of a selector but not with parent-selector rule(&). For example: | ||
```js | ||
const styles = { | ||
".baseComponent":{ | ||
width: 100, | ||
height: 200, | ||
}, | ||
".anotherBaseComponent":{ | ||
width: 100, | ||
height: 200, | ||
}, | ||
".childComponent":{ | ||
"@extend": ".baseComponent,.anotherBaseComponent" | ||
} | ||
} | ||
``` | ||
### Run-time Directives | ||
Run-time directives are run for each style request by @smartface/styler, when making request to Styler, parent selector's properties are overriden if necessary. | ||
```js | ||
const styles = { | ||
".baseComponent":{ | ||
width: 100, | ||
height: 200 | ||
"+anyRuleCreatedByUser:rule-params":{ | ||
"width": 400 | ||
}, | ||
"+anotherRuleCreatedByUser:rule-params":{ | ||
"width": 400, | ||
"height": 500 | ||
} | ||
} | ||
} | ||
``` | ||
## Styling Conventions and Best Practices | ||
We assume that you know what [BEM](http://getbem.com/) convention is. As a summary, according to [BEM](http://getbem.com/), pages are built with blocks, blocks are built with elements and another blocks. Elements and blocks have modifiers that are used to manipulate their display properties. | ||
For the blocks we can use "\__" or "\_" and for the elements we can use "\__" or "\_" and for the modifiers we can use "\--" or "\-". | ||
For example: | ||
In the CSS | ||
```css | ||
.parentBlock { | ||
... | ||
} | ||
.parentBlock_element { | ||
... | ||
} | ||
.parentBlock_element-modifier { | ||
... | ||
} | ||
.parentBlock_childBlock--modifier { | ||
... | ||
} | ||
/* or with modifiers*/ | ||
.searchBlock_searchInputE{ | ||
} | ||
.searchBlock_searchInput-activated{ | ||
} | ||
.searchBlock_searchInput-deactivated{ | ||
} | ||
/* or with modifiers as variable */ | ||
.searchBlock_searchInput-isActivated--true{ | ||
... | ||
} | ||
.searchBlock_searchInput-isActivated--false{ | ||
... | ||
} | ||
.searchBlock_searchInput-color{ | ||
... | ||
} | ||
.searchBlock_searchInput-color--red{ | ||
... | ||
} | ||
``` | ||
This method makes styles more readable, maintainable and easier to understand. | ||
## Context Management | ||
Each context encapsulates some behaviors and applies theme to decorated components which are came from outside of the context using Context's actors and reducers. | ||
Each context encapsulates some behaviors and applies theme to decorated components | ||
which are came from outside of the context using Context's actors and reducers. | ||
### Contx/Smartface/pageContext | ||
PageContext creates stylable Smartface pages and components so that we can manipulate them using style-objects and selectors. Smartface UI-Editor Transpiler connects Pages and PageContext. To add components dynamically in runtime, (For instance there might be images that should be created after an api call) PageContext's actions must be used. | ||
PageContext creates stylable Smartface pages and components so that we can manipulate | ||
them using style-objects and selectors. Smartface UI-Editor Transpiler connects | ||
Pages and PageContext. To add components dynamically in runtime, (For instance | ||
there might be images that should be created after an api call) PageContext's | ||
actions must be used. | ||
#### Contx/Smartface/pageContext API | ||
##### FlexLayout::children: object | ||
When PageContext is initialized for the first time then it creates component view-tree recursively using FlexLayout's children property. | ||
When PageContext is initialized for the first time then it creates component | ||
view-tree recursively using FlexLayout's children property. | ||
##### Component::dispatch(action:object) | ||
To manipulate Context's states and behaviors, explicitly defined or custom actions must be used so that Context's reducers are triggered. | ||
To manipulate Context's states and behaviors, explicitly defined or custom actions | ||
must be used so that Context's reducers are triggered. | ||
@@ -205,4 +45,12 @@ ##### Contx/Smartface/ | ||
- **Action.type => updateUserStyle** : | ||
Update component userStyle. | ||
- *Action::userStyle:object* | ||
Update component userStyle. | ||
- ```js | ||
button.dispatch({ | ||
type: "updateUserStyle", | ||
userStyle: { | ||
backgroundColor: "#AABBCC" | ||
} | ||
}); | ||
``` | ||
- **Action.type => removeChild** : | ||
@@ -213,8 +61,21 @@ Removes target component and it's children from context. | ||
- **Action.type => pushClassNames** : | ||
Pushes new className selectors to the target component in order to manipulate component properties. | ||
Pushes new className selectors to the target component. | ||
- *Action::classNames:string* for one classname | ||
- *Action::classNames:Array* for multiple classnames | ||
- ```js | ||
button.dispatch({ | ||
type: "pushClassNames", | ||
classNames: [".foo", ".bar"] | ||
}); | ||
``` | ||
- ```js | ||
button.dispatch({ | ||
type: "pushClassNames", | ||
classNames: ".foo" | ||
}); | ||
``` | ||
- **Action.type => removeClassName** : | ||
Removes className selector from specified component. | ||
- *Action::className:string* | ||
- *Action::classNames:string* for one classname | ||
- *Action::classNames:Array* for multiple classnames | ||
- **Action.type => invalidate** : | ||
@@ -227,23 +88,58 @@ Forces to update Context's actors and applies styles if they are changed. | ||
Adds specified component to the FlexLayout instance and if contextName is specified then dispatches addPageContextChild action to the Context. | ||
Adds specified component to target layout and if contextName is specified then | ||
dispatches addPageContextChild action to the Context. | ||
```js | ||
var button = new Button(); | ||
page.layout.addChild(button, "myButton", ".button", { | ||
width: 250, | ||
height: 250 | ||
}); | ||
``` | ||
or | ||
```js | ||
page.layout.addChild(button, "myButton", ".button", function(userProps) { | ||
userProps.width = 250; | ||
userProps.height = 250; | ||
return userProps; | ||
}); | ||
``` | ||
##### FlexLayout::removeChild(childComponent:object) | ||
Removes specified component from FlexLayout instance then dispatches removeChild action to the Context. | ||
Removes specified component from target layout then dispatches removeChild action | ||
to the Context. | ||
```js | ||
// button component will be removed from both context and page layout | ||
page.layout.removeChild(button); | ||
``` | ||
##### FlexLayout::removeAll() | ||
Removes specified component's children then dispatches removeChildren action to the Context. | ||
Removes target component's children then dispatches removeChildren action to | ||
the Context. | ||
```js | ||
// Children of page will be removed from both context and page layout | ||
page.layout.removeAll(); | ||
``` | ||
#### Life-Cycle Events | ||
##### Component::componentDidLeave | ||
When a component is removed from the Context and if the component has componentDidLeave method then it's triggered. | ||
When a component is removed from the Context and if the component has componentDidLeave | ||
method then it's triggered. | ||
##### Component::componentDidEnter(dispatch:function) | ||
When a component initialized in the Context and if the component has componentDidEnter method and then it's triggered by passing it's dispatch method. If not, dispatch method will be assigned to component directly. | ||
When a component initialized in the Context and if the component has componentDidEnter | ||
method and then it's triggered by passing it's dispatch method. If not, dispatch | ||
method will be assigned to component directly. | ||
##### Component::onError(error:Error) | ||
If an error occcurs while an operation is being performed for a component, for example assignment of new properties, and the component has onError method then the error is passed to onError method of the component. If not and then the context throws the error. | ||
If an error occcurs while an operation is being performed for a component, for | ||
example assignment of new properties, and the component has onError method then | ||
the error is passed to onError method of the component. If not and then the | ||
context throws the error. |
92678
33
2179
142