@semantic-ui/component
Advanced tools
Comparing version 0.0.33 to 0.0.34
@@ -15,8 +15,8 @@ { | ||
"dependencies": { | ||
"@semantic-ui/query": "^0.0.33", | ||
"@semantic-ui/reactivity": "^0.0.33", | ||
"@semantic-ui/templating": "^0.0.33", | ||
"@semantic-ui/utils": "^0.0.33" | ||
"@semantic-ui/query": "^0.0.34", | ||
"@semantic-ui/reactivity": "^0.0.34", | ||
"@semantic-ui/templating": "^0.0.34", | ||
"@semantic-ui/utils": "^0.0.34" | ||
}, | ||
"version": "0.0.33" | ||
"version": "0.0.34" | ||
} |
@@ -40,3 +40,2 @@ import { unsafeCSS } from 'lit'; | ||
} = {}) => { | ||
// AST shared across instances | ||
@@ -43,0 +42,0 @@ if(!ast) { |
@@ -41,2 +41,5 @@ import { nothing } from 'lit'; | ||
let value; | ||
if (this.reaction) { | ||
this.reaction.stop(); | ||
} | ||
this.reaction = Reaction.create((computation) => { | ||
@@ -43,0 +46,0 @@ if(!this.isConnected) { |
@@ -1,16 +0,7 @@ | ||
import { nothing, noChange } from 'lit'; | ||
import { repeat } from 'lit/directives/repeat.js'; | ||
import { directive } from 'lit/directive.js'; | ||
import { insertPart, getCommittedValue, removePart, setCommittedValue, setChildPartValue } from 'lit/directive-helpers.js'; | ||
import { AsyncDirective } from 'lit/async-directive.js'; | ||
import { Reaction } from '@semantic-ui/reactivity'; | ||
import { hashCode, clone, isEqual, each, isPlainObject, isString } from '@semantic-ui/utils'; | ||
const generateMap = (list, start, end) => { | ||
const map = new Map(); | ||
for (let i = start; i <= end; i++) { | ||
map.set(list[i], i); | ||
} | ||
return map; | ||
}; | ||
import { isPlainObject, isString } from '@semantic-ui/utils'; | ||
@@ -21,35 +12,10 @@ export class ReactiveEachDirective extends AsyncDirective { | ||
this.reaction = null; | ||
this.part = null; | ||
this.items = []; | ||
this.eachCondition = null; | ||
this.host = partInfo?.options?.host; | ||
this.initialized = false; | ||
this.childParts = []; | ||
this.templateCachedIndex = new Map(); | ||
this.templateCachedData = new Map(); | ||
this.templateCache = new Map(); | ||
} | ||
render(eachCondition, data) { | ||
render(eachCondition, settings = {}) { | ||
this.eachCondition = eachCondition; | ||
if (!this.reaction) { | ||
this.reaction = Reaction.create((comp) => { | ||
if (!this.isConnected) { | ||
comp.stop(); | ||
return nothing; | ||
} | ||
const items = this.getItems(eachCondition); // setup reactivity | ||
this.updateItems(items); | ||
}); | ||
} | ||
return this.getValuesAndKeys().values.map( | ||
(value, index) => value(index).content | ||
); | ||
} | ||
update(part, settings) { | ||
this.part = part; | ||
return this.render.apply(this, settings); | ||
} | ||
disconnected() { | ||
// Stop existing reaction | ||
if (this.reaction) { | ||
@@ -59,35 +25,36 @@ this.reaction.stop(); | ||
} | ||
} | ||
getItems() { | ||
let items = this.eachCondition.over() || []; | ||
if(!items?.map) { | ||
return; | ||
} | ||
items = items.map((item, index) => { | ||
if (isPlainObject(item) && !this.getItemID(item, index)) { | ||
item._hash = hashCode(item); | ||
// Create a new reaction | ||
this.reaction = Reaction.create((computation) => { | ||
if (!this.isConnected) { | ||
computation.stop(); | ||
return; | ||
} | ||
return item; | ||
this.items = this.getItems(this.eachCondition); | ||
const rendered = this.renderItems(); | ||
if (!computation.firstRun) { | ||
this.setValue(rendered); | ||
} | ||
}); | ||
return items; | ||
return this.renderItems(); | ||
} | ||
getValuesAndKeys(items = this.getItems()) { | ||
const keys = []; | ||
const values = []; | ||
items = items || []; | ||
each(items, (item, index) => { | ||
keys[index] = this.getItemID(item, index); | ||
// we only want to lazily get new template if the contents have changed | ||
values[index] = (passedIndex = index) => { | ||
return this.getTemplate(item, passedIndex); | ||
}; | ||
}); | ||
return { | ||
values, | ||
keys, | ||
}; | ||
renderItems() { | ||
return repeat( | ||
this.items, | ||
(item, index) => this.getItemID(item, index), | ||
(item, index) => this.getTemplate(item, index) | ||
); | ||
} | ||
getItems() { | ||
return this.eachCondition.over() || []; | ||
} | ||
getTemplate(item, index) { | ||
const templateData = this.getEachData(item, index, this.eachCondition.as); | ||
return this.eachCondition.content(templateData); | ||
} | ||
getItemID(item, index) { | ||
@@ -97,3 +64,3 @@ if (isPlainObject(item)) { | ||
} | ||
if (isString) { | ||
if (isString(item)) { | ||
return item; | ||
@@ -110,149 +77,12 @@ } | ||
getTemplate(item, index) { | ||
// memoize this | ||
let eachData = this.getEachData(item, index, this.eachCondition.as); | ||
const itemID = this.getItemID(item, index); | ||
const sameIndex = this.templateCachedIndex.get(itemID) == index; | ||
const sameData = isEqual(this.templateCachedData.get(itemID), eachData); | ||
if (false && sameIndex && sameData) { | ||
// reuse the template nothing to rerender | ||
return { | ||
cached: true, | ||
content: this.templateCache.get(itemID), | ||
}; | ||
disconnected() { | ||
if (this.reaction) { | ||
this.reaction.stop(); | ||
this.reaction = null; | ||
} | ||
else { | ||
// something has changed for this template | ||
const content = this.eachCondition.content(eachData); | ||
this.templateCachedIndex.set(itemID, index); | ||
this.templateCachedData.set(itemID, clone(eachData)); | ||
this.templateCache.set(itemID, content); | ||
return { | ||
cached: false, | ||
content: content, | ||
}; | ||
} | ||
} | ||
/* | ||
Adapted from Lit's Repeat Directive | ||
The key difference is we dont want to rerender templates (call content()) | ||
if the position doesnt move. | ||
*/ | ||
updateItems(items = this.getItems()) { | ||
const containerPart = this.part; | ||
if (!this.part) { | ||
return; | ||
} | ||
const oldParts = getCommittedValue(containerPart); | ||
const { values: newValues, keys: newKeys } = this.getValuesAndKeys(items); | ||
if (!Array.isArray(oldParts)) { | ||
this._itemKeys = newKeys; | ||
return newValues; | ||
} | ||
const oldKeys = (this._itemKeys ??= []); | ||
const newParts = []; | ||
let newKeyToIndexMap; | ||
let oldKeyToIndexMap; | ||
let oldHead = 0; | ||
let oldTail = oldParts.length - 1; | ||
let newHead = 0; | ||
let newTail = newValues.length - 1; | ||
while (oldHead <= oldTail && newHead <= newTail) { | ||
if (oldParts[oldHead] === null) { | ||
oldHead++; | ||
} | ||
else if (oldParts[oldTail] === null) { | ||
oldTail--; | ||
} | ||
else if (oldKeys[oldHead] === newKeys[newHead]) { | ||
// MODIFIED FROM REPEAT | ||
// WE DONT WANT TO REPULL TEMPLATE HERE | ||
const template = newValues[newHead](newHead); | ||
if (template.cached) { | ||
newParts[newHead] = oldParts[oldHead]; | ||
} | ||
else { | ||
newParts[newHead] = setChildPartValue( | ||
oldParts[oldHead], | ||
template.content | ||
); | ||
} | ||
oldHead++; | ||
newHead++; | ||
} | ||
else if (oldKeys[oldTail] === newKeys[newTail]) { | ||
newParts[newTail] = setChildPartValue( | ||
oldParts[oldTail], | ||
newValues[newTail](newTail).content | ||
); | ||
oldTail--; | ||
newTail--; | ||
} | ||
else if (oldKeys[oldHead] === newKeys[newTail]) { | ||
newParts[newTail] = setChildPartValue( | ||
oldParts[oldHead], | ||
newValues[newTail](newTail).content | ||
); | ||
insertPart(containerPart, newParts[newTail + 1], oldParts[oldHead]); | ||
oldHead++; | ||
newTail--; | ||
} | ||
else if (oldKeys[oldTail] === newKeys[newHead]) { | ||
newParts[newHead] = setChildPartValue( | ||
oldParts[oldTail], | ||
newValues[newHead](newHead).content | ||
); | ||
insertPart(containerPart, oldParts[oldHead], oldParts[oldTail]); | ||
oldTail--; | ||
newHead++; | ||
} | ||
else { | ||
if (newKeyToIndexMap === undefined) { | ||
newKeyToIndexMap = generateMap(newKeys, newHead, newTail); | ||
oldKeyToIndexMap = generateMap(oldKeys, oldHead, oldTail); | ||
} | ||
if (!newKeyToIndexMap.has(oldKeys[oldHead])) { | ||
removePart(oldParts[oldHead]); | ||
oldHead++; | ||
} | ||
else if (!newKeyToIndexMap.has(oldKeys[oldTail])) { | ||
removePart(oldParts[oldTail]); | ||
oldTail--; | ||
} | ||
else { | ||
const oldIndex = oldKeyToIndexMap.get(newKeys[newHead]); | ||
const oldPart = oldIndex !== undefined ? oldParts[oldIndex] : null; | ||
if (oldPart === null) { | ||
const newPart = insertPart(containerPart, oldParts[oldHead]); | ||
setChildPartValue(newPart, newValues[newHead](newHead).content); | ||
newParts[newHead] = newPart; | ||
} | ||
else { | ||
newParts[newHead] = setChildPartValue( | ||
oldPart, | ||
newValues[newHead](newHead).content | ||
); | ||
insertPart(containerPart, oldParts[oldHead], oldPart); | ||
oldParts[oldIndex] = null; | ||
} | ||
newHead++; | ||
} | ||
} | ||
} | ||
while (newHead <= newTail) { | ||
const newPart = insertPart(containerPart, newParts[newTail + 1]); | ||
setChildPartValue(newPart, newValues[newHead]().content); | ||
newParts[newHead++] = newPart; | ||
} | ||
while (oldHead <= oldTail) { | ||
const oldPart = oldParts[oldHead++]; | ||
if (oldPart !== null) { | ||
removePart(oldPart); | ||
} | ||
} | ||
this._itemKeys = newKeys; | ||
setCommittedValue(containerPart, newParts); | ||
return noChange; | ||
reconnected() { | ||
// The reaction will be recreated in the next render | ||
} | ||
@@ -259,0 +89,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { html } from 'lit'; | ||
import { html, svg } from 'lit'; | ||
@@ -18,3 +18,3 @@ import { Reaction, ReactiveVar } from '@semantic-ui/reactivity'; | ||
constructor({ ast, data, subTemplates, snippets, helpers }) { | ||
constructor({ ast, data, subTemplates, snippets, helpers, isSVG }) { | ||
this.ast = ast || ''; | ||
@@ -27,2 +27,3 @@ this.data = data; | ||
this.helpers = helpers || {}; | ||
this.isSVG = isSVG; | ||
} | ||
@@ -44,3 +45,4 @@ | ||
this.clearTemp(); | ||
this.litTemplate = html.apply(this, [this.html, ...this.expressions]); | ||
const renderer = (this.isSVG) ? svg : html; | ||
this.litTemplate = renderer.apply(this, [this.html, ...this.expressions]); | ||
return this.litTemplate; | ||
@@ -56,2 +58,6 @@ } | ||
case 'svg': | ||
this.addValue(this.evaluateSVG(node.content, data)); | ||
break; | ||
case 'expression': | ||
@@ -148,2 +154,6 @@ const value = this.evaluateExpression(node.value, data, { | ||
evaluateSVG(svg, data) { | ||
return this.renderContent({ ast: svg, isSVG: true, data }); | ||
} | ||
evaluateSnippet(node, data = {}) { | ||
@@ -377,6 +387,7 @@ const getValue = (expressionString) => { | ||
// subtrees are rendered as separate contexts | ||
renderContent({ ast, data, subTemplates }) { | ||
renderContent({ ast, data, isSVG = this.isSVG } = {}) { | ||
const tree = new LitRenderer({ | ||
ast, | ||
data, | ||
isSVG, | ||
subTemplates: this.subTemplates, | ||
@@ -383,0 +394,0 @@ snippets: this.snippets, |
48265
1440
+ Added@semantic-ui/query@0.0.34(transitive)
+ Added@semantic-ui/reactivity@0.0.34(transitive)
+ Added@semantic-ui/templating@0.0.34(transitive)
+ Added@semantic-ui/utils@0.0.34(transitive)
- Removed@semantic-ui/query@0.0.33(transitive)
- Removed@semantic-ui/reactivity@0.0.33(transitive)
- Removed@semantic-ui/templating@0.0.33(transitive)
- Removed@semantic-ui/utils@0.0.33(transitive)
Updated@semantic-ui/query@^0.0.34
Updated@semantic-ui/utils@^0.0.34