Skip to content

Commit

Permalink
fix: fix the context-element change requestAnimationFrame
Browse files Browse the repository at this point in the history
Fix the context element change request anmiation frame to timeout
  • Loading branch information
marsa-emreef committed Jun 30, 2020
1 parent 1e27a85 commit a4e33fe
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 54 deletions.
48 changes: 48 additions & 0 deletions example/color-palette/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
body{
margin: 0px;
padding: 0px;
}
.container{
display: flex;
width: 100vw;
height : 100vh;
align-items: center;
justify-content: center;
}
.box{
background-color: rgba(0,0,0,0);
display: inline-block;
border: 10rem solid rgba(0,0,0,0);
border-bottom:77rem solid rgba(255,0,0,1);
transform: rotate(0deg);
transform-origin: top;
}
.box-container{
margin-top: -10rem;
}
.dot{
width: 2px;
height: 2px;
display: flex;
justify-content: center;
transform: rotate(10deg);
position: absolute;
}
.context-array{
width: 40rem;
height: 40rem;
border-radius: 40rem;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
position: absolute;

}
.palates-container{
position: relative;
display: flex;
align-items: center;
justify-content: center;

}
25 changes: 25 additions & 0 deletions example/color-palette/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Color Palete</title>
<link rel="stylesheet" href="index.css">
<script src="../../src/index.ts"></script>
</head>
<body>
<div class="container">
<context-element id="palate">
<context-array data.watch="palateOne" data.key="id" class="palates-container">
<context-array data.watch="palateTwo" data.key="id" class="context-array" style.watch="scale">
<div class="dot" style.watch="style">
<div class="box-container">
<div class="box" style.watch="colorStyle" onmouseenter.action="SET_COLOR"></div>
</div>
</div>
</context-array>
</context-array>
</context-element>
</div>
<script src="index.js"></script>
</body>
</html>
35 changes: 35 additions & 0 deletions example/color-palette/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
document.body.onload = () => {
const palateElement = document.getElementById('palate');
const layer = 16;
const maximumHueColor = 360;
const palate = 24;
const degree = Math.round(maximumHueColor / palate );
const saturationRange = 50;
const lightRange = 60;
palateElement.data = {
palateOne : Array.from({length:layer}).map((_,id) => {
const layerIndex = id;
const saturation = Math.round((saturationRange / layer) * (layer - (layerIndex + 0)));
const scale = `transform : scale(${ (1/layer) * (layer - layerIndex) })`;
const light = Math.round((lightRange / layer) * (layer - layerIndex));
return {
id,
scale,
palateTwo : Array.from({length:(palate)}).map((_,id) => {
const colorStyle = `border-bottom-color: hsl(${degree * id},${(100 - saturationRange)+saturation}%,${light + 20 }%) !important`;
return {
id,
style:`transform : rotate(${(degree) * id}deg)`,
colorStyle
}
})
}
})
}

palateElement.reducer = (context,action) => {
debugger;
console.log(action);
return {...context};
}
};
4 changes: 3 additions & 1 deletion src/array-context-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ export class ArrayContextElement<Context> extends ContextElement<Context[]> {
const contextData: Context[] = this.contextData;
const template: ChildNode[] = this.template;
const renderers: Map<string, Renderer> = this.renderers;

if (hasNoValue(contextData) || hasNoValue(template)) {
return;
}

this.removeExpiredData();
let anchorNode: Node = document.createElement('template');
this.append(anchorNode);
Expand All @@ -112,7 +114,7 @@ export class ArrayContextElement<Context> extends ContextElement<Context[]> {
const dataKey = this.dataKeyPicker(data);
if (!renderers.has(dataKey)) {
const dataNode: ChildNode[] = template.map(node => node.cloneNode(true)) as ChildNode[];
const itemRenderer = new DataRenderer(dataNode,this.getAsset, this.updateDataCallback, () => this.reducer);
const itemRenderer = new DataRenderer(dataNode,this.getAsset, this.updateDataCallback, () => this.reducer,this.updateParentDataCallback);
renderers.set(dataKey, itemRenderer);
}
const itemRenderer = renderers.get(dataKey);
Expand Down
44 changes: 41 additions & 3 deletions src/context-element.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import {composeChangeEventName, DataGetter, DataSetter, hasNoValue, hasValue, HIDE_CLASS, Reducer} from "./types";
import {
Action, ArrayAction, ArrayDataGetterValue, ChildAction,
composeChangeEventName,
DataGetter,
DataSetter,
hasNoValue,
hasValue,
HIDE_CLASS,
Reducer, STATE_GLOBAL
} from "./types";
import noEmptyTextNode from "./libs/no-empty-text-node";
import DataRenderer from "./libs/data-renderer";

Expand Down Expand Up @@ -33,6 +42,7 @@ export class ContextElement<Context> extends HTMLElement {
protected contextData: Context;
protected onMountedCallback: () => void;
private superContextElement:ContextElement<any>;
public dataPath:string;

/**
* Constructor sets default value of reducer to return the parameter immediately (param) => param.
Expand Down Expand Up @@ -104,13 +114,15 @@ export class ContextElement<Context> extends HTMLElement {
const requestAnimationFrameCallback = () => {
this.populateTemplate();
this.classList.remove(HIDE_CLASS);

this.render();
if (hasValue(this.onMountedCallback)) {
this.onMountedCallback();
this.onMountedCallback = null;
}
};
requestAnimationFrame(requestAnimationFrameCallback);
//requestAnimationFrame(requestAnimationFrameCallback);
setTimeout(requestAnimationFrameCallback,0);
}
}

Expand Down Expand Up @@ -139,6 +151,31 @@ export class ContextElement<Context> extends HTMLElement {
}
};

protected updateParentDataCallback = (action:ArrayAction<any>|Action) => {
const arrayAction = (action as ArrayAction<any>);
const childAction:ChildAction = {
event : action.event,
path:this.dataPath,
type:action.type,
index : arrayAction.index,
key : arrayAction.key,
data : arrayAction.data
};
this.superContextElement?.updateDataFromChild(childAction);
};

protected updateDataFromChild = (action:ChildAction) => {
const reducer = this.reducer;
this.updateDataCallback((oldData:Context) => {
if(hasNoValue(reducer)){
action.path = `${this.dataPath}.${action.path}`;
this.superContextElement?.updateDataFromChild(action);
return oldData;
}
return reducer(oldData, action);
});
};

/**
* render method is invoked by the component when it received a new data-update.
* First it will create DataRenderer object if its not exist.
Expand All @@ -158,7 +195,7 @@ export class ContextElement<Context> extends HTMLElement {
}
if (hasNoValue(this.renderer)) {
const dataNodes: ChildNode[] = this.template.map(node => node.cloneNode(true)) as ChildNode[];
this.renderer = new DataRenderer(dataNodes,this.getAsset, this.updateDataCallback,() => this.reducer);
this.renderer = new DataRenderer(dataNodes,this.getAsset, this.updateDataCallback,() => this.reducer,this.updateParentDataCallback);
}
const reversedNodes: Node[] = [...this.renderer.nodes].reverse();
let anchorNode: Node = document.createElement('template');
Expand Down Expand Up @@ -222,4 +259,5 @@ export class ContextElement<Context> extends HTMLElement {
}
return null;
};

}
53 changes: 30 additions & 23 deletions src/libs/attribute-evaluator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Action, ArrayAction,
ArrayDataGetterValue,
AssetGetter,
composeChangeEventName,
Expand All @@ -14,7 +15,7 @@ import {
ReducerGetter,
STATE_GLOBAL,
STATE_PROPERTY,
UpdateDataCallback
UpdateDataCallback, UpdateParentDataCallback
} from "../types";
import isValidAttribute from "./attribute-validator";
import {toggleMissingStateAndProperty} from "./error-message";
Expand Down Expand Up @@ -73,10 +74,15 @@ export default class AttributeEvaluator<Context> {
*/
private readonly updateData: UpdateDataCallback<Context>;

/**
* Update parent data is a callback to bubble action to the parent.
*/
private readonly updateParentData:UpdateParentDataCallback<Context>;

/**
* callback function that is called when an action is triggered by dom event.
*/
private readonly reducer: ReducerGetter<Context>;
private readonly reducerGetter: ReducerGetter<Context>;

// mapping for watch & assets
private readonly stateAttributeProperty: Map<string,Map<string, Map<string, string>>> = null;
Expand All @@ -96,22 +102,23 @@ export default class AttributeEvaluator<Context> {
* @param assetGetter : callback function to get the asset from context-data
* @param dataGetter : callback function to return current data.
* @param updateData : callback function to inform DataRenderer that a new data is created because of user action.
* @param reducer : function to map data into a new one because of user action.
* @param reducerGetter : function to map data into a new one because of user action.
* @param activeAttributes : attributes that is used to lookup the nodes
*/
constructor(activeNode: ChildNode,assetGetter:AssetGetter, dataGetter: DataGetter<Context>, updateData: UpdateDataCallback<Context>, reducer: ReducerGetter<Context>,activeAttributes:string[]) {
constructor(activeNode: ChildNode,assetGetter:AssetGetter, dataGetter: DataGetter<Context>, updateData: UpdateDataCallback<Context>, reducerGetter: ReducerGetter<Context>,activeAttributes:string[],updateParentData:UpdateParentDataCallback<Context>) {
this.activeNode = activeNode;
this.dataGetter = dataGetter;
this.assetGetter = assetGetter;
this.updateData = updateData;
this.reducer = reducer;
this.updateParentData = updateParentData;
this.reducerGetter = reducerGetter;
this.activeAttributeValue = populateActiveAttributeValue(activeNode as HTMLElement,activeAttributes);
this.defaultAttributeValue = populateDefaultAttributeValue(activeNode as HTMLElement);
this.eventStateAction = mapEventStateAction(this.activeAttributeValue);
this.stateAttributeProperty = mapStateAttributeProperty(this.activeAttributeValue,[DATA_WATCH_ATTRIBUTE,DATA_ASSET_ATTRIBUTE]);
this.attributeStateProperty = mapAttributeStateProperty(this.activeAttributeValue,DATA_TOGGLE_ATTRIBUTE);

initEventListener(activeNode as HTMLElement, this.eventStateAction, dataGetter, updateData, reducer);
initEventListener(activeNode as HTMLElement, this.eventStateAction, dataGetter, updateData, reducerGetter,updateParentData);
}

/**
Expand Down Expand Up @@ -263,38 +270,35 @@ const populateActiveAttributeValue = (element: HTMLElement,activeAttributes:stri
* @param eventStateAction
* @param dataGetter
* @param updateData
* @param reducer
* @param reducerGetter
*/
const initEventListener = <Context>(element: HTMLElement, eventStateAction: Map<string, Map<string, string>>, dataGetter: DataGetter<Context>, updateData: UpdateDataCallback<Context>, reducer:ReducerGetter<Context>) => {
const initEventListener = <Context>(element: HTMLElement, eventStateAction: Map<string, Map<string, string>>, dataGetter: DataGetter<Context>, updateData: UpdateDataCallback<Context>, reducerGetter:ReducerGetter<Context>,updateParentData:UpdateParentDataCallback<Context>) => {
eventStateAction.forEach((stateAction: Map<string, string>, event: string) => {

event = event.startsWith('on') ? event.substring('on'.length, event.length) : event;
element.addEventListener(event, (event: Event) => {
if (event.type === 'submit') {
event.preventDefault();
event.stopImmediatePropagation();
event.stopPropagation();
}
event.preventDefault();
event.stopImmediatePropagation();
const dataGetterValue: DataGetterValue<any>|ArrayDataGetterValue<any> = dataGetter();
let dataState = dataGetterValue.data[STATE_PROPERTY];
if (stateAction.has(dataState) || stateAction.has(STATE_GLOBAL)) {
updateData((oldData) => {

const reducer = reducerGetter();
const type = stateAction.get(dataState) || stateAction.get(STATE_GLOBAL);
let data = dataGetterValue.data;
const action:any = {type,event};
if('key' in dataGetterValue){
const arrayDataGetterValue = dataGetterValue as ArrayDataGetterValue<any>;
data = arrayDataGetterValue.data;
debugger;
return reducer()(oldData, {
type,
event,
data,
key: arrayDataGetterValue.key,
index: arrayDataGetterValue.index
});
action.data = data;
action.key = arrayDataGetterValue.key;
action.index = arrayDataGetterValue.index;
}
if(hasNoValue(reducer)){
updateParentData(action);
return oldData;
}
return reducer()(oldData, {type,event});
return reducer(oldData, action);
});
}
})
Expand All @@ -317,6 +321,9 @@ function setPropertyValue(attribute: string, element: any, val: any, data: any,
}
if (attribute in element) {
element[attribute] = val;
if(attribute === 'data'){
element.dataPath = property;
}
const eventName = composeChangeEventName(attribute);
element[eventName] = (val: any) => injectValue(data, property, val);
}
Expand Down
Loading

0 comments on commit a4e33fe

Please sign in to comment.