@erickmerchant/framework
Advanced tools
Comparing version 42.0.1 to 42.1.0
export const createApp = (state) => { | ||
let viewCalled = false | ||
let callingView = false | ||
let willCallView = false | ||
let view | ||
const callView = () => { | ||
viewCalled = false | ||
if (willCallView) return | ||
return Promise.resolve().then(() => { | ||
if (!viewCalled && view) { | ||
viewCalled = true | ||
willCallView = true | ||
Promise.resolve().then(() => { | ||
willCallView = false | ||
if (!callingView && view) { | ||
callingView = true | ||
view(get()) | ||
viewCalled = false | ||
callingView = false | ||
} | ||
@@ -23,3 +28,3 @@ }) | ||
set(_, key, val) { | ||
if (viewCalled) return false | ||
if (callingView) return false | ||
@@ -26,0 +31,0 @@ state[key] = val |
@@ -33,3 +33,3 @@ const svgNamespace = 'http://www.w3.org/2000/svg' | ||
const morphAttribute = (target, key, value) => { | ||
const morphAttribute = (target, key, value, isExistingElement) => { | ||
const remove = value == null || value === false | ||
@@ -54,8 +54,8 @@ | ||
} else { | ||
if (remove) { | ||
if (isExistingElement && remove) { | ||
target.removeAttribute(key) | ||
} else { | ||
const stringified = value === true ? '' : value | ||
} else if (!remove) { | ||
const stringified = value === true ? '' : String(value) | ||
if (target.getAttribute(key) !== stringified) { | ||
if (!isExistingElement || target.getAttribute(key) !== stringified) { | ||
target.setAttribute(key, stringified) | ||
@@ -73,6 +73,13 @@ } | ||
const morphChild = (target, childNode, next, variables, isSameView) => { | ||
const morphChild = ( | ||
target, | ||
childNode, | ||
next, | ||
variables, | ||
isExistingElement, | ||
isSameView | ||
) => { | ||
const document = target.ownerDocument | ||
const append = childNode == null | ||
const append = !isExistingElement || childNode == null | ||
@@ -111,5 +118,5 @@ let replace = false | ||
if (next.view != null) { | ||
morphRoot(currentChild, next) | ||
} else if (!isSameView || next.dynamic) { | ||
morph(currentChild, next, variables, isSameView) | ||
morphRoot(currentChild, next, !(append || replace)) | ||
} else if (append || replace || !isSameView || next.dynamic) { | ||
morph(currentChild, next, variables, !(append || replace), isSameView) | ||
} | ||
@@ -127,3 +134,3 @@ } | ||
const morph = (target, next, variables, isSameView) => { | ||
const morph = (target, next, variables, isExistingElement, isSameView) => { | ||
const attributesLength = next.attributes.length | ||
@@ -133,25 +140,27 @@ | ||
for (let i = 0, length = attributesLength; i < length; i++) { | ||
const attribute = next.attributes[i] | ||
if (!isExistingElement || !isSameView || next.dynamic & 0b01) { | ||
for (let i = 0, length = attributesLength; i < length; i++) { | ||
const attribute = next.attributes[i] | ||
if (!isSameView || attribute.variable) { | ||
let value = attribute.value | ||
if (!isExistingElement || !isSameView || attribute.variable) { | ||
let value = attribute.value | ||
if (attribute.variable) { | ||
value = variables[value] | ||
} | ||
if (attribute.variable) { | ||
value = variables[value] | ||
} | ||
if (attribute.key) { | ||
morphAttribute(target, attribute.key, value) | ||
if (attribute.key) { | ||
morphAttribute(target, attribute.key, value, isExistingElement) | ||
attrNames.push(attribute.key) | ||
} else { | ||
const keys = Object.keys(value) | ||
attrNames.push(attribute.key) | ||
} else { | ||
const keys = Object.keys(value) | ||
for (let i = 0, len = keys.length; i < len; i++) { | ||
const key = keys[i] | ||
for (let i = 0, len = keys.length; i < len; i++) { | ||
const key = keys[i] | ||
morphAttribute(target, key, value[key]) | ||
morphAttribute(target, key, value[key], isExistingElement) | ||
attrNames.push(key) | ||
attrNames.push(key) | ||
} | ||
} | ||
@@ -162,3 +171,3 @@ } | ||
if (!isSameView) { | ||
if (isExistingElement && !isSameView) { | ||
for (const attr of target.attributes) { | ||
@@ -172,50 +181,60 @@ if (!~attrNames.indexOf(attr.name)) { | ||
const childrenLength = next.children.length | ||
let childNode = target.firstChild | ||
let deopt = !isSameView | ||
let skip = isExistingElement && isSameView | ||
for (let childIndex = 0; childIndex < childrenLength; childIndex++) { | ||
let child = next.children[childIndex] | ||
if (!isExistingElement || !isSameView || next.dynamic & 0b10) { | ||
for (let childIndex = 0; childIndex < childrenLength; childIndex++) { | ||
let child = next.children[childIndex] | ||
if (!deopt && !child.dynamic && !child.variable) { | ||
childNode = getNextSibling(childNode) | ||
} else { | ||
deopt = true | ||
if (skip && !child.dynamic && !child.variable) { | ||
childNode = getNextSibling(childNode) | ||
} else { | ||
skip = false | ||
if (child.variable) { | ||
const variableValue = child.value | ||
if (child.variable) { | ||
const variableValue = child.value | ||
child = variables[variableValue] | ||
child = variables[variableValue] | ||
if (typeof child === 'string' || child?.[Symbol.iterator] == null) { | ||
if (typeof child === 'string' || child?.[Symbol.iterator] == null) { | ||
child = [child] | ||
} | ||
} else { | ||
child = [child] | ||
} | ||
} else { | ||
child = [child] | ||
} | ||
for (let grand of child) { | ||
if (grand == null || grand.type == null) { | ||
grand = {type: 'text', value: grand == null ? '' : grand} | ||
for (let grand of child) { | ||
if (grand == null || grand.type == null) { | ||
grand = {type: 'text', value: grand == null ? '' : grand} | ||
} | ||
childNode = morphChild( | ||
target, | ||
childNode, | ||
grand, | ||
variables, | ||
isExistingElement, | ||
isSameView | ||
) | ||
} | ||
childNode = morphChild(target, childNode, grand, variables, isSameView) | ||
} | ||
} | ||
} | ||
if (childNode) { | ||
let nextChild | ||
if (childNode) { | ||
let nextChild | ||
do { | ||
nextChild = getNextSibling(childNode) | ||
do { | ||
nextChild = getNextSibling(childNode) | ||
childNode.remove() | ||
childNode.remove() | ||
childNode = nextChild | ||
} while (childNode) | ||
childNode = nextChild | ||
} while (childNode) | ||
} | ||
} | ||
} | ||
const morphRoot = (target, next) => { | ||
const morphRoot = (target, next, isExistingElement = true) => { | ||
const meta = readMeta(target) | ||
@@ -225,8 +244,8 @@ | ||
if (!isSameView) { | ||
if (!isExistingElement || !isSameView) { | ||
meta.view = next.view | ||
} | ||
if (!isSameView || next.dynamic) { | ||
morph(target, next, next.variables, isSameView) | ||
if (!isExistingElement || !isSameView || next.dynamic) { | ||
morph(target, next, next.variables, isExistingElement, isSameView) | ||
} | ||
@@ -233,0 +252,0 @@ } |
12
html.js
@@ -166,3 +166,3 @@ const weakMap = new WeakMap() | ||
type: 'node', | ||
dynamic: false, | ||
dynamic: 0, | ||
attributes: [], | ||
@@ -191,3 +191,3 @@ children: [] | ||
child.dynamic = true | ||
child.dynamic |= 0b01 | ||
@@ -201,3 +201,3 @@ child.attributes.push({ | ||
} else if (token.type === 'variable') { | ||
child.dynamic = true | ||
child.dynamic |= 0b01 | ||
@@ -222,5 +222,5 @@ child.attributes.push({ | ||
} else if (token.type === 'tag') { | ||
const dynamic = parse(tokens, child, token.value) | ||
const dynamic = parse(tokens, child, token.value) ? 0b10 : 0 | ||
child.dynamic = child.dynamic || dynamic | ||
child.dynamic = child.dynamic | dynamic | ||
} else if (token.type === 'text') { | ||
@@ -232,3 +232,3 @@ child.children.push({ | ||
} else if (token.type === 'variable') { | ||
child.dynamic = true | ||
child.dynamic |= 0b10 | ||
@@ -235,0 +235,0 @@ child.children.push({ |
{ | ||
"name": "@erickmerchant/framework", | ||
"version": "42.0.1", | ||
"version": "42.1.0", | ||
"description": "A front-end framework.", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/erickmerchant/framework#readme", |
@@ -1,9 +0,23 @@ | ||
const escape = (str) => | ||
String(str) | ||
.replace(/&/g, '&') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>') | ||
.replace(/"/g, '"') | ||
.replace(/'/g, ''') | ||
const escapeObj = { | ||
'&': '&', | ||
'<': '<', | ||
'>': '>', | ||
'"': '"', | ||
"'": ''' | ||
} | ||
const escapeValuesArr = Object.values(escapeObj) | ||
const escapeKeysStr = Object.keys(escapeObj).join('') | ||
const escapeRegex = new RegExp(escapeKeysStr, 'g') | ||
const escape = (str) => { | ||
try { | ||
return str.replaceAll( | ||
escapeRegex, | ||
(match) => escapeValuesArr[escapeKeysStr.indexOf(match)] | ||
) | ||
} catch { | ||
return str | ||
} | ||
} | ||
const selfClosing = [ | ||
@@ -10,0 +24,0 @@ 'area', |
17653
565