Skip to content

Commit

Permalink
- Fix rendering bugs
Browse files Browse the repository at this point in the history
- Use webpack instead of parcel
- Render array of nodes properly
- Make key and ref as explicit expression (babel-plugin)
- [WIP] Keyed array
  • Loading branch information
s-yadav committed May 18, 2019
1 parent 2785157 commit f0264b1
Show file tree
Hide file tree
Showing 11 changed files with 2,150 additions and 2,155 deletions.
13 changes: 11 additions & 2 deletions example/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { Component, html, createElement } from '../src';

const items = ['Sudhanshu', 'Hactor', 'Himanshu', 'Himan'];

// .filter(str => str.startsWith(value))

function Input (props) {
const { onChange, value, children } = props;
console.log(children);
Expand All @@ -11,7 +15,7 @@ function Input (props) {

export default class App extends Component {
state = {
value: 'test',
value: '',
}
handleChange = (e) => {
const { value } = e.target;
Expand All @@ -20,13 +24,18 @@ export default class App extends Component {
render () {
const { name } = this.props;
const { value } = this.state;
const filteredItems = items.filter(str => str.toLowerCase().startsWith(value.toLowerCase()));
return (
<div id="test">
<span>Hello {name}</span>
<Input value={value} onChange={this.handleChange}>
<span>Hello {value}</span>
</Input>
<span class="from"> ({value})</span>
<ul>
{filteredItems.map((item) => {
return <li key={item} >{item}</li>;
})}
</ul>
</div>
);
}
Expand Down
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"author": "s-yadav <sudhanshuyadav2@gmail.com>",
"license": "MIT",
"scripts": {
"start": "parcel example/index.html --open"
"start": "webpack-dev-server --open"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
Expand All @@ -15,6 +15,7 @@
"@babel/plugin-proposal-object-rest-spread": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"babel-eslint": "^9.0.0",
"babel-loader": "^8.0.6",
"cross-env": "^5.2.0",
"eslint": "^5.9.0",
"eslint-config-airbnb-base": "^13.1.0",
Expand All @@ -23,8 +24,11 @@
"eslint-plugin-node": "^8.0.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"parcel-bundler": "^1.12.3",
"src": "^1.1.2"
"html-webpack-plugin": "^3.2.0",
"src": "^1.1.2",
"webpack": "^4.31.0",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.4.1"
},
"dependencies": {
"@babel/plugin-syntax-jsx": "^7.2.0"
Expand Down
87 changes: 87 additions & 0 deletions references/keyed-nodes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
We can use following to update looped items, and update dom efficiently.

Assumptions:
- Each nodeItem will have the last position, currentPosition and last nodeItem reference.
- Each nodeItem will be storing effectivePosition


Steps:
- If length of last nodeList element is > than the current nodeList elements. You have to remove all nodes between the last item of the new node list and the nextSibling value from the part.
- If newPosition and effectivePosition is not same, add the element on the correct position.
- If the element is string and the last node is not text we can recreate it.
- If the element does not have associated node, create the element
- If any thing is changed from the last

```js

function isArrayNodesChanged (nodes, oldNodes) {
const nodesLength = nodes.length;
if (!oldNodes || nodesLength !== oldNodes.length) return true;
for (let i = 0; i < nodesLength; i++) {
const node = nodes[i];
const oldNode = oldNodes[i];
if (node && isReactLitNode(node)) {
/**
* If node has a key, and old node is present and old node's key and newNode keys match
* then the value is not changed, if not then return true
*/
if (!(node.key && oldNodes && node.key === oldNode.key)) return true;
} else if (isReactLitNode(oldNode)) {
/**
* if oldNode is reactLitNode and new node is not (that will be checked on last if )
* then return true
*/
return true;
}
// No need to match two non ReactLitNodes
}
}

function updateArrayNodes (part, node, oldNode = []) {
const { parentNode, previousSibling, nextSibling } = part;

const nodeLength = Math.max(node.length, oldNode.length);

const nodesChanged = isArrayNodesChanged(node, oldNode);

if (nodesChanged) {
const fragement = document.createFragm
}

let lastNodeOnLoop;
const domNodes = [];
for (let i = 0, ln = node.length; i < ln; i ++) {
const currentNode = node[i];
if () {

} else {
domNodes.push(document.createTextNode(currentNode.toString()));
}
}



for (let i = 0, ln = nodeLength; i < ln; i++) {
const currentNode = node[i] || {};
/**
* get the last node which we will using as previous siblings.
* For the first fragment it will be previousSibling value of the part,
* for the next fragment it will be last element of the fragment nodes.
*/

let _previousSibling = previousSibling;

if (i > 0) {
const lastNodes = node[i - 1].templateNode.nodes;
_previousSibling = lastNodes[lastNodes.length - 1];
}

// update the node and child elements if required
updateNode({
parentNode,
previousSibling: _previousSibling,
nextSibling,
}, currentNode);
}
}
```
14 changes: 9 additions & 5 deletions src/TemplateNode.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { attrMarker, marker } from './TemplateResult';
import { remove } from './utils';
import { remove, toArray } from './utils';

export default class TemplateNode {
constructor (templateResult) {
Expand All @@ -8,10 +8,14 @@ export default class TemplateNode {
// create the template first time the element is used
templateResult.create();

// create dom node out of template
this.node = this.createNode();
// create dom fragment out of template
this.fragment = this.createNode();

this.parts = this.getParts();

// keep the reference of child nodes
// TODO: Check if you want to use Array.from instead
this.nodes = toArray(this.fragment.childNodes);
}
createNode () {
const { template } = this.templateResult;
Expand All @@ -36,10 +40,10 @@ export default class TemplateNode {
);
}
getParts () {
const { node, templateResult } = this;
const { fragment, templateResult } = this;

const { partsMeta } = templateResult;
const walker = this.createWalker(node);
const walker = this.createWalker(fragment);

let partIndex = 0;
let partMeta = partsMeta[partIndex];
Expand Down
4 changes: 4 additions & 0 deletions src/TemplateResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ export default class TemplateResult {
* or an spread attribute. Otherwise it will be a node expression.
*/
if (tagStarted) {
/**
* TODO: Remove this if. This might not be needed as
* we are always treating expression as spread attribute
*/
if (str.endsWith('=')) {
attrName = str.match(EXPRESSION_ATTR_NAME_REGEX)[1];
isAttrValue = true;
Expand Down
6 changes: 1 addition & 5 deletions src/associateInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,18 @@ export default function associateInstance (renderTree, lastRenderedTree) {
return;
}

console.log(node);

debugger;
const defaultNode = Array.isArray(node) ? [] : {};
const oldNode = lastRenderedTree || defaultNode;

if (Array.isArray(node)) {
const nodes = node;
const oldNodes = oldNode;
const oldNodesMap = formNodeMap(oldNodes);

const oldNodesMap = formNodeMap(oldNodes);
for (let i = 0, ln = nodes.length; i < ln; i++) {
const node = nodes[i];
const key = getKey(node, i);
const oldNode = oldNodesMap[key];

if (oldNode) {
associateInstance(node, oldNode);
}
Expand Down
9 changes: 7 additions & 2 deletions src/babel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ function isHTMLElement (tagName) {
return !!tagName && /^[a-z]/.test(tagName);
}

const RESERVED_ATTRIBUTES = {
key: 1,
ref: 1,
};

function needsToBeExpression (tagName, attrName) {
/**
* TODO: No need to change value attribute of a checkbox or radio button.
*/
const tags = ['input', 'select', 'textarea'];
const attributes = ['value', 'defaultValue', 'checked', 'defaultCheckd'];
return tags.includes(tagName) && attributes.includes(attrName);
const attributes = ['value', 'defaultValue', 'checked', 'defaultChecked'];
return RESERVED_ATTRIBUTES[attrName] || (tags.includes(tagName) && attributes.includes(attrName));
}

function BabelPluginReactLit (babel) {
Expand Down
Loading

0 comments on commit f0264b1

Please sign in to comment.