@adaas/are-html 0.0.20 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.d.mts +161 -5
- package/dist/browser/index.mjs +357 -55
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.mts +7 -0
- package/dist/node/directives/AreDirectiveFor.directive.d.ts +7 -0
- package/dist/node/directives/AreDirectiveFor.directive.js +17 -2
- package/dist/node/directives/AreDirectiveFor.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs +17 -2
- package/dist/node/directives/AreDirectiveFor.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveShow.directive.d.mts +32 -0
- package/dist/node/directives/AreDirectiveShow.directive.d.ts +32 -0
- package/dist/node/directives/AreDirectiveShow.directive.js +81 -0
- package/dist/node/directives/AreDirectiveShow.directive.js.map +1 -0
- package/dist/node/directives/AreDirectiveShow.directive.mjs +71 -0
- package/dist/node/directives/AreDirectiveShow.directive.mjs.map +1 -0
- package/dist/node/engine/AreHTML.engine.d.mts +2 -1
- package/dist/node/engine/AreHTML.engine.d.ts +2 -1
- package/dist/node/engine/AreHTML.engine.js +8 -2
- package/dist/node/engine/AreHTML.engine.js.map +1 -1
- package/dist/node/engine/AreHTML.engine.mjs +8 -2
- package/dist/node/engine/AreHTML.engine.mjs.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.d.mts +3 -0
- package/dist/node/engine/AreHTML.interpreter.d.ts +3 -0
- package/dist/node/engine/AreHTML.interpreter.js +29 -0
- package/dist/node/engine/AreHTML.interpreter.js.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.mjs +29 -0
- package/dist/node/engine/AreHTML.interpreter.mjs.map +1 -1
- package/dist/node/index.d.mts +4 -1
- package/dist/node/index.d.ts +4 -1
- package/dist/node/index.js +21 -0
- package/dist/node/index.mjs +3 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.mts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.d.ts +1 -0
- package/dist/node/instructions/AreHTML.instructions.constants.js +2 -1
- package/dist/node/instructions/AreHTML.instructions.constants.js.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.constants.mjs +2 -1
- package/dist/node/instructions/AreHTML.instructions.constants.mjs.map +1 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.mts +9 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.ts +9 -1
- package/dist/node/instructions/HideElement.instruction.d.mts +13 -0
- package/dist/node/instructions/HideElement.instruction.d.ts +13 -0
- package/dist/node/instructions/HideElement.instruction.js +31 -0
- package/dist/node/instructions/HideElement.instruction.js.map +1 -0
- package/dist/node/instructions/HideElement.instruction.mjs +24 -0
- package/dist/node/instructions/HideElement.instruction.mjs.map +1 -0
- package/dist/node/lib/AreRoot/AreRoot.component.d.mts +57 -3
- package/dist/node/lib/AreRoot/AreRoot.component.d.ts +57 -3
- package/dist/node/lib/AreRoot/AreRoot.component.js +137 -48
- package/dist/node/lib/AreRoot/AreRoot.component.js.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.mjs +139 -50
- package/dist/node/lib/AreRoot/AreRoot.component.mjs.map +1 -1
- package/dist/node/lib/AreRoot/AreRootCache.context.d.mts +58 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.d.ts +58 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.js +106 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.js.map +1 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.mjs +99 -0
- package/dist/node/lib/AreRoot/AreRootCache.context.mjs.map +1 -0
- package/examples/jumpstart/dist/index.html +1 -1
- package/examples/jumpstart/dist/{mq1a0fv0-ccgtz6.js → mq7hqrxy-4kus50.js} +629 -433
- package/examples/signal-routing/dist/index.html +1 -1
- package/examples/signal-routing/dist/{mq1bzrik-4lec86.js → mq7k53th-qiwy4x.js} +903 -486
- package/examples/signal-routing/src/components/SettingsPage.component.ts +39 -0
- package/examples/signal-routing/src/concept.ts +2 -0
- package/package.json +3 -3
- package/src/directives/AreDirectiveFor.directive.ts +44 -2
- package/src/directives/AreDirectiveShow.directive.ts +127 -0
- package/src/engine/AreHTML.engine.ts +11 -1
- package/src/engine/AreHTML.interpreter.ts +50 -0
- package/src/index.ts +3 -0
- package/src/instructions/AreHTML.instructions.constants.ts +1 -0
- package/src/instructions/AreHTML.instructions.types.ts +9 -0
- package/src/instructions/HideElement.instruction.ts +29 -0
- package/src/lib/AreRoot/AreRoot.component.ts +201 -71
- package/src/lib/AreRoot/AreRootCache.context.ts +133 -0
|
@@ -8,6 +8,13 @@ declare class AreDirectiveFor extends AreDirective {
|
|
|
8
8
|
transform(attribute: AreDirectiveAttribute, scope: A_Scope, store: AreStore, scene: AreScene, logger: A_Logger, ...args: any[]): void;
|
|
9
9
|
compile(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, ...args: any[]): void;
|
|
10
10
|
update(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, ...args: any[]): void;
|
|
11
|
+
/**
|
|
12
|
+
* Walks the node's ancestor chain (inclusive) and reports whether the
|
|
13
|
+
* whole path is currently active — i.e. the subtree is actually rendered
|
|
14
|
+
* into the DOM. A single inactive ancestor scene (e.g. a `$if` whose
|
|
15
|
+
* condition is false) means the subtree is detached.
|
|
16
|
+
*/
|
|
17
|
+
private isAttached;
|
|
11
18
|
/**
|
|
12
19
|
* Build a key-function that derives a stable identity from each item.
|
|
13
20
|
* If the user provided a `track <expr>` clause, evaluate it as a path on
|
|
@@ -8,6 +8,13 @@ declare class AreDirectiveFor extends AreDirective {
|
|
|
8
8
|
transform(attribute: AreDirectiveAttribute, scope: A_Scope, store: AreStore, scene: AreScene, logger: A_Logger, ...args: any[]): void;
|
|
9
9
|
compile(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, ...args: any[]): void;
|
|
10
10
|
update(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, ...args: any[]): void;
|
|
11
|
+
/**
|
|
12
|
+
* Walks the node's ancestor chain (inclusive) and reports whether the
|
|
13
|
+
* whole path is currently active — i.e. the subtree is actually rendered
|
|
14
|
+
* into the DOM. A single inactive ancestor scene (e.g. a `$if` whose
|
|
15
|
+
* condition is false) means the subtree is detached.
|
|
16
|
+
*/
|
|
17
|
+
private isAttached;
|
|
11
18
|
/**
|
|
12
19
|
* Build a key-function that derives a stable identity from each item.
|
|
13
20
|
* If the user provided a `track <expr>` clause, evaluate it as a path on
|
|
@@ -52,6 +52,7 @@ exports.AreDirectiveFor = class AreDirectiveFor extends AreDirective_component.A
|
|
|
52
52
|
const owner = attribute.owner;
|
|
53
53
|
const currentChildren = [...owner.children];
|
|
54
54
|
attribute.value = newArray;
|
|
55
|
+
const attached = this.isAttached(owner);
|
|
55
56
|
const computeKey = this.makeKeyFn(key, index, trackExpr);
|
|
56
57
|
const childByKey = /* @__PURE__ */ new Map();
|
|
57
58
|
const remaining = /* @__PURE__ */ new Set();
|
|
@@ -85,15 +86,29 @@ exports.AreDirectiveFor = class AreDirectiveFor extends AreDirective_component.A
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
for (const child of remaining) {
|
|
88
|
-
child.unmount();
|
|
89
|
+
if (attached) child.unmount();
|
|
89
90
|
owner.removeChild(child);
|
|
90
91
|
}
|
|
91
92
|
for (const child of newOnes) {
|
|
92
93
|
child.transform();
|
|
93
94
|
child.compile();
|
|
94
|
-
child.mount();
|
|
95
|
+
if (attached) child.mount();
|
|
95
96
|
}
|
|
96
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Walks the node's ancestor chain (inclusive) and reports whether the
|
|
100
|
+
* whole path is currently active — i.e. the subtree is actually rendered
|
|
101
|
+
* into the DOM. A single inactive ancestor scene (e.g. a `$if` whose
|
|
102
|
+
* condition is false) means the subtree is detached.
|
|
103
|
+
*/
|
|
104
|
+
isAttached(node) {
|
|
105
|
+
let current = node;
|
|
106
|
+
while (current) {
|
|
107
|
+
if (current.scene?.isInactive) return false;
|
|
108
|
+
current = current.parent;
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
97
112
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
98
113
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
99
114
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/directives/AreDirectiveFor.directive.ts"],"names":["AreDirectiveFor","AreDirective","AddCommentInstruction","AreDirectiveContext","AreCompilerError","A_Caller","A_Scope","AreStore","AreScene","A_Logger","A_Frame"],"mappings":"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","file":"AreDirectiveFor.directive.js","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreCompilerError, AreScene, AreStore } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreHTMLNode } from \"@adaas/are-html/node\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\n\n\ntype AreForExpression = {\n key: string;\n index: string | undefined;\n arrayExpr: string;\n /** Optional `track <expr>` clause, e.g. `track row.id` */\n trackExpr: string | undefined;\n};\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $for directive. Iterates over an array expression resolved from the store and renders a cloned template fragment per item, managing per-item subscopes and comment-node anchors. Supports keyed diffing via an optional track clause to minimise DOM mutations on collection updates.'\n})\n@AreDirective.Priority(1)\nexport class AreDirectiveFor extends AreDirective {\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n\n logger.debug(`[Transform] directive $FOR for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * Transfer the original node's scope (with all registered attributes and children)\n * to the template clone, and give the owner node a fresh empty scope.\n * This mirrors the $if directive's approach, making the owner a lightweight\n * group container whose sole visible presence is a comment placeholder.\n */\n const forTemplate = node.cloneWithScope();\n\n /**\n * Remove the $for attribute from the template so iterative clones do not\n * re-trigger this directive during their own transform phase.\n * Re-register it on the owner so the reactive compile/update pipeline keeps working.\n */\n const forAttr = forTemplate.attributes.find(d => d.name === attribute.name);\n\n if (forAttr) {\n forTemplate.scope.deregister(forAttr);\n node.scope.register(forAttr);\n }\n\n /**\n * Re-initialize the owner node with its fresh scope so it becomes a valid\n * group container that will own the generated item nodes as children.\n */\n node.init();\n\n /**\n * Store the template for use in compile and update.\n */\n attribute.template = forTemplate;\n\n\n /**\n * Parse the $for expression and evaluate the source array.\n */\n const { key, index, arrayExpr } = this.parseExpression(attribute.content);\n const array = this.resolveArray(store, arrayExpr, attribute.content);\n\n attribute.value = array;\n\n /**\n * For each item in the array, spawn a clone of the template with the\n * item's store values pre-set and its scene activated.\n *\n * The children are added to the owner node before the main compiler's\n * children iteration loop runs, so the main cycle will compile them —\n * no explicit child.compile() call is needed here.\n */\n for (let i = 0; i < array.length; i++) {\n this.spawnItemNode(attribute.template!, attribute.owner, key, index, array[i], i);\n }\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Replace the group node's default host declaration with a comment placeholder\n * so the owner element itself does not render as a DOM element — the item nodes\n * render as its children instead.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- for: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier });\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n }\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Re-evaluate the source array.\n */\n const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);\n const newArray = this.resolveArray(store, arrayExpr, attribute.content);\n\n const owner = attribute.owner;\n const currentChildren = [...owner.children] as AreHTMLNode[];\n\n attribute.value = newArray;\n\n const computeKey = this.makeKeyFn(key, index, trackExpr);\n\n // ── 1. Index existing children by stable key ────────────────────────\n const childByKey = new Map<any, AreHTMLNode>();\n const remaining = new Set<AreHTMLNode>();\n\n for (let i = 0; i < currentChildren.length; i++) {\n const child = currentChildren[i];\n const ctx = child.scope.resolveFlat(AreDirectiveContext);\n const k = ctx ? computeKey(ctx.scope[key], ctx.scope[index || 'index']) : Symbol('orphan');\n childByKey.set(k, child);\n remaining.add(child);\n }\n\n // ── 2. Walk desired list; reuse existing or spawn new ───────────────\n const desired: AreHTMLNode[] = [];\n const newOnes: AreHTMLNode[] = [];\n\n for (let i = 0; i < newArray.length; i++) {\n const item = newArray[i];\n const k = computeKey(item, i);\n const existing = childByKey.get(k);\n\n if (existing) {\n remaining.delete(existing);\n\n let directiveContext = existing.scope.resolveFlat(AreDirectiveContext);\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(existing.aseid);\n existing.scope.register(directiveContext);\n }\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n };\n desired.push(existing);\n } else {\n const itemNode = this.spawnItemNode(attribute.template!, owner, key, index, item, i);\n desired.push(itemNode);\n newOnes.push(itemNode);\n }\n }\n\n // ── 3. Unmount + detach removed children ─────────────────────────────\n for (const child of remaining) {\n child.unmount();\n owner.removeChild(child);\n }\n\n // ── 4. Mount only the new ones (kept children stay where they are). ─\n for (const child of newOnes) {\n child.transform();\n child.compile();\n child.mount();\n }\n }\n\n\n // ─────────────────────────────────────────────────────────────────────────────\n // ── Helpers ──────────────────────────────────────────────────────────────────\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Build a key-function that derives a stable identity from each item.\n * If the user provided a `track <expr>` clause, evaluate it as a path on\n * the item; otherwise fall back to the item identity (reference equality).\n */\n private makeKeyFn(key: string, index: string | undefined, trackExpr: string | undefined): (item: any, i: number) => any {\n if (!trackExpr) {\n return (item, i) => item ?? i;\n }\n\n // Strip any leading `key.` so users can write `track row.id`.\n const path = trackExpr.startsWith(key + '.') ? trackExpr.slice(key.length + 1) : trackExpr;\n\n return (item, i) => {\n if (item == null) return i;\n if (path === key || path === '$index') return path === '$index' ? i : item;\n\n // dotted path lookup\n const parts = path.split('.');\n let v: any = item;\n for (const p of parts) {\n if (v == null) return i;\n v = v[p];\n }\n return v ?? i;\n };\n }\n\n /**\n * Parses the $for expression string into its constituent parts.\n *\n * Supported formats:\n * item in items\n * item, index in items\n * (item, index) in items\n * item in filter(items)\n * item, index in filter(items, 'active')\n * item in items track item.id\n * (item, i) in items track item.id\n */\n private parseExpression(content: string): AreForExpression {\n // Strip optional `track <expr>` suffix first.\n let trackExpr: string | undefined;\n const trackIdx = content.search(/\\s+track\\s+/);\n let body = content;\n if (trackIdx !== -1) {\n const m = content.slice(trackIdx).match(/\\s+track\\s+(.+)$/);\n if (m) {\n trackExpr = m[1].trim();\n body = content.slice(0, trackIdx).trim();\n }\n }\n\n const inIndex = body.lastIndexOf(' in ');\n const keyAndIndex = body.slice(0, inIndex).trim().replace(/^\\(|\\)$/g, '');\n const arrayExpr = body.slice(inIndex + 4).trim();\n const keyParts = keyAndIndex.split(',').map(p => p.trim());\n\n return {\n key: keyParts[0],\n index: keyParts[1] || undefined,\n arrayExpr,\n trackExpr,\n };\n }\n\n /**\n * Resolves the array expression against the store.\n * Supports both plain key lookups and function-call expressions:\n * items → store.get('items')\n * filter(items) → store.get('filter')(store.get('items'))\n */\n private resolveArray(store: AreStore, arrayExpr: string, fullContent: string): any[] {\n let result: any;\n const callMatch = arrayExpr.match(/^([^(]+)\\((.+)\\)$/);\n\n if (callMatch) {\n const fnName = callMatch[1].trim();\n const fn = store.get(fnName as any);\n\n if (typeof fn !== 'function')\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Function',\n description: `The expression \"${fnName}\" in the \"for\" directive does not resolve to a function in the store. Received: ${typeof fn}`,\n });\n\n const rawArgs = callMatch[2].split(',').map(a => a.trim());\n const resolvedArgs = rawArgs.map(arg => {\n if (arg.startsWith(\"'\") && arg.endsWith(\"'\")) return arg.slice(1, -1);\n if (arg.startsWith('\"') && arg.endsWith('\"')) return arg.slice(1, -1);\n if (!isNaN(Number(arg))) return Number(arg);\n // Dotted-path / optional-chain: e.g. `record?.embedding` or `record.data`\n const stripped = arg.replace(/\\?$/, '');\n if (stripped.includes('.')) {\n const parts = stripped.split('.').map(p => p.replace(/\\?$/, ''));\n let val: any = store.get(parts[0] as any);\n for (let j = 1; j < parts.length; j++) {\n if (val == null) return undefined;\n val = val[parts[j]];\n }\n return val ?? undefined;\n }\n return store.get(stripped as any);\n });\n\n result = (fn as Function)(...resolvedArgs);\n } else if (arrayExpr.includes('.')) {\n // dotted-path lookup: e.g. \"list.items\" or \"record?.keywords\"\n // Strip optional-chaining `?` suffix from each segment so that\n // `record?.keywords` resolves the same as `record.keywords`.\n const parts = arrayExpr.split('.').map(p => p.replace(/\\?$/, ''));\n result = store.get(parts[0] as any);\n for (let i = 1; i < parts.length; i++) {\n if (result == null) break;\n result = result[parts[i]];\n }\n } else {\n result = store.get(arrayExpr.replace(/\\?$/, '') as any);\n }\n\n // null / undefined from optional-chaining expressions (e.g. `record?.keywords`)\n // means the source object is not yet loaded — treat as empty array so the\n // directive initialises gracefully and fills in when the store updates.\n if (result == null) return [];\n\n if (!Array.isArray(result))\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Value',\n description: `The \"for\" directive expects an array but got ${typeof result}. Expression: \"${fullContent}\". Received: ${JSON.stringify(result)}`,\n });\n\n return result;\n }\n\n /**\n * Creates a single item node from the template, registers it as a child of\n * the owner, initialises it, injects item-scoped store values, and activates\n * its scene so the mount/compile cycle will include it.\n *\n * NOTE: This method does NOT call compile() or mount() — the caller is\n * responsible for doing so when the main lifecycle cycle won't cover it\n * (i.e. during update, but not during the initial compile phase).\n */\n private spawnItemNode(\n template: AreHTMLNode,\n owner: AreHTMLNode,\n key: string,\n index: string | undefined,\n item: any,\n i: number,\n ): AreHTMLNode {\n const itemNode = template.clone() as AreHTMLNode;\n\n owner.addChild(itemNode);\n\n const queue = [itemNode];\n\n while (queue.length > 0) {\n const current = queue.shift()!\n\n current.init();\n\n queue.push(...current.children as AreHTMLNode[]);\n }\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n let directiveContext = itemNode.scope.resolveFlat(AreDirectiveContext);\n\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(itemNode.aseid);\n itemNode.scope.register(directiveContext);\n }\n\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n }\n\n itemNode.scene.activate();\n\n return itemNode;\n }\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/AreDirectiveFor.directive.ts"],"names":["AreDirectiveFor","AreDirective","AddCommentInstruction","AreDirectiveContext","AreCompilerError","A_Caller","A_Scope","AreStore","AreScene","A_Logger","A_Frame"],"mappings":"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","file":"AreDirectiveFor.directive.js","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreCompilerError, AreScene, AreStore } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreHTMLNode } from \"@adaas/are-html/node\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\n\n\ntype AreForExpression = {\n key: string;\n index: string | undefined;\n arrayExpr: string;\n /** Optional `track <expr>` clause, e.g. `track row.id` */\n trackExpr: string | undefined;\n};\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $for directive. Iterates over an array expression resolved from the store and renders a cloned template fragment per item, managing per-item subscopes and comment-node anchors. Supports keyed diffing via an optional track clause to minimise DOM mutations on collection updates.'\n})\n@AreDirective.Priority(1)\nexport class AreDirectiveFor extends AreDirective {\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n\n logger.debug(`[Transform] directive $FOR for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * Transfer the original node's scope (with all registered attributes and children)\n * to the template clone, and give the owner node a fresh empty scope.\n * This mirrors the $if directive's approach, making the owner a lightweight\n * group container whose sole visible presence is a comment placeholder.\n */\n const forTemplate = node.cloneWithScope();\n\n /**\n * Remove the $for attribute from the template so iterative clones do not\n * re-trigger this directive during their own transform phase.\n * Re-register it on the owner so the reactive compile/update pipeline keeps working.\n */\n const forAttr = forTemplate.attributes.find(d => d.name === attribute.name);\n\n if (forAttr) {\n forTemplate.scope.deregister(forAttr);\n node.scope.register(forAttr);\n }\n\n /**\n * Re-initialize the owner node with its fresh scope so it becomes a valid\n * group container that will own the generated item nodes as children.\n */\n node.init();\n\n /**\n * Store the template for use in compile and update.\n */\n attribute.template = forTemplate;\n\n\n /**\n * Parse the $for expression and evaluate the source array.\n */\n const { key, index, arrayExpr } = this.parseExpression(attribute.content);\n const array = this.resolveArray(store, arrayExpr, attribute.content);\n\n attribute.value = array;\n\n /**\n * For each item in the array, spawn a clone of the template with the\n * item's store values pre-set and its scene activated.\n *\n * The children are added to the owner node before the main compiler's\n * children iteration loop runs, so the main cycle will compile them —\n * no explicit child.compile() call is needed here.\n */\n for (let i = 0; i < array.length; i++) {\n this.spawnItemNode(attribute.template!, attribute.owner, key, index, array[i], i);\n }\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Replace the group node's default host declaration with a comment placeholder\n * so the owner element itself does not render as a DOM element — the item nodes\n * render as its children instead.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- for: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier });\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n }\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Re-evaluate the source array.\n */\n const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);\n const newArray = this.resolveArray(store, arrayExpr, attribute.content);\n\n const owner = attribute.owner;\n const currentChildren = [...owner.children] as AreHTMLNode[];\n\n attribute.value = newArray;\n\n /**\n * Is this `$for`'s subtree currently rendered into the DOM?\n *\n * A `$for` can update while its subtree is detached — e.g. it lives\n * inside a `$if` whose condition is currently false (the documented\n * `<div $if><x $for></div>` nesting). The directive still receives the\n * store change and re-diffs, but it must NOT mount/unmount item nodes\n * directly while detached: the `$for` anchor (and its ancestors) are\n * not in the DOM, so the interpreter's mount-point walk would fall\n * through to the nearest *mounted* ancestor (the `$if` comment in the\n * grandparent) and HOIST the items out of their intended container.\n * When the ancestor `$if` later activates, its mount cascade applies\n * the already-compiled item instructions in the correct place.\n *\n * Detached === any ancestor scene is inactive (regular nodes default\n * to an active scene; only structural directives deactivate one).\n */\n const attached = this.isAttached(owner);\n\n const computeKey = this.makeKeyFn(key, index, trackExpr);\n\n // ── 1. Index existing children by stable key ────────────────────────\n const childByKey = new Map<any, AreHTMLNode>();\n const remaining = new Set<AreHTMLNode>();\n\n for (let i = 0; i < currentChildren.length; i++) {\n const child = currentChildren[i];\n const ctx = child.scope.resolveFlat(AreDirectiveContext);\n const k = ctx ? computeKey(ctx.scope[key], ctx.scope[index || 'index']) : Symbol('orphan');\n childByKey.set(k, child);\n remaining.add(child);\n }\n\n // ── 2. Walk desired list; reuse existing or spawn new ───────────────\n const desired: AreHTMLNode[] = [];\n const newOnes: AreHTMLNode[] = [];\n\n for (let i = 0; i < newArray.length; i++) {\n const item = newArray[i];\n const k = computeKey(item, i);\n const existing = childByKey.get(k);\n\n if (existing) {\n remaining.delete(existing);\n\n let directiveContext = existing.scope.resolveFlat(AreDirectiveContext);\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(existing.aseid);\n existing.scope.register(directiveContext);\n }\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n };\n desired.push(existing);\n } else {\n const itemNode = this.spawnItemNode(attribute.template!, owner, key, index, item, i);\n desired.push(itemNode);\n newOnes.push(itemNode);\n }\n }\n\n // ── 3. Unmount + detach removed children ─────────────────────────────\n for (const child of remaining) {\n // Only revert DOM if the subtree is live; a detached subtree's item\n // nodes were never mounted (see `attached` rationale above), so\n // unmounting them is a no-op at best and risks reverting stale state.\n if (attached) child.unmount();\n owner.removeChild(child);\n }\n\n // ── 4. Mount only the new ones (kept children stay where they are). ─\n for (const child of newOnes) {\n child.transform();\n child.compile();\n // While detached, stop after compile: the item's instructions are\n // planned and the ancestor `$if`'s mount cascade will apply them in\n // the correct container once the condition becomes truthy. Mounting\n // here would hoist the item to the nearest mounted ancestor.\n if (attached) child.mount();\n }\n }\n\n\n /**\n * Walks the node's ancestor chain (inclusive) and reports whether the\n * whole path is currently active — i.e. the subtree is actually rendered\n * into the DOM. A single inactive ancestor scene (e.g. a `$if` whose\n * condition is false) means the subtree is detached.\n */\n private isAttached(node: AreHTMLNode): boolean {\n let current: AreHTMLNode | undefined = node;\n while (current) {\n if (current.scene?.isInactive) return false;\n current = current.parent as AreHTMLNode | undefined;\n }\n return true;\n }\n\n\n // ─────────────────────────────────────────────────────────────────────────────\n // ── Helpers ──────────────────────────────────────────────────────────────────\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Build a key-function that derives a stable identity from each item.\n * If the user provided a `track <expr>` clause, evaluate it as a path on\n * the item; otherwise fall back to the item identity (reference equality).\n */\n private makeKeyFn(key: string, index: string | undefined, trackExpr: string | undefined): (item: any, i: number) => any {\n if (!trackExpr) {\n return (item, i) => item ?? i;\n }\n\n // Strip any leading `key.` so users can write `track row.id`.\n const path = trackExpr.startsWith(key + '.') ? trackExpr.slice(key.length + 1) : trackExpr;\n\n return (item, i) => {\n if (item == null) return i;\n if (path === key || path === '$index') return path === '$index' ? i : item;\n\n // dotted path lookup\n const parts = path.split('.');\n let v: any = item;\n for (const p of parts) {\n if (v == null) return i;\n v = v[p];\n }\n return v ?? i;\n };\n }\n\n /**\n * Parses the $for expression string into its constituent parts.\n *\n * Supported formats:\n * item in items\n * item, index in items\n * (item, index) in items\n * item in filter(items)\n * item, index in filter(items, 'active')\n * item in items track item.id\n * (item, i) in items track item.id\n */\n private parseExpression(content: string): AreForExpression {\n // Strip optional `track <expr>` suffix first.\n let trackExpr: string | undefined;\n const trackIdx = content.search(/\\s+track\\s+/);\n let body = content;\n if (trackIdx !== -1) {\n const m = content.slice(trackIdx).match(/\\s+track\\s+(.+)$/);\n if (m) {\n trackExpr = m[1].trim();\n body = content.slice(0, trackIdx).trim();\n }\n }\n\n const inIndex = body.lastIndexOf(' in ');\n const keyAndIndex = body.slice(0, inIndex).trim().replace(/^\\(|\\)$/g, '');\n const arrayExpr = body.slice(inIndex + 4).trim();\n const keyParts = keyAndIndex.split(',').map(p => p.trim());\n\n return {\n key: keyParts[0],\n index: keyParts[1] || undefined,\n arrayExpr,\n trackExpr,\n };\n }\n\n /**\n * Resolves the array expression against the store.\n * Supports both plain key lookups and function-call expressions:\n * items → store.get('items')\n * filter(items) → store.get('filter')(store.get('items'))\n */\n private resolveArray(store: AreStore, arrayExpr: string, fullContent: string): any[] {\n let result: any;\n const callMatch = arrayExpr.match(/^([^(]+)\\((.+)\\)$/);\n\n if (callMatch) {\n const fnName = callMatch[1].trim();\n const fn = store.get(fnName as any);\n\n if (typeof fn !== 'function')\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Function',\n description: `The expression \"${fnName}\" in the \"for\" directive does not resolve to a function in the store. Received: ${typeof fn}`,\n });\n\n const rawArgs = callMatch[2].split(',').map(a => a.trim());\n const resolvedArgs = rawArgs.map(arg => {\n if (arg.startsWith(\"'\") && arg.endsWith(\"'\")) return arg.slice(1, -1);\n if (arg.startsWith('\"') && arg.endsWith('\"')) return arg.slice(1, -1);\n if (!isNaN(Number(arg))) return Number(arg);\n // Dotted-path / optional-chain: e.g. `record?.embedding` or `record.data`\n const stripped = arg.replace(/\\?$/, '');\n if (stripped.includes('.')) {\n const parts = stripped.split('.').map(p => p.replace(/\\?$/, ''));\n let val: any = store.get(parts[0] as any);\n for (let j = 1; j < parts.length; j++) {\n if (val == null) return undefined;\n val = val[parts[j]];\n }\n return val ?? undefined;\n }\n return store.get(stripped as any);\n });\n\n result = (fn as Function)(...resolvedArgs);\n } else if (arrayExpr.includes('.')) {\n // dotted-path lookup: e.g. \"list.items\" or \"record?.keywords\"\n // Strip optional-chaining `?` suffix from each segment so that\n // `record?.keywords` resolves the same as `record.keywords`.\n const parts = arrayExpr.split('.').map(p => p.replace(/\\?$/, ''));\n result = store.get(parts[0] as any);\n for (let i = 1; i < parts.length; i++) {\n if (result == null) break;\n result = result[parts[i]];\n }\n } else {\n result = store.get(arrayExpr.replace(/\\?$/, '') as any);\n }\n\n // null / undefined from optional-chaining expressions (e.g. `record?.keywords`)\n // means the source object is not yet loaded — treat as empty array so the\n // directive initialises gracefully and fills in when the store updates.\n if (result == null) return [];\n\n if (!Array.isArray(result))\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Value',\n description: `The \"for\" directive expects an array but got ${typeof result}. Expression: \"${fullContent}\". Received: ${JSON.stringify(result)}`,\n });\n\n return result;\n }\n\n /**\n * Creates a single item node from the template, registers it as a child of\n * the owner, initialises it, injects item-scoped store values, and activates\n * its scene so the mount/compile cycle will include it.\n *\n * NOTE: This method does NOT call compile() or mount() — the caller is\n * responsible for doing so when the main lifecycle cycle won't cover it\n * (i.e. during update, but not during the initial compile phase).\n */\n private spawnItemNode(\n template: AreHTMLNode,\n owner: AreHTMLNode,\n key: string,\n index: string | undefined,\n item: any,\n i: number,\n ): AreHTMLNode {\n const itemNode = template.clone() as AreHTMLNode;\n\n owner.addChild(itemNode);\n\n const queue = [itemNode];\n\n while (queue.length > 0) {\n const current = queue.shift()!\n\n current.init();\n\n queue.push(...current.children as AreHTMLNode[]);\n }\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n let directiveContext = itemNode.scope.resolveFlat(AreDirectiveContext);\n\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(itemNode.aseid);\n itemNode.scope.register(directiveContext);\n }\n\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n }\n\n itemNode.scene.activate();\n\n return itemNode;\n }\n}"]}
|
|
@@ -40,6 +40,7 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
40
40
|
const owner = attribute.owner;
|
|
41
41
|
const currentChildren = [...owner.children];
|
|
42
42
|
attribute.value = newArray;
|
|
43
|
+
const attached = this.isAttached(owner);
|
|
43
44
|
const computeKey = this.makeKeyFn(key, index, trackExpr);
|
|
44
45
|
const childByKey = /* @__PURE__ */ new Map();
|
|
45
46
|
const remaining = /* @__PURE__ */ new Set();
|
|
@@ -73,15 +74,29 @@ let AreDirectiveFor = class extends AreDirective {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
for (const child of remaining) {
|
|
76
|
-
child.unmount();
|
|
77
|
+
if (attached) child.unmount();
|
|
77
78
|
owner.removeChild(child);
|
|
78
79
|
}
|
|
79
80
|
for (const child of newOnes) {
|
|
80
81
|
child.transform();
|
|
81
82
|
child.compile();
|
|
82
|
-
child.mount();
|
|
83
|
+
if (attached) child.mount();
|
|
83
84
|
}
|
|
84
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Walks the node's ancestor chain (inclusive) and reports whether the
|
|
88
|
+
* whole path is currently active — i.e. the subtree is actually rendered
|
|
89
|
+
* into the DOM. A single inactive ancestor scene (e.g. a `$if` whose
|
|
90
|
+
* condition is false) means the subtree is detached.
|
|
91
|
+
*/
|
|
92
|
+
isAttached(node) {
|
|
93
|
+
let current = node;
|
|
94
|
+
while (current) {
|
|
95
|
+
if (current.scene?.isInactive) return false;
|
|
96
|
+
current = current.parent;
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
85
100
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
86
101
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
87
102
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/directives/AreDirectiveFor.directive.ts"],"names":[],"mappings":"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","file":"AreDirectiveFor.directive.mjs","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreCompilerError, AreScene, AreStore } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreHTMLNode } from \"@adaas/are-html/node\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\n\n\ntype AreForExpression = {\n key: string;\n index: string | undefined;\n arrayExpr: string;\n /** Optional `track <expr>` clause, e.g. `track row.id` */\n trackExpr: string | undefined;\n};\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $for directive. Iterates over an array expression resolved from the store and renders a cloned template fragment per item, managing per-item subscopes and comment-node anchors. Supports keyed diffing via an optional track clause to minimise DOM mutations on collection updates.'\n})\n@AreDirective.Priority(1)\nexport class AreDirectiveFor extends AreDirective {\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n\n logger.debug(`[Transform] directive $FOR for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * Transfer the original node's scope (with all registered attributes and children)\n * to the template clone, and give the owner node a fresh empty scope.\n * This mirrors the $if directive's approach, making the owner a lightweight\n * group container whose sole visible presence is a comment placeholder.\n */\n const forTemplate = node.cloneWithScope();\n\n /**\n * Remove the $for attribute from the template so iterative clones do not\n * re-trigger this directive during their own transform phase.\n * Re-register it on the owner so the reactive compile/update pipeline keeps working.\n */\n const forAttr = forTemplate.attributes.find(d => d.name === attribute.name);\n\n if (forAttr) {\n forTemplate.scope.deregister(forAttr);\n node.scope.register(forAttr);\n }\n\n /**\n * Re-initialize the owner node with its fresh scope so it becomes a valid\n * group container that will own the generated item nodes as children.\n */\n node.init();\n\n /**\n * Store the template for use in compile and update.\n */\n attribute.template = forTemplate;\n\n\n /**\n * Parse the $for expression and evaluate the source array.\n */\n const { key, index, arrayExpr } = this.parseExpression(attribute.content);\n const array = this.resolveArray(store, arrayExpr, attribute.content);\n\n attribute.value = array;\n\n /**\n * For each item in the array, spawn a clone of the template with the\n * item's store values pre-set and its scene activated.\n *\n * The children are added to the owner node before the main compiler's\n * children iteration loop runs, so the main cycle will compile them —\n * no explicit child.compile() call is needed here.\n */\n for (let i = 0; i < array.length; i++) {\n this.spawnItemNode(attribute.template!, attribute.owner, key, index, array[i], i);\n }\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Replace the group node's default host declaration with a comment placeholder\n * so the owner element itself does not render as a DOM element — the item nodes\n * render as its children instead.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- for: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier });\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n }\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Re-evaluate the source array.\n */\n const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);\n const newArray = this.resolveArray(store, arrayExpr, attribute.content);\n\n const owner = attribute.owner;\n const currentChildren = [...owner.children] as AreHTMLNode[];\n\n attribute.value = newArray;\n\n const computeKey = this.makeKeyFn(key, index, trackExpr);\n\n // ── 1. Index existing children by stable key ────────────────────────\n const childByKey = new Map<any, AreHTMLNode>();\n const remaining = new Set<AreHTMLNode>();\n\n for (let i = 0; i < currentChildren.length; i++) {\n const child = currentChildren[i];\n const ctx = child.scope.resolveFlat(AreDirectiveContext);\n const k = ctx ? computeKey(ctx.scope[key], ctx.scope[index || 'index']) : Symbol('orphan');\n childByKey.set(k, child);\n remaining.add(child);\n }\n\n // ── 2. Walk desired list; reuse existing or spawn new ───────────────\n const desired: AreHTMLNode[] = [];\n const newOnes: AreHTMLNode[] = [];\n\n for (let i = 0; i < newArray.length; i++) {\n const item = newArray[i];\n const k = computeKey(item, i);\n const existing = childByKey.get(k);\n\n if (existing) {\n remaining.delete(existing);\n\n let directiveContext = existing.scope.resolveFlat(AreDirectiveContext);\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(existing.aseid);\n existing.scope.register(directiveContext);\n }\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n };\n desired.push(existing);\n } else {\n const itemNode = this.spawnItemNode(attribute.template!, owner, key, index, item, i);\n desired.push(itemNode);\n newOnes.push(itemNode);\n }\n }\n\n // ── 3. Unmount + detach removed children ─────────────────────────────\n for (const child of remaining) {\n child.unmount();\n owner.removeChild(child);\n }\n\n // ── 4. Mount only the new ones (kept children stay where they are). ─\n for (const child of newOnes) {\n child.transform();\n child.compile();\n child.mount();\n }\n }\n\n\n // ─────────────────────────────────────────────────────────────────────────────\n // ── Helpers ──────────────────────────────────────────────────────────────────\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Build a key-function that derives a stable identity from each item.\n * If the user provided a `track <expr>` clause, evaluate it as a path on\n * the item; otherwise fall back to the item identity (reference equality).\n */\n private makeKeyFn(key: string, index: string | undefined, trackExpr: string | undefined): (item: any, i: number) => any {\n if (!trackExpr) {\n return (item, i) => item ?? i;\n }\n\n // Strip any leading `key.` so users can write `track row.id`.\n const path = trackExpr.startsWith(key + '.') ? trackExpr.slice(key.length + 1) : trackExpr;\n\n return (item, i) => {\n if (item == null) return i;\n if (path === key || path === '$index') return path === '$index' ? i : item;\n\n // dotted path lookup\n const parts = path.split('.');\n let v: any = item;\n for (const p of parts) {\n if (v == null) return i;\n v = v[p];\n }\n return v ?? i;\n };\n }\n\n /**\n * Parses the $for expression string into its constituent parts.\n *\n * Supported formats:\n * item in items\n * item, index in items\n * (item, index) in items\n * item in filter(items)\n * item, index in filter(items, 'active')\n * item in items track item.id\n * (item, i) in items track item.id\n */\n private parseExpression(content: string): AreForExpression {\n // Strip optional `track <expr>` suffix first.\n let trackExpr: string | undefined;\n const trackIdx = content.search(/\\s+track\\s+/);\n let body = content;\n if (trackIdx !== -1) {\n const m = content.slice(trackIdx).match(/\\s+track\\s+(.+)$/);\n if (m) {\n trackExpr = m[1].trim();\n body = content.slice(0, trackIdx).trim();\n }\n }\n\n const inIndex = body.lastIndexOf(' in ');\n const keyAndIndex = body.slice(0, inIndex).trim().replace(/^\\(|\\)$/g, '');\n const arrayExpr = body.slice(inIndex + 4).trim();\n const keyParts = keyAndIndex.split(',').map(p => p.trim());\n\n return {\n key: keyParts[0],\n index: keyParts[1] || undefined,\n arrayExpr,\n trackExpr,\n };\n }\n\n /**\n * Resolves the array expression against the store.\n * Supports both plain key lookups and function-call expressions:\n * items → store.get('items')\n * filter(items) → store.get('filter')(store.get('items'))\n */\n private resolveArray(store: AreStore, arrayExpr: string, fullContent: string): any[] {\n let result: any;\n const callMatch = arrayExpr.match(/^([^(]+)\\((.+)\\)$/);\n\n if (callMatch) {\n const fnName = callMatch[1].trim();\n const fn = store.get(fnName as any);\n\n if (typeof fn !== 'function')\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Function',\n description: `The expression \"${fnName}\" in the \"for\" directive does not resolve to a function in the store. Received: ${typeof fn}`,\n });\n\n const rawArgs = callMatch[2].split(',').map(a => a.trim());\n const resolvedArgs = rawArgs.map(arg => {\n if (arg.startsWith(\"'\") && arg.endsWith(\"'\")) return arg.slice(1, -1);\n if (arg.startsWith('\"') && arg.endsWith('\"')) return arg.slice(1, -1);\n if (!isNaN(Number(arg))) return Number(arg);\n // Dotted-path / optional-chain: e.g. `record?.embedding` or `record.data`\n const stripped = arg.replace(/\\?$/, '');\n if (stripped.includes('.')) {\n const parts = stripped.split('.').map(p => p.replace(/\\?$/, ''));\n let val: any = store.get(parts[0] as any);\n for (let j = 1; j < parts.length; j++) {\n if (val == null) return undefined;\n val = val[parts[j]];\n }\n return val ?? undefined;\n }\n return store.get(stripped as any);\n });\n\n result = (fn as Function)(...resolvedArgs);\n } else if (arrayExpr.includes('.')) {\n // dotted-path lookup: e.g. \"list.items\" or \"record?.keywords\"\n // Strip optional-chaining `?` suffix from each segment so that\n // `record?.keywords` resolves the same as `record.keywords`.\n const parts = arrayExpr.split('.').map(p => p.replace(/\\?$/, ''));\n result = store.get(parts[0] as any);\n for (let i = 1; i < parts.length; i++) {\n if (result == null) break;\n result = result[parts[i]];\n }\n } else {\n result = store.get(arrayExpr.replace(/\\?$/, '') as any);\n }\n\n // null / undefined from optional-chaining expressions (e.g. `record?.keywords`)\n // means the source object is not yet loaded — treat as empty array so the\n // directive initialises gracefully and fills in when the store updates.\n if (result == null) return [];\n\n if (!Array.isArray(result))\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Value',\n description: `The \"for\" directive expects an array but got ${typeof result}. Expression: \"${fullContent}\". Received: ${JSON.stringify(result)}`,\n });\n\n return result;\n }\n\n /**\n * Creates a single item node from the template, registers it as a child of\n * the owner, initialises it, injects item-scoped store values, and activates\n * its scene so the mount/compile cycle will include it.\n *\n * NOTE: This method does NOT call compile() or mount() — the caller is\n * responsible for doing so when the main lifecycle cycle won't cover it\n * (i.e. during update, but not during the initial compile phase).\n */\n private spawnItemNode(\n template: AreHTMLNode,\n owner: AreHTMLNode,\n key: string,\n index: string | undefined,\n item: any,\n i: number,\n ): AreHTMLNode {\n const itemNode = template.clone() as AreHTMLNode;\n\n owner.addChild(itemNode);\n\n const queue = [itemNode];\n\n while (queue.length > 0) {\n const current = queue.shift()!\n\n current.init();\n\n queue.push(...current.children as AreHTMLNode[]);\n }\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n let directiveContext = itemNode.scope.resolveFlat(AreDirectiveContext);\n\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(itemNode.aseid);\n itemNode.scope.register(directiveContext);\n }\n\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n }\n\n itemNode.scene.activate();\n\n return itemNode;\n }\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/AreDirectiveFor.directive.ts"],"names":[],"mappings":"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","file":"AreDirectiveFor.directive.mjs","sourcesContent":["import { A_Caller, A_Inject, A_Scope } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreCompilerError, AreScene, AreStore } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AddCommentInstruction } from \"@adaas/are-html/instructions/AddComment.instruction\";\nimport { AreHTMLNode } from \"@adaas/are-html/node\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\n\n\ntype AreForExpression = {\n key: string;\n index: string | undefined;\n arrayExpr: string;\n /** Optional `track <expr>` clause, e.g. `track row.id` */\n trackExpr: string | undefined;\n};\n\n\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $for directive. Iterates over an array expression resolved from the store and renders a cloned template fragment per item, managing per-item subscopes and comment-node anchors. Supports keyed diffing via an optional track clause to minimise DOM mutations on collection updates.'\n})\n@AreDirective.Priority(1)\nexport class AreDirectiveFor extends AreDirective {\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Scope) scope: A_Scope,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n\n logger.debug(`[Transform] directive $FOR for <${attribute.owner.aseid.toString()}>`)\n\n const node = attribute.owner;\n\n /**\n * Transfer the original node's scope (with all registered attributes and children)\n * to the template clone, and give the owner node a fresh empty scope.\n * This mirrors the $if directive's approach, making the owner a lightweight\n * group container whose sole visible presence is a comment placeholder.\n */\n const forTemplate = node.cloneWithScope();\n\n /**\n * Remove the $for attribute from the template so iterative clones do not\n * re-trigger this directive during their own transform phase.\n * Re-register it on the owner so the reactive compile/update pipeline keeps working.\n */\n const forAttr = forTemplate.attributes.find(d => d.name === attribute.name);\n\n if (forAttr) {\n forTemplate.scope.deregister(forAttr);\n node.scope.register(forAttr);\n }\n\n /**\n * Re-initialize the owner node with its fresh scope so it becomes a valid\n * group container that will own the generated item nodes as children.\n */\n node.init();\n\n /**\n * Store the template for use in compile and update.\n */\n attribute.template = forTemplate;\n\n\n /**\n * Parse the $for expression and evaluate the source array.\n */\n const { key, index, arrayExpr } = this.parseExpression(attribute.content);\n const array = this.resolveArray(store, arrayExpr, attribute.content);\n\n attribute.value = array;\n\n /**\n * For each item in the array, spawn a clone of the template with the\n * item's store values pre-set and its scene activated.\n *\n * The children are added to the owner node before the main compiler's\n * children iteration loop runs, so the main cycle will compile them —\n * no explicit child.compile() call is needed here.\n */\n for (let i = 0; i < array.length; i++) {\n this.spawnItemNode(attribute.template!, attribute.owner, key, index, array[i], i);\n }\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Replace the group node's default host declaration with a comment placeholder\n * so the owner element itself does not render as a DOM element — the item nodes\n * render as its children instead.\n */\n const hostInstruction = scene.host!;\n const commentIdentifier = ` --- for: ${attribute.template!.id} --- `;\n const declaration = new AddCommentInstruction({ content: commentIdentifier });\n\n scene.setHost(declaration);\n scene.planBefore(declaration, hostInstruction);\n scene.unPlan(hostInstruction);\n }\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n ...args: any[]\n ): void {\n /**\n * Re-evaluate the source array.\n */\n const { key, index, arrayExpr, trackExpr } = this.parseExpression(attribute.content);\n const newArray = this.resolveArray(store, arrayExpr, attribute.content);\n\n const owner = attribute.owner;\n const currentChildren = [...owner.children] as AreHTMLNode[];\n\n attribute.value = newArray;\n\n /**\n * Is this `$for`'s subtree currently rendered into the DOM?\n *\n * A `$for` can update while its subtree is detached — e.g. it lives\n * inside a `$if` whose condition is currently false (the documented\n * `<div $if><x $for></div>` nesting). The directive still receives the\n * store change and re-diffs, but it must NOT mount/unmount item nodes\n * directly while detached: the `$for` anchor (and its ancestors) are\n * not in the DOM, so the interpreter's mount-point walk would fall\n * through to the nearest *mounted* ancestor (the `$if` comment in the\n * grandparent) and HOIST the items out of their intended container.\n * When the ancestor `$if` later activates, its mount cascade applies\n * the already-compiled item instructions in the correct place.\n *\n * Detached === any ancestor scene is inactive (regular nodes default\n * to an active scene; only structural directives deactivate one).\n */\n const attached = this.isAttached(owner);\n\n const computeKey = this.makeKeyFn(key, index, trackExpr);\n\n // ── 1. Index existing children by stable key ────────────────────────\n const childByKey = new Map<any, AreHTMLNode>();\n const remaining = new Set<AreHTMLNode>();\n\n for (let i = 0; i < currentChildren.length; i++) {\n const child = currentChildren[i];\n const ctx = child.scope.resolveFlat(AreDirectiveContext);\n const k = ctx ? computeKey(ctx.scope[key], ctx.scope[index || 'index']) : Symbol('orphan');\n childByKey.set(k, child);\n remaining.add(child);\n }\n\n // ── 2. Walk desired list; reuse existing or spawn new ───────────────\n const desired: AreHTMLNode[] = [];\n const newOnes: AreHTMLNode[] = [];\n\n for (let i = 0; i < newArray.length; i++) {\n const item = newArray[i];\n const k = computeKey(item, i);\n const existing = childByKey.get(k);\n\n if (existing) {\n remaining.delete(existing);\n\n let directiveContext = existing.scope.resolveFlat(AreDirectiveContext);\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(existing.aseid);\n existing.scope.register(directiveContext);\n }\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n };\n desired.push(existing);\n } else {\n const itemNode = this.spawnItemNode(attribute.template!, owner, key, index, item, i);\n desired.push(itemNode);\n newOnes.push(itemNode);\n }\n }\n\n // ── 3. Unmount + detach removed children ─────────────────────────────\n for (const child of remaining) {\n // Only revert DOM if the subtree is live; a detached subtree's item\n // nodes were never mounted (see `attached` rationale above), so\n // unmounting them is a no-op at best and risks reverting stale state.\n if (attached) child.unmount();\n owner.removeChild(child);\n }\n\n // ── 4. Mount only the new ones (kept children stay where they are). ─\n for (const child of newOnes) {\n child.transform();\n child.compile();\n // While detached, stop after compile: the item's instructions are\n // planned and the ancestor `$if`'s mount cascade will apply them in\n // the correct container once the condition becomes truthy. Mounting\n // here would hoist the item to the nearest mounted ancestor.\n if (attached) child.mount();\n }\n }\n\n\n /**\n * Walks the node's ancestor chain (inclusive) and reports whether the\n * whole path is currently active — i.e. the subtree is actually rendered\n * into the DOM. A single inactive ancestor scene (e.g. a `$if` whose\n * condition is false) means the subtree is detached.\n */\n private isAttached(node: AreHTMLNode): boolean {\n let current: AreHTMLNode | undefined = node;\n while (current) {\n if (current.scene?.isInactive) return false;\n current = current.parent as AreHTMLNode | undefined;\n }\n return true;\n }\n\n\n // ─────────────────────────────────────────────────────────────────────────────\n // ── Helpers ──────────────────────────────────────────────────────────────────\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Build a key-function that derives a stable identity from each item.\n * If the user provided a `track <expr>` clause, evaluate it as a path on\n * the item; otherwise fall back to the item identity (reference equality).\n */\n private makeKeyFn(key: string, index: string | undefined, trackExpr: string | undefined): (item: any, i: number) => any {\n if (!trackExpr) {\n return (item, i) => item ?? i;\n }\n\n // Strip any leading `key.` so users can write `track row.id`.\n const path = trackExpr.startsWith(key + '.') ? trackExpr.slice(key.length + 1) : trackExpr;\n\n return (item, i) => {\n if (item == null) return i;\n if (path === key || path === '$index') return path === '$index' ? i : item;\n\n // dotted path lookup\n const parts = path.split('.');\n let v: any = item;\n for (const p of parts) {\n if (v == null) return i;\n v = v[p];\n }\n return v ?? i;\n };\n }\n\n /**\n * Parses the $for expression string into its constituent parts.\n *\n * Supported formats:\n * item in items\n * item, index in items\n * (item, index) in items\n * item in filter(items)\n * item, index in filter(items, 'active')\n * item in items track item.id\n * (item, i) in items track item.id\n */\n private parseExpression(content: string): AreForExpression {\n // Strip optional `track <expr>` suffix first.\n let trackExpr: string | undefined;\n const trackIdx = content.search(/\\s+track\\s+/);\n let body = content;\n if (trackIdx !== -1) {\n const m = content.slice(trackIdx).match(/\\s+track\\s+(.+)$/);\n if (m) {\n trackExpr = m[1].trim();\n body = content.slice(0, trackIdx).trim();\n }\n }\n\n const inIndex = body.lastIndexOf(' in ');\n const keyAndIndex = body.slice(0, inIndex).trim().replace(/^\\(|\\)$/g, '');\n const arrayExpr = body.slice(inIndex + 4).trim();\n const keyParts = keyAndIndex.split(',').map(p => p.trim());\n\n return {\n key: keyParts[0],\n index: keyParts[1] || undefined,\n arrayExpr,\n trackExpr,\n };\n }\n\n /**\n * Resolves the array expression against the store.\n * Supports both plain key lookups and function-call expressions:\n * items → store.get('items')\n * filter(items) → store.get('filter')(store.get('items'))\n */\n private resolveArray(store: AreStore, arrayExpr: string, fullContent: string): any[] {\n let result: any;\n const callMatch = arrayExpr.match(/^([^(]+)\\((.+)\\)$/);\n\n if (callMatch) {\n const fnName = callMatch[1].trim();\n const fn = store.get(fnName as any);\n\n if (typeof fn !== 'function')\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Function',\n description: `The expression \"${fnName}\" in the \"for\" directive does not resolve to a function in the store. Received: ${typeof fn}`,\n });\n\n const rawArgs = callMatch[2].split(',').map(a => a.trim());\n const resolvedArgs = rawArgs.map(arg => {\n if (arg.startsWith(\"'\") && arg.endsWith(\"'\")) return arg.slice(1, -1);\n if (arg.startsWith('\"') && arg.endsWith('\"')) return arg.slice(1, -1);\n if (!isNaN(Number(arg))) return Number(arg);\n // Dotted-path / optional-chain: e.g. `record?.embedding` or `record.data`\n const stripped = arg.replace(/\\?$/, '');\n if (stripped.includes('.')) {\n const parts = stripped.split('.').map(p => p.replace(/\\?$/, ''));\n let val: any = store.get(parts[0] as any);\n for (let j = 1; j < parts.length; j++) {\n if (val == null) return undefined;\n val = val[parts[j]];\n }\n return val ?? undefined;\n }\n return store.get(stripped as any);\n });\n\n result = (fn as Function)(...resolvedArgs);\n } else if (arrayExpr.includes('.')) {\n // dotted-path lookup: e.g. \"list.items\" or \"record?.keywords\"\n // Strip optional-chaining `?` suffix from each segment so that\n // `record?.keywords` resolves the same as `record.keywords`.\n const parts = arrayExpr.split('.').map(p => p.replace(/\\?$/, ''));\n result = store.get(parts[0] as any);\n for (let i = 1; i < parts.length; i++) {\n if (result == null) break;\n result = result[parts[i]];\n }\n } else {\n result = store.get(arrayExpr.replace(/\\?$/, '') as any);\n }\n\n // null / undefined from optional-chaining expressions (e.g. `record?.keywords`)\n // means the source object is not yet loaded — treat as empty array so the\n // directive initialises gracefully and fills in when the store updates.\n if (result == null) return [];\n\n if (!Array.isArray(result))\n throw new AreCompilerError({\n title: 'Invalid \"for\" Directive Value',\n description: `The \"for\" directive expects an array but got ${typeof result}. Expression: \"${fullContent}\". Received: ${JSON.stringify(result)}`,\n });\n\n return result;\n }\n\n /**\n * Creates a single item node from the template, registers it as a child of\n * the owner, initialises it, injects item-scoped store values, and activates\n * its scene so the mount/compile cycle will include it.\n *\n * NOTE: This method does NOT call compile() or mount() — the caller is\n * responsible for doing so when the main lifecycle cycle won't cover it\n * (i.e. during update, but not during the initial compile phase).\n */\n private spawnItemNode(\n template: AreHTMLNode,\n owner: AreHTMLNode,\n key: string,\n index: string | undefined,\n item: any,\n i: number,\n ): AreHTMLNode {\n const itemNode = template.clone() as AreHTMLNode;\n\n owner.addChild(itemNode);\n\n const queue = [itemNode];\n\n while (queue.length > 0) {\n const current = queue.shift()!\n\n current.init();\n\n queue.push(...current.children as AreHTMLNode[]);\n }\n\n /**\n * Resolve or create a directive context for the item node. This is needed to hold the item-specific store values (e.g. the \"item\" and \"index\" in a \"for\" loop) that the template's bindings will reference during compile and update. The context is shared among all clones of the same template, but that's fine because each clone gets its own scope values assigned here.\n */\n let directiveContext = itemNode.scope.resolveFlat(AreDirectiveContext);\n\n if (!directiveContext) {\n directiveContext = new AreDirectiveContext(itemNode.aseid);\n itemNode.scope.register(directiveContext);\n }\n\n directiveContext.scope = {\n ...directiveContext.scope,\n [key]: item,\n [index || 'index']: i,\n }\n\n itemNode.scene.activate();\n\n return itemNode;\n }\n}"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { A_Logger } from '@adaas/a-utils/a-logger';
|
|
2
|
+
import { a as AreDirective, b as AreDirectiveAttribute } from '../AreBinding.attribute-doUvtOjc.mjs';
|
|
3
|
+
import { AreStore, AreScene, AreSyntax } from '@adaas/are';
|
|
4
|
+
import { AreDirectiveContext } from '../lib/AreDirective/AreDirective.context.mjs';
|
|
5
|
+
import '@adaas/a-concept';
|
|
6
|
+
import '../lib/AreStyle/AreStyle.context.mjs';
|
|
7
|
+
import '@adaas/a-utils/a-execution';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `$show` directive — conditionally toggles an element's visibility.
|
|
11
|
+
*
|
|
12
|
+
* Unlike `$if`, `$show` keeps the element fully mounted at all times and only
|
|
13
|
+
* flips its inline `display` (Vue `v-show` semantics). The element's subtree,
|
|
14
|
+
* event listeners and scene state are preserved across toggles, which makes it
|
|
15
|
+
* far cheaper than `$if` for things that flip on/off frequently. Use `$if` when
|
|
16
|
+
* the hidden branch is expensive and rarely shown; use `$show` when it toggles
|
|
17
|
+
* often.
|
|
18
|
+
*
|
|
19
|
+
* ⚠️ Known limitations:
|
|
20
|
+
* - Do NOT combine `$show` with `$if`/`$for` on the SAME element — they share
|
|
21
|
+
* an owner node and would fight over its host instruction. Wrap one in a
|
|
22
|
+
* parent element instead.
|
|
23
|
+
* - `$show` forces inline `display:none`, which beats stylesheet rules but will
|
|
24
|
+
* NOT override the element's own inline `:style="display:..."` binding.
|
|
25
|
+
*/
|
|
26
|
+
declare class AreDirectiveShow extends AreDirective {
|
|
27
|
+
transform(attribute: AreDirectiveAttribute, logger: A_Logger, ...args: any[]): void;
|
|
28
|
+
compile(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, syntax: AreSyntax, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
29
|
+
update(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, syntax: AreSyntax, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { AreDirectiveShow };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { A_Logger } from '@adaas/a-utils/a-logger';
|
|
2
|
+
import { a as AreDirective, b as AreDirectiveAttribute } from '../AreBinding.attribute-Bm5LlOyE.js';
|
|
3
|
+
import { AreStore, AreScene, AreSyntax } from '@adaas/are';
|
|
4
|
+
import { AreDirectiveContext } from '../lib/AreDirective/AreDirective.context.js';
|
|
5
|
+
import '@adaas/a-concept';
|
|
6
|
+
import '../lib/AreStyle/AreStyle.context.js';
|
|
7
|
+
import '@adaas/a-utils/a-execution';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* `$show` directive — conditionally toggles an element's visibility.
|
|
11
|
+
*
|
|
12
|
+
* Unlike `$if`, `$show` keeps the element fully mounted at all times and only
|
|
13
|
+
* flips its inline `display` (Vue `v-show` semantics). The element's subtree,
|
|
14
|
+
* event listeners and scene state are preserved across toggles, which makes it
|
|
15
|
+
* far cheaper than `$if` for things that flip on/off frequently. Use `$if` when
|
|
16
|
+
* the hidden branch is expensive and rarely shown; use `$show` when it toggles
|
|
17
|
+
* often.
|
|
18
|
+
*
|
|
19
|
+
* ⚠️ Known limitations:
|
|
20
|
+
* - Do NOT combine `$show` with `$if`/`$for` on the SAME element — they share
|
|
21
|
+
* an owner node and would fight over its host instruction. Wrap one in a
|
|
22
|
+
* parent element instead.
|
|
23
|
+
* - `$show` forces inline `display:none`, which beats stylesheet rules but will
|
|
24
|
+
* NOT override the element's own inline `:style="display:..."` binding.
|
|
25
|
+
*/
|
|
26
|
+
declare class AreDirectiveShow extends AreDirective {
|
|
27
|
+
transform(attribute: AreDirectiveAttribute, logger: A_Logger, ...args: any[]): void;
|
|
28
|
+
compile(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, syntax: AreSyntax, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
29
|
+
update(attribute: AreDirectiveAttribute, store: AreStore, scene: AreScene, syntax: AreSyntax, directiveContext?: AreDirectiveContext, ...args: any[]): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { AreDirectiveShow };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var aConcept = require('@adaas/a-concept');
|
|
4
|
+
var aLogger = require('@adaas/a-utils/a-logger');
|
|
5
|
+
var are = require('@adaas/are');
|
|
6
|
+
var AreDirective_component = require('@adaas/are-html/directive/AreDirective.component');
|
|
7
|
+
var AreDirective_context = require('@adaas/are-html/directive/AreDirective.context');
|
|
8
|
+
var HideElement_instruction = require('@adaas/are-html/instructions/HideElement.instruction');
|
|
9
|
+
var core = require('@adaas/a-frame/core');
|
|
10
|
+
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
14
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
15
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
16
|
+
if (decorator = decorators[i])
|
|
17
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
18
|
+
if (kind && result) __defProp(target, key, result);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
|
|
22
|
+
exports.AreDirectiveShow = class AreDirectiveShow extends AreDirective_component.AreDirective {
|
|
23
|
+
transform(attribute, logger, ...args) {
|
|
24
|
+
logger.debug(`[Transform] directive $SHOW for <${attribute.owner.aseid.toString()}> (no structural change)`);
|
|
25
|
+
}
|
|
26
|
+
compile(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
27
|
+
const visible = !!syntax.evaluate(attribute.content, store, {
|
|
28
|
+
...directiveContext?.scope || {}
|
|
29
|
+
});
|
|
30
|
+
attribute.value = visible;
|
|
31
|
+
const hide = new HideElement_instruction.HideElementInstruction(scene.host, {});
|
|
32
|
+
attribute.cache = hide;
|
|
33
|
+
if (!visible)
|
|
34
|
+
scene.plan(hide);
|
|
35
|
+
}
|
|
36
|
+
update(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
37
|
+
const previous = !!attribute.value;
|
|
38
|
+
const next = !!syntax.evaluate(attribute.content, store, {
|
|
39
|
+
...directiveContext?.scope || {}
|
|
40
|
+
});
|
|
41
|
+
attribute.value = next;
|
|
42
|
+
if (previous === next) return;
|
|
43
|
+
const hide = attribute.cache;
|
|
44
|
+
if (!hide) return;
|
|
45
|
+
if (next)
|
|
46
|
+
scene.unPlan(hide);
|
|
47
|
+
else
|
|
48
|
+
scene.plan(hide);
|
|
49
|
+
attribute.owner.interpret();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
__decorateClass([
|
|
53
|
+
AreDirective_component.AreDirective.Transform,
|
|
54
|
+
__decorateParam(0, aConcept.A_Inject(aConcept.A_Caller)),
|
|
55
|
+
__decorateParam(1, aConcept.A_Inject(aLogger.A_Logger))
|
|
56
|
+
], exports.AreDirectiveShow.prototype, "transform", 1);
|
|
57
|
+
__decorateClass([
|
|
58
|
+
AreDirective_component.AreDirective.Compile,
|
|
59
|
+
__decorateParam(0, aConcept.A_Inject(aConcept.A_Caller)),
|
|
60
|
+
__decorateParam(1, aConcept.A_Inject(are.AreStore)),
|
|
61
|
+
__decorateParam(2, aConcept.A_Inject(are.AreScene)),
|
|
62
|
+
__decorateParam(3, aConcept.A_Inject(are.AreSyntax)),
|
|
63
|
+
__decorateParam(4, aConcept.A_Inject(AreDirective_context.AreDirectiveContext))
|
|
64
|
+
], exports.AreDirectiveShow.prototype, "compile", 1);
|
|
65
|
+
__decorateClass([
|
|
66
|
+
AreDirective_component.AreDirective.Update,
|
|
67
|
+
__decorateParam(0, aConcept.A_Inject(aConcept.A_Caller)),
|
|
68
|
+
__decorateParam(1, aConcept.A_Inject(are.AreStore)),
|
|
69
|
+
__decorateParam(2, aConcept.A_Inject(are.AreScene)),
|
|
70
|
+
__decorateParam(3, aConcept.A_Inject(are.AreSyntax)),
|
|
71
|
+
__decorateParam(4, aConcept.A_Inject(AreDirective_context.AreDirectiveContext))
|
|
72
|
+
], exports.AreDirectiveShow.prototype, "update", 1);
|
|
73
|
+
exports.AreDirectiveShow = __decorateClass([
|
|
74
|
+
core.A_Frame.Define({
|
|
75
|
+
namespace: "a-are-html",
|
|
76
|
+
description: "Built-in $show directive. Toggles an element's visibility by flipping its inline display value based on a store expression, keeping the element mounted (subtree, listeners and scene state preserved) instead of unmounting it like $if."
|
|
77
|
+
}),
|
|
78
|
+
AreDirective_component.AreDirective.Priority(3)
|
|
79
|
+
], exports.AreDirectiveShow);
|
|
80
|
+
//# sourceMappingURL=AreDirectiveShow.directive.js.map
|
|
81
|
+
//# sourceMappingURL=AreDirectiveShow.directive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/directives/AreDirectiveShow.directive.ts"],"names":["AreDirectiveShow","AreDirective","HideElementInstruction","A_Caller","A_Logger","AreStore","AreScene","AreSyntax","AreDirectiveContext","A_Frame"],"mappings":"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","file":"AreDirectiveShow.directive.js","sourcesContent":["import { A_Caller, A_Inject } from \"@adaas/a-concept\";\nimport { A_Logger } from \"@adaas/a-utils/a-logger\";\nimport { AreDirectiveAttribute } from \"@adaas/are-html/attributes/AreDirective.attribute\";\nimport { AreScene, AreStore, AreSyntax } from \"@adaas/are\";\nimport { AreDirective } from \"@adaas/are-html/directive/AreDirective.component\";\nimport { AreDirectiveContext } from \"@adaas/are-html/directive/AreDirective.context\";\nimport { HideElementInstruction } from \"@adaas/are-html/instructions/HideElement.instruction\";\nimport { A_Frame } from \"@adaas/a-frame/core\";\n\n\n\n/**\n * `$show` directive — conditionally toggles an element's visibility.\n *\n * Unlike `$if`, `$show` keeps the element fully mounted at all times and only\n * flips its inline `display` (Vue `v-show` semantics). The element's subtree,\n * event listeners and scene state are preserved across toggles, which makes it\n * far cheaper than `$if` for things that flip on/off frequently. Use `$if` when\n * the hidden branch is expensive and rarely shown; use `$show` when it toggles\n * often.\n *\n * ⚠️ Known limitations:\n * - Do NOT combine `$show` with `$if`/`$for` on the SAME element — they share\n * an owner node and would fight over its host instruction. Wrap one in a\n * parent element instead.\n * - `$show` forces inline `display:none`, which beats stylesheet rules but will\n * NOT override the element's own inline `:style=\"display:...\"` binding.\n */\n@A_Frame.Define({\n namespace: 'a-are-html',\n description: 'Built-in $show directive. Toggles an element\\'s visibility by flipping its inline display value based on a store expression, keeping the element mounted (subtree, listeners and scene state preserved) instead of unmounting it like $if.'\n})\n@AreDirective.Priority(3)\nexport class AreDirectiveShow extends AreDirective {\n\n\n @AreDirective.Transform\n transform(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(A_Logger) logger: A_Logger,\n ...args: any[]\n ) {\n // $show makes no structural change to the tree — the element stays in\n // place and is only hidden/shown at interpret time. Nothing to do here\n // beyond overriding the base directive's default transform warning.\n logger.debug(`[Transform] directive $SHOW for <${attribute.owner.aseid.toString()}> (no structural change)`)\n }\n\n\n @AreDirective.Compile\n compile(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(AreSyntax) syntax: AreSyntax,\n\n @A_Inject(AreDirectiveContext) directiveContext?: AreDirectiveContext,\n ...args: any[]\n ): void {\n /**\n * 1. Evaluate the expression to determine the initial visibility.\n */\n const visible = !!syntax.evaluate(attribute.content, store, {\n ...(directiveContext?.scope || {}),\n });\n\n attribute.value = visible;\n\n /**\n * 2. Create a single reusable HideElement mutation parented to the\n * element's host instruction, and cache it on the attribute so\n * update() can plan/unplan the exact same instance.\n */\n const hide = new HideElementInstruction(scene.host!, {});\n attribute.cache = hide;\n\n /**\n * 3. When initially hidden, plan the mutation so the first interpret\n * applies `display:none`. When visible, leave it unplanned.\n */\n if (!visible)\n scene.plan(hide);\n }\n\n\n @AreDirective.Update\n update(\n @A_Inject(A_Caller) attribute: AreDirectiveAttribute,\n @A_Inject(AreStore) store: AreStore,\n @A_Inject(AreScene) scene: AreScene,\n @A_Inject(AreSyntax) syntax: AreSyntax,\n\n @A_Inject(AreDirectiveContext) directiveContext?: AreDirectiveContext,\n ...args: any[]\n ): void {\n /**\n * 1. Re-evaluate the expression, forwarding the directive context scope\n * (e.g. a `$for` loop variable) so `$show` reacts correctly inside\n * loops.\n */\n const previous = !!attribute.value;\n const next = !!syntax.evaluate(attribute.content, store, {\n ...(directiveContext?.scope || {}),\n });\n\n attribute.value = next;\n\n // Skip when visibility has not changed — avoids redundant DOM writes.\n if (previous === next) return;\n\n const hide = attribute.cache as HideElementInstruction | undefined;\n\n if (!hide) return;\n\n /**\n * 2. Toggle the cached mutation: unplan to reveal, plan to hide. Then\n * re-interpret the owner so the scene diff applies/reverts it.\n */\n if (next)\n scene.unPlan(hide);\n else\n scene.plan(hide);\n\n attribute.owner.interpret();\n }\n\n}\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { __decorateClass, __decorateParam } from '../chunk-EQQGB2QZ.mjs';
|
|
2
|
+
import { A_Inject, A_Caller } from '@adaas/a-concept';
|
|
3
|
+
import { A_Logger } from '@adaas/a-utils/a-logger';
|
|
4
|
+
import { AreStore, AreScene, AreSyntax } from '@adaas/are';
|
|
5
|
+
import { AreDirective } from '@adaas/are-html/directive/AreDirective.component';
|
|
6
|
+
import { AreDirectiveContext } from '@adaas/are-html/directive/AreDirective.context';
|
|
7
|
+
import { HideElementInstruction } from '@adaas/are-html/instructions/HideElement.instruction';
|
|
8
|
+
import { A_Frame } from '@adaas/a-frame/core';
|
|
9
|
+
|
|
10
|
+
let AreDirectiveShow = class extends AreDirective {
|
|
11
|
+
transform(attribute, logger, ...args) {
|
|
12
|
+
logger.debug(`[Transform] directive $SHOW for <${attribute.owner.aseid.toString()}> (no structural change)`);
|
|
13
|
+
}
|
|
14
|
+
compile(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
15
|
+
const visible = !!syntax.evaluate(attribute.content, store, {
|
|
16
|
+
...directiveContext?.scope || {}
|
|
17
|
+
});
|
|
18
|
+
attribute.value = visible;
|
|
19
|
+
const hide = new HideElementInstruction(scene.host, {});
|
|
20
|
+
attribute.cache = hide;
|
|
21
|
+
if (!visible)
|
|
22
|
+
scene.plan(hide);
|
|
23
|
+
}
|
|
24
|
+
update(attribute, store, scene, syntax, directiveContext, ...args) {
|
|
25
|
+
const previous = !!attribute.value;
|
|
26
|
+
const next = !!syntax.evaluate(attribute.content, store, {
|
|
27
|
+
...directiveContext?.scope || {}
|
|
28
|
+
});
|
|
29
|
+
attribute.value = next;
|
|
30
|
+
if (previous === next) return;
|
|
31
|
+
const hide = attribute.cache;
|
|
32
|
+
if (!hide) return;
|
|
33
|
+
if (next)
|
|
34
|
+
scene.unPlan(hide);
|
|
35
|
+
else
|
|
36
|
+
scene.plan(hide);
|
|
37
|
+
attribute.owner.interpret();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
__decorateClass([
|
|
41
|
+
AreDirective.Transform,
|
|
42
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
43
|
+
__decorateParam(1, A_Inject(A_Logger))
|
|
44
|
+
], AreDirectiveShow.prototype, "transform", 1);
|
|
45
|
+
__decorateClass([
|
|
46
|
+
AreDirective.Compile,
|
|
47
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
48
|
+
__decorateParam(1, A_Inject(AreStore)),
|
|
49
|
+
__decorateParam(2, A_Inject(AreScene)),
|
|
50
|
+
__decorateParam(3, A_Inject(AreSyntax)),
|
|
51
|
+
__decorateParam(4, A_Inject(AreDirectiveContext))
|
|
52
|
+
], AreDirectiveShow.prototype, "compile", 1);
|
|
53
|
+
__decorateClass([
|
|
54
|
+
AreDirective.Update,
|
|
55
|
+
__decorateParam(0, A_Inject(A_Caller)),
|
|
56
|
+
__decorateParam(1, A_Inject(AreStore)),
|
|
57
|
+
__decorateParam(2, A_Inject(AreScene)),
|
|
58
|
+
__decorateParam(3, A_Inject(AreSyntax)),
|
|
59
|
+
__decorateParam(4, A_Inject(AreDirectiveContext))
|
|
60
|
+
], AreDirectiveShow.prototype, "update", 1);
|
|
61
|
+
AreDirectiveShow = __decorateClass([
|
|
62
|
+
A_Frame.Define({
|
|
63
|
+
namespace: "a-are-html",
|
|
64
|
+
description: "Built-in $show directive. Toggles an element's visibility by flipping its inline display value based on a store expression, keeping the element mounted (subtree, listeners and scene state preserved) instead of unmounting it like $if."
|
|
65
|
+
}),
|
|
66
|
+
AreDirective.Priority(3)
|
|
67
|
+
], AreDirectiveShow);
|
|
68
|
+
|
|
69
|
+
export { AreDirectiveShow };
|
|
70
|
+
//# sourceMappingURL=AreDirectiveShow.directive.mjs.map
|
|
71
|
+
//# sourceMappingURL=AreDirectiveShow.directive.mjs.map
|