diff --git a/examples/conditionals-and-loops/app.ts b/examples/conditionals-and-loops/app.ts
index 896c25f..b681a31 100644
--- a/examples/conditionals-and-loops/app.ts
+++ b/examples/conditionals-and-loops/app.ts
@@ -7,11 +7,11 @@ import { CivComponent, Reactive, Template, css, html } from 'civ-fe';
-
- - {{ item }}
+
- List is not empty, but hidden.
- List is empty.
+ List is not empty, but hidden.
+ List is empty.
`)
export default class ConditionalsAndLoops extends CivComponent {
diff --git a/examples/simple-component/app.ts b/examples/simple-component/app.ts
index 6515cc5..85e0565 100644
--- a/examples/simple-component/app.ts
+++ b/examples/simple-component/app.ts
@@ -13,7 +13,7 @@ export class TodoItem extends CivComponent {
@ResolveComponents({ TodoItem })
@Template(html`
-
+
`)
export default class SimpleComponent extends CivComponent {
diff --git a/src/civ-component.ts b/src/civ-component.ts
index ee562de..21aeda0 100644
--- a/src/civ-component.ts
+++ b/src/civ-component.ts
@@ -3,7 +3,7 @@ import { INJECTED_NS_PREFIX, REACTIVE_TEMPLATE_DOM, REACTIVE_TEMPLATE_SHEET, Rea
import { activateReactivity, initReactivity, REACTIVE_KIT, ReactivityHost } from "./lib/reactive";
import {
attachedEventName, detachEventName, moveEventName, movedEventName,
- attrToTrait, componentFlagClass, isMagicForAttr, isMagicForTemplateElement,
+ attrToTrait, componentFlagClass, isMagicElifAttr, isMagicElseAttr, isMagicForAttr, isMagicForTemplateElement, isMagicIfAttr,
significantFlagClass, subtreeTemplateFlagClass,
Traits, EventHandlerTrait,
} from "./protocol";
@@ -420,6 +420,7 @@ export class CivComponent extends EventTarget {
}
const elemTraits: Traits = [];
const magicAttrs: Attr[] = [];
+ const structuralTraitAttrMap = new Map<'for' | 'if' | 'elif' | 'else', string>();
if (Reflect.get(components, elem.tagName.toUpperCase())) {
elem.classList.add(componentFlagClass);
}
@@ -433,7 +434,31 @@ export class CivComponent extends EventTarget {
if (!trait) {
continue;
}
- elemTraits.push(trait);
+ const structuralTrait = isMagicForAttr(name) ? 'for' :
+ isMagicIfAttr(name) ? 'if' :
+ isMagicElifAttr(name) ? 'elif' :
+ isMagicElseAttr(name) ? 'else' :
+ undefined;
+ if (structuralTrait) {
+ const existingTraitIndex = elemTraits.findIndex(([t]) => t === structuralTrait);
+ if (existingTraitIndex !== -1) {
+ const existingAttrName = structuralTraitAttrMap.get(structuralTrait) || '';
+ const existingIsStarAlias = existingAttrName.startsWith('*');
+ const currentIsStarAlias = name.startsWith('*');
+ if (!existingIsStarAlias && currentIsStarAlias) {
+ elemTraits[existingTraitIndex] = trait;
+ structuralTraitAttrMap.set(structuralTrait, name);
+ } else {
+ magicAttrs.push(attr);
+ continue;
+ }
+ } else {
+ elemTraits.push(trait);
+ structuralTraitAttrMap.set(structuralTrait, name);
+ }
+ } else {
+ elemTraits.push(trait);
+ }
magicAttrs.push(attr);
if (trait.length === 1 || !trait.includes(expr)) {
continue;
diff --git a/src/protocol.ts b/src/protocol.ts
index 9053f68..2df011b 100644
--- a/src/protocol.ts
+++ b/src/protocol.ts
@@ -124,16 +124,16 @@ export function isMagicModel(name: string) {
return name === `${pseudoNamespacePrefix}model` || name === 'v-model';
}
export function isMagicForAttr(name: string) {
- return name === `${pseudoNamespacePrefix}for` || name === `render:for` || name === 'v-for';
+ return name === `${pseudoNamespacePrefix}for` || name === `render:for` || name === 'v-for' || name === '*for';
}
export function isMagicIfAttr(name: string) {
- return name === `${pseudoNamespacePrefix}if` || name === `render:if` || name === 'v-if';
+ return name === `${pseudoNamespacePrefix}if` || name === `render:if` || name === 'v-if' || name === '*if';
}
export function isMagicElifAttr(name: string) {
- return name === `${pseudoNamespacePrefix}elif` || name === `render:elif` || name === 'v-else-if';
+ return name === `${pseudoNamespacePrefix}elif` || name === `render:elif` || name === 'v-else-if' || name === '*else-if';
}
export function isMagicElseAttr(name: string) {
- return name === `${pseudoNamespacePrefix}else` || name === `render:else` || name === 'v-else';
+ return name === `${pseudoNamespacePrefix}else` || name === `render:else` || name === 'v-else' || name === '*else';
}
export function isMagicHTMLAttr(name: string) {
return name === `${pseudoNamespacePrefix}html` || name === `render:html` || name === 'v-html';
@@ -215,7 +215,10 @@ export function attrToTrait(attrName: string, expr: string): Traits[number] | un
}
export function isMagicForTemplateElement(elem: Element) {
- return elem.hasAttribute(`${pseudoNamespacePrefix}for`) || elem.hasAttribute('v-for');
+ return elem.hasAttribute(`${pseudoNamespacePrefix}for`) ||
+ elem.hasAttribute('render:for') ||
+ elem.hasAttribute('v-for') ||
+ elem.hasAttribute('*for');
}
export const attachedEventName = `${pseudoNamespacePrefix}attached`;