@adaas/are-html 0.0.2 → 0.0.4
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/README.md +4 -4
- package/dist/browser/index.d.mts +88 -5
- package/dist/browser/index.mjs +542 -176
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/attributes/AreBinding.attribute.js +17 -4
- package/dist/node/attributes/AreBinding.attribute.js.map +1 -1
- package/dist/node/attributes/AreBinding.attribute.mjs +10 -3
- package/dist/node/attributes/AreBinding.attribute.mjs.map +1 -1
- package/dist/node/attributes/AreDirective.attribute.js +17 -4
- package/dist/node/attributes/AreDirective.attribute.js.map +1 -1
- package/dist/node/attributes/AreDirective.attribute.mjs +10 -3
- package/dist/node/attributes/AreDirective.attribute.mjs.map +1 -1
- package/dist/node/attributes/AreEvent.attribute.js +17 -4
- package/dist/node/attributes/AreEvent.attribute.js.map +1 -1
- package/dist/node/attributes/AreEvent.attribute.mjs +10 -3
- package/dist/node/attributes/AreEvent.attribute.mjs.map +1 -1
- package/dist/node/attributes/AreStatic.attribute.js +17 -4
- package/dist/node/attributes/AreStatic.attribute.js.map +1 -1
- package/dist/node/attributes/AreStatic.attribute.mjs +10 -3
- package/dist/node/attributes/AreStatic.attribute.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.mts +8 -0
- package/dist/node/directives/AreDirectiveFor.directive.d.ts +8 -0
- package/dist/node/directives/AreDirectiveFor.directive.js +78 -33
- package/dist/node/directives/AreDirectiveFor.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs +78 -33
- package/dist/node/directives/AreDirectiveFor.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.d.mts +18 -0
- package/dist/node/directives/AreDirectiveIf.directive.d.ts +18 -0
- package/dist/node/directives/AreDirectiveIf.directive.js +10 -3
- package/dist/node/directives/AreDirectiveIf.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.mjs +10 -3
- package/dist/node/directives/AreDirectiveIf.directive.mjs.map +1 -1
- package/dist/node/engine/AreHTML.compiler.d.mts +2 -2
- package/dist/node/engine/AreHTML.compiler.d.ts +2 -2
- package/dist/node/engine/AreHTML.compiler.js +57 -29
- package/dist/node/engine/AreHTML.compiler.js.map +1 -1
- package/dist/node/engine/AreHTML.compiler.mjs +58 -30
- package/dist/node/engine/AreHTML.compiler.mjs.map +1 -1
- package/dist/node/engine/AreHTML.constants.d.mts +53 -1
- package/dist/node/engine/AreHTML.constants.d.ts +53 -1
- package/dist/node/engine/AreHTML.constants.js +100 -0
- package/dist/node/engine/AreHTML.constants.js.map +1 -1
- package/dist/node/engine/AreHTML.constants.mjs +93 -0
- package/dist/node/engine/AreHTML.constants.mjs.map +1 -1
- package/dist/node/engine/AreHTML.context.d.mts +6 -2
- package/dist/node/engine/AreHTML.context.d.ts +6 -2
- package/dist/node/engine/AreHTML.context.js +42 -7
- package/dist/node/engine/AreHTML.context.js.map +1 -1
- package/dist/node/engine/AreHTML.context.mjs +35 -6
- package/dist/node/engine/AreHTML.context.mjs.map +1 -1
- package/dist/node/engine/AreHTML.engine.js +10 -7
- package/dist/node/engine/AreHTML.engine.js.map +1 -1
- package/dist/node/engine/AreHTML.engine.mjs +10 -7
- package/dist/node/engine/AreHTML.engine.mjs.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.js +155 -43
- package/dist/node/engine/AreHTML.interpreter.js.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.mjs +155 -43
- package/dist/node/engine/AreHTML.interpreter.mjs.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.js +17 -12
- package/dist/node/engine/AreHTML.lifecycle.js.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.mjs +9 -2
- package/dist/node/engine/AreHTML.lifecycle.mjs.map +1 -1
- package/dist/node/engine/AreHTML.tokenizer.js +14 -9
- package/dist/node/engine/AreHTML.tokenizer.js.map +1 -1
- package/dist/node/engine/AreHTML.tokenizer.mjs +10 -3
- package/dist/node/engine/AreHTML.tokenizer.mjs.map +1 -1
- package/dist/node/engine/AreHTML.transformer.js +13 -8
- package/dist/node/engine/AreHTML.transformer.js.map +1 -1
- package/dist/node/engine/AreHTML.transformer.mjs +9 -2
- package/dist/node/engine/AreHTML.transformer.mjs.map +1 -1
- package/dist/node/index.d.mts +2 -1
- package/dist/node/index.d.ts +2 -1
- package/dist/node/index.js +3 -3
- package/dist/node/index.mjs +1 -1
- package/dist/node/instructions/AddAttribute.instruction.js +3 -4
- package/dist/node/instructions/AddAttribute.instruction.js.map +1 -1
- package/dist/node/instructions/AddAttribute.instruction.mjs +3 -4
- package/dist/node/instructions/AddAttribute.instruction.mjs.map +1 -1
- package/dist/node/instructions/AddComment.instruction.js +3 -4
- package/dist/node/instructions/AddComment.instruction.js.map +1 -1
- package/dist/node/instructions/AddComment.instruction.mjs +3 -4
- package/dist/node/instructions/AddComment.instruction.mjs.map +1 -1
- package/dist/node/instructions/AddElement.instruction.js +3 -4
- package/dist/node/instructions/AddElement.instruction.js.map +1 -1
- package/dist/node/instructions/AddElement.instruction.mjs +3 -4
- package/dist/node/instructions/AddElement.instruction.mjs.map +1 -1
- package/dist/node/instructions/AddInterpolation.instruction.js +3 -4
- package/dist/node/instructions/AddInterpolation.instruction.js.map +1 -1
- package/dist/node/instructions/AddInterpolation.instruction.mjs +3 -4
- package/dist/node/instructions/AddInterpolation.instruction.mjs.map +1 -1
- package/dist/node/instructions/AddListener.instruction.js +3 -4
- package/dist/node/instructions/AddListener.instruction.js.map +1 -1
- package/dist/node/instructions/AddListener.instruction.mjs +3 -4
- package/dist/node/instructions/AddListener.instruction.mjs.map +1 -1
- package/dist/node/instructions/AddStyle.instruction.js +3 -4
- package/dist/node/instructions/AddStyle.instruction.js.map +1 -1
- package/dist/node/instructions/AddStyle.instruction.mjs +3 -4
- package/dist/node/instructions/AddStyle.instruction.mjs.map +1 -1
- package/dist/node/instructions/AddText.instruction.js +3 -4
- package/dist/node/instructions/AddText.instruction.js.map +1 -1
- package/dist/node/instructions/AddText.instruction.mjs +3 -4
- package/dist/node/instructions/AddText.instruction.mjs.map +1 -1
- package/dist/node/lib/AreDirective/AreDirective.component.js +5 -0
- package/dist/node/lib/AreDirective/AreDirective.component.js.map +1 -1
- package/dist/node/lib/AreDirective/AreDirective.component.mjs +5 -0
- package/dist/node/lib/AreDirective/AreDirective.component.mjs.map +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.js +17 -4
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.js.map +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.mjs +10 -3
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.mjs.map +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js +3 -4
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js.map +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs +3 -4
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.js +3 -4
- package/dist/node/lib/AreRoot/AreRoot.component.js.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.mjs +3 -4
- package/dist/node/lib/AreRoot/AreRoot.component.mjs.map +1 -1
- package/dist/node/lib/{AreWatcher/AreWatcher.component.d.mts → AreRouteWatcher/AreRouteWatcher.component.d.mts} +2 -2
- package/dist/node/lib/{AreWatcher/AreWatcher.component.d.ts → AreRouteWatcher/AreRouteWatcher.component.d.ts} +2 -2
- package/dist/node/lib/{AreWatcher/AreWatcher.component.js → AreRouteWatcher/AreRouteWatcher.component.js} +9 -10
- package/dist/node/lib/AreRouteWatcher/AreRouteWatcher.component.js.map +1 -0
- package/dist/node/lib/{AreWatcher/AreWatcher.component.mjs → AreRouteWatcher/AreRouteWatcher.component.mjs} +10 -11
- package/dist/node/lib/AreRouteWatcher/AreRouteWatcher.component.mjs.map +1 -0
- package/dist/node/lib/AreStyle/AreStyle.context.js +17 -4
- package/dist/node/lib/AreStyle/AreStyle.context.js.map +1 -1
- package/dist/node/lib/AreStyle/AreStyle.context.mjs +10 -3
- package/dist/node/lib/AreStyle/AreStyle.context.mjs.map +1 -1
- package/dist/node/nodes/AreComment.js +17 -4
- package/dist/node/nodes/AreComment.js.map +1 -1
- package/dist/node/nodes/AreComment.mjs +10 -3
- package/dist/node/nodes/AreComment.mjs.map +1 -1
- package/dist/node/nodes/AreComponent.js +3 -4
- package/dist/node/nodes/AreComponent.js.map +1 -1
- package/dist/node/nodes/AreComponent.mjs +3 -4
- package/dist/node/nodes/AreComponent.mjs.map +1 -1
- package/dist/node/nodes/AreInterpolation.js +17 -4
- package/dist/node/nodes/AreInterpolation.js.map +1 -1
- package/dist/node/nodes/AreInterpolation.mjs +10 -3
- package/dist/node/nodes/AreInterpolation.mjs.map +1 -1
- package/dist/node/nodes/AreRoot.js +3 -4
- package/dist/node/nodes/AreRoot.js.map +1 -1
- package/dist/node/nodes/AreRoot.mjs +3 -4
- package/dist/node/nodes/AreRoot.mjs.map +1 -1
- package/dist/node/nodes/AreText.js +17 -4
- package/dist/node/nodes/AreText.js.map +1 -1
- package/dist/node/nodes/AreText.mjs +10 -3
- package/dist/node/nodes/AreText.mjs.map +1 -1
- package/dist/node/signals/AreRoute.signal.js +18 -5
- package/dist/node/signals/AreRoute.signal.js.map +1 -1
- package/dist/node/signals/AreRoute.signal.mjs +10 -3
- package/dist/node/signals/AreRoute.signal.mjs.map +1 -1
- package/docs/SYNTAX.md +714 -0
- package/docs/arehtml.monaco.json +235 -0
- package/docs/arehtml.monaco.ts +119 -0
- package/examples/dashboard/dist/index.html +1 -1
- package/examples/dashboard/dist/mpioi5ab-8c3oa9.js +13674 -0
- package/examples/jumpstart/dist/index.html +1 -1
- package/examples/{dashboard/dist/mnzfypsd-6zjt7w.js → jumpstart/dist/mor90p6y-0plg7g.js} +1869 -1926
- package/examples/jumpstart/dist/{mnpl1g4i-nobz9g.js → mor90p7p-1898bz.js} +2797 -2282
- package/examples/jumpstart/src/components/List.component.ts +14 -13
- package/examples/jumpstart/src/concept.ts +5 -4
- package/jest.config.ts +1 -1
- package/package.json +10 -6
- package/src/attributes/AreBinding.attribute.ts +5 -0
- package/src/attributes/AreDirective.attribute.ts +5 -0
- package/src/attributes/AreEvent.attribute.ts +5 -0
- package/src/attributes/AreStatic.attribute.ts +5 -0
- package/src/directives/AreDirectiveFor.directive.ts +97 -60
- package/src/directives/AreDirectiveIf.directive.ts +37 -15
- package/src/engine/AreHTML.compiler.ts +64 -36
- package/src/engine/AreHTML.constants.ts +144 -0
- package/src/engine/AreHTML.context.ts +33 -4
- package/src/engine/AreHTML.engine.ts +12 -7
- package/src/engine/AreHTML.interpreter.ts +195 -68
- package/src/engine/AreHTML.lifecycle.ts +5 -0
- package/src/engine/AreHTML.tokenizer.ts +6 -1
- package/src/engine/AreHTML.transformer.ts +5 -0
- package/src/index.ts +2 -2
- package/src/instructions/AddAttribute.instruction.ts +3 -4
- package/src/instructions/AddComment.instruction.ts +3 -4
- package/src/instructions/AddElement.instruction.ts +3 -4
- package/src/instructions/AddInterpolation.instruction.ts +3 -4
- package/src/instructions/AddListener.instruction.ts +3 -4
- package/src/instructions/AddStyle.instruction.ts +3 -4
- package/src/instructions/AddText.instruction.ts +3 -4
- package/src/lib/AreDirective/AreDirective.component.ts +5 -0
- package/src/lib/AreHTMLAttribute/AreHTML.attribute.ts +5 -0
- package/src/lib/AreHTMLNode/AreHTMLNode.ts +3 -4
- package/src/lib/AreRoot/AreRoot.component.ts +3 -4
- package/src/lib/{AreWatcher/AreWatcher.component.ts → AreRouteWatcher/AreRouteWatcher.component.ts} +5 -6
- package/src/lib/AreStyle/AreStyle.context.ts +5 -0
- package/src/nodes/AreComment.ts +5 -0
- package/src/nodes/AreComponent.ts +3 -4
- package/src/nodes/AreInterpolation.ts +5 -0
- package/src/nodes/AreRoot.ts +3 -4
- package/src/nodes/AreText.ts +5 -0
- package/src/signals/AreRoute.signal.ts +5 -0
- package/dist/node/lib/AreWatcher/AreWatcher.component.js.map +0 -1
- package/dist/node/lib/AreWatcher/AreWatcher.component.mjs.map +0 -1
|
@@ -1,2 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boolean HTML attributes whose presence (regardless of value) implies "true",
|
|
3
|
+
* and whose absence implies "false". Setting these via `setAttribute(name, value)`
|
|
4
|
+
* always renders the attribute, which is wrong for reactive bindings.
|
|
5
|
+
*
|
|
6
|
+
* Reference: https://html.spec.whatwg.org/multipage/indices.html#attributes-3
|
|
7
|
+
*/
|
|
8
|
+
export const BOOLEAN_ATTRIBUTES = new Set<string>([
|
|
9
|
+
'allowfullscreen',
|
|
10
|
+
'async',
|
|
11
|
+
'autofocus',
|
|
12
|
+
'autoplay',
|
|
13
|
+
'checked',
|
|
14
|
+
'controls',
|
|
15
|
+
'default',
|
|
16
|
+
'defer',
|
|
17
|
+
'disabled',
|
|
18
|
+
'formnovalidate',
|
|
19
|
+
'hidden',
|
|
20
|
+
'inert',
|
|
21
|
+
'ismap',
|
|
22
|
+
'itemscope',
|
|
23
|
+
'loop',
|
|
24
|
+
'multiple',
|
|
25
|
+
'muted',
|
|
26
|
+
'nomodule',
|
|
27
|
+
'novalidate',
|
|
28
|
+
'open',
|
|
29
|
+
'playsinline',
|
|
30
|
+
'readonly',
|
|
31
|
+
'required',
|
|
32
|
+
'reversed',
|
|
33
|
+
'selected',
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
export function isBooleanAttribute(name: string): boolean {
|
|
37
|
+
return BOOLEAN_ATTRIBUTES.has(name.toLowerCase());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Form-control IDL properties that must be set as a JS property
|
|
42
|
+
* (not just an attribute) so live user input is reflected.
|
|
43
|
+
*
|
|
44
|
+
* `<input value="foo">` only sets the *default* value;
|
|
45
|
+
* `input.value = "foo"` updates the live state.
|
|
46
|
+
*/
|
|
47
|
+
export const IDL_FORM_PROPERTIES: Record<string, Set<string>> = {
|
|
48
|
+
INPUT: new Set(['value', 'checked', 'indeterminate']),
|
|
49
|
+
TEXTAREA: new Set(['value']),
|
|
50
|
+
SELECT: new Set(['value']),
|
|
51
|
+
OPTION: new Set(['selected']),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export function isIDLFormProperty(tagName: string, attrName: string): boolean {
|
|
55
|
+
const set = IDL_FORM_PROPERTIES[tagName.toUpperCase()];
|
|
56
|
+
return !!set && set.has(attrName);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Normalize a `:class` binding value into a single space-separated string.
|
|
61
|
+
* Supports the common shapes:
|
|
62
|
+
* - string → "a b"
|
|
63
|
+
* - array<string | object | falsy> → ["a", { b: true, c: cond }, null]
|
|
64
|
+
* - object<string, boolean> → { a: true, b: false }
|
|
65
|
+
*/
|
|
66
|
+
export function normalizeClassValue(value: any): string {
|
|
67
|
+
if (value === null || value === undefined || value === false) return '';
|
|
68
|
+
if (typeof value === 'string') return value;
|
|
69
|
+
if (typeof value === 'number') return String(value);
|
|
70
|
+
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
return value.map(normalizeClassValue).filter(Boolean).join(' ');
|
|
73
|
+
}
|
|
74
|
+
if (typeof value === 'object') {
|
|
75
|
+
const parts: string[] = [];
|
|
76
|
+
for (const key of Object.keys(value)) {
|
|
77
|
+
if (value[key]) parts.push(key);
|
|
78
|
+
}
|
|
79
|
+
return parts.join(' ');
|
|
80
|
+
}
|
|
81
|
+
return '';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Normalize a `:style` binding value into an inline-style string.
|
|
86
|
+
* Supports:
|
|
87
|
+
* - string → "color: red; font-size: 12px"
|
|
88
|
+
* - object<string, string|number> → { color: 'red', fontSize: '12px' }
|
|
89
|
+
* - array<string | object> → ['color: red', { fontSize: '12px' }]
|
|
90
|
+
*/
|
|
91
|
+
export function normalizeStyleValue(value: any): string {
|
|
92
|
+
if (value === null || value === undefined || value === false) return '';
|
|
93
|
+
if (typeof value === 'string') return value;
|
|
94
|
+
if (typeof value === 'number') return String(value);
|
|
95
|
+
|
|
96
|
+
if (Array.isArray(value)) {
|
|
97
|
+
return value.map(normalizeStyleValue).filter(Boolean).join('; ');
|
|
98
|
+
}
|
|
99
|
+
if (typeof value === 'object') {
|
|
100
|
+
const parts: string[] = [];
|
|
101
|
+
for (const key of Object.keys(value)) {
|
|
102
|
+
const v = value[key];
|
|
103
|
+
if (v === null || v === undefined || v === false) continue;
|
|
104
|
+
const kebab = key.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
|
|
105
|
+
parts.push(`${kebab}: ${v}`);
|
|
106
|
+
}
|
|
107
|
+
return parts.join('; ');
|
|
108
|
+
}
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Parse a DOM event name with modifiers, e.g. "click.stop.prevent" or "keydown.enter".
|
|
114
|
+
* Returns the bare event name plus the modifier set.
|
|
115
|
+
*/
|
|
116
|
+
export interface ParsedEventName {
|
|
117
|
+
event: string;
|
|
118
|
+
modifiers: Set<string>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function parseEventName(raw: string): ParsedEventName {
|
|
122
|
+
const [event, ...modifiers] = raw.split('.');
|
|
123
|
+
return { event, modifiers: new Set(modifiers) };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Known event-listener modifiers that map directly to addEventListener options.
|
|
128
|
+
*/
|
|
129
|
+
export const LISTENER_OPTION_MODIFIERS = new Set(['capture', 'once', 'passive']);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Coerce a value into a string for DOM consumption.
|
|
133
|
+
* Avoids "undefined"/"null"/"[object Object]" leaks into the DOM.
|
|
134
|
+
*/
|
|
135
|
+
export function toDOMString(value: any): string {
|
|
136
|
+
if (value === null || value === undefined) return '';
|
|
137
|
+
if (typeof value === 'string') return value;
|
|
138
|
+
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
139
|
+
try {
|
|
140
|
+
return JSON.stringify(value);
|
|
141
|
+
} catch {
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
1
145
|
|
|
2
146
|
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { AreContext, AreInstruction, AreNode } from "@adaas/are";
|
|
2
2
|
import { AreHTMLContextConstructor } from "./AreHTML.types";
|
|
3
|
+
import { A_Frame } from "@adaas/a-frame/core";
|
|
3
4
|
|
|
4
5
|
|
|
6
|
+
@A_Frame.Define({
|
|
7
|
+
namespace: 'a-are-html',
|
|
8
|
+
description: 'Runtime index for the HTML rendering engine. Maps each AreNode and instruction ASEID to its corresponding DOM element so that apply and revert handlers on interpreter instructions can look up their DOM node in O(1). Tracks root-element mounts and maintains the group-level index used by structural directives.'
|
|
9
|
+
})
|
|
5
10
|
export class AreHTMLEngineContext extends AreContext {
|
|
6
11
|
|
|
7
12
|
/**
|
|
@@ -41,7 +46,7 @@ export class AreHTMLEngineContext extends AreContext {
|
|
|
41
46
|
/**
|
|
42
47
|
* Event listeners attached to elements, used for proper cleanup when reverting instructions. Maps a DOM element to a map of event names and their corresponding listeners, allowing the engine to track which listeners are attached to which elements and remove them when necessary (e.g., when an instruction is reverted).
|
|
43
48
|
*/
|
|
44
|
-
elementListeners: new WeakMap<Node, Map<string, EventListenerOrEventListenerObject
|
|
49
|
+
elementListeners: new WeakMap<Node, Map<string, Set<EventListenerOrEventListenerObject>>>()
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
/**
|
|
@@ -172,7 +177,11 @@ export class AreHTMLEngineContext extends AreContext {
|
|
|
172
177
|
if (!this.index.elementListeners.has(element)) {
|
|
173
178
|
this.index.elementListeners.set(element, new Map());
|
|
174
179
|
}
|
|
175
|
-
this.index.elementListeners.get(element)
|
|
180
|
+
const byEvent = this.index.elementListeners.get(element)!;
|
|
181
|
+
if (!byEvent.has(eventName)) {
|
|
182
|
+
byEvent.set(eventName, new Set());
|
|
183
|
+
}
|
|
184
|
+
byEvent.get(eventName)!.add(listener);
|
|
176
185
|
}
|
|
177
186
|
/**
|
|
178
187
|
* Retrieves the event listener associated with a specific DOM element and event name from the context's index. This method looks up the element in the elementListeners map and then retrieves the listener for the specified event name. If no listener is found for the given element and event, it returns undefined. This allows the engine to efficiently access and manage event listeners that have been attached to dynamically created elements, enabling proper cleanup when instructions are reverted or when nodes are removed from the DOM.
|
|
@@ -182,6 +191,16 @@ export class AreHTMLEngineContext extends AreContext {
|
|
|
182
191
|
* @returns
|
|
183
192
|
*/
|
|
184
193
|
getListener(element: Node, eventName: string): EventListenerOrEventListenerObject | undefined {
|
|
194
|
+
const set = this.index.elementListeners.get(element)?.get(eventName);
|
|
195
|
+
if (!set || set.size === 0) return undefined;
|
|
196
|
+
// Return the first listener for backwards compatibility.
|
|
197
|
+
return set.values().next().value;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Returns all listeners registered for a given element + event name.
|
|
202
|
+
*/
|
|
203
|
+
getListeners(element: Node, eventName: string): Set<EventListenerOrEventListenerObject> | undefined {
|
|
185
204
|
return this.index.elementListeners.get(element)?.get(eventName);
|
|
186
205
|
}
|
|
187
206
|
/**
|
|
@@ -190,7 +209,17 @@ export class AreHTMLEngineContext extends AreContext {
|
|
|
190
209
|
* @param element
|
|
191
210
|
* @param eventName
|
|
192
211
|
*/
|
|
193
|
-
removeListener(element: Node, eventName: string): void {
|
|
194
|
-
this.index.elementListeners.get(element)
|
|
212
|
+
removeListener(element: Node, eventName: string, listener?: EventListenerOrEventListenerObject): void {
|
|
213
|
+
const byEvent = this.index.elementListeners.get(element);
|
|
214
|
+
if (!byEvent) return;
|
|
215
|
+
if (listener) {
|
|
216
|
+
const set = byEvent.get(eventName);
|
|
217
|
+
if (set) {
|
|
218
|
+
set.delete(listener);
|
|
219
|
+
if (set.size === 0) byEvent.delete(eventName);
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
byEvent.delete(eventName);
|
|
223
|
+
}
|
|
195
224
|
}
|
|
196
225
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A_Feature, A_Inject, A_Scope } from "@adaas/a-concept";
|
|
2
|
-
import { A_Frame } from "@adaas/a-frame"
|
|
2
|
+
import { A_Frame } from "@adaas/a-frame/core"
|
|
3
3
|
import { A_ServiceFeatures } from "@adaas/a-utils/a-service";
|
|
4
4
|
import { AreEngine, AreSyntaxTokenMatch, AreSyntax } from "@adaas/are";
|
|
5
5
|
import { AreHTMLInterpreter } from "@adaas/are-html/interpreter";
|
|
@@ -16,10 +16,9 @@ import { AreHTMLCompiler } from "./AreHTML.compiler";
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
@A_Frame.
|
|
20
|
-
namespace: '
|
|
21
|
-
|
|
22
|
-
description: 'HTML Rendering Engine for A-Concept Rendering Engine (ARE), responsible for processing and rendering HTML templates within the ARE framework.'
|
|
19
|
+
@A_Frame.Define({
|
|
20
|
+
namespace: 'a-are-html',
|
|
21
|
+
description: 'Concrete HTML rendering engine that assembles the full ARE pipeline for web environments. Bootstraps and wires AreHTMLTokenizer, AreHTMLTransformer, AreHTMLCompiler, AreHTMLInterpreter, and AreHTMLLifecycle; mounts root nodes from inline or fetched templates; and drives reactive re-renders via the AreSignals bus.'
|
|
23
22
|
})
|
|
24
23
|
export class AreHTMLEngine extends AreEngine {
|
|
25
24
|
|
|
@@ -167,8 +166,14 @@ export class AreHTMLEngine extends AreEngine {
|
|
|
167
166
|
if (nextOpen !== -1 && nextOpen < nextClose) {
|
|
168
167
|
const charAfter = source[nextOpen + tagName.length + 1]
|
|
169
168
|
if (charAfter === ' ' || charAfter === '>' || charAfter === '/') {
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
// Skip self-closing nested occurrences, e.g. <div/> inside <div>...</div>.
|
|
170
|
+
const innerEnd = AreHTMLEngine.findTagClose(source, nextOpen)
|
|
171
|
+
const isSelfClose = innerEnd !== -1 && source[innerEnd - 1] === '/'
|
|
172
|
+
|
|
173
|
+
if (!isSelfClose) {
|
|
174
|
+
level++
|
|
175
|
+
}
|
|
176
|
+
searchIndex = (innerEnd === -1 ? nextOpen + tagName.length + 1 : innerEnd + 1)
|
|
172
177
|
continue
|
|
173
178
|
}
|
|
174
179
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
-
import { A_Frame } from "@adaas/a-frame"
|
|
2
|
+
import { A_Frame } from "@adaas/a-frame/core"
|
|
3
3
|
import { A_Logger } from "@adaas/a-utils/a-logger";
|
|
4
4
|
import {
|
|
5
5
|
AreSyntax, AreStore,
|
|
@@ -17,18 +17,25 @@ import { AddTextInstruction } from "@adaas/are-html/instructions/AddText.instruc
|
|
|
17
17
|
import { AreDirectiveContext } from "@adaas/are-html/directive/AreDirective.context";
|
|
18
18
|
import { AreHTMLNode } from "../lib/AreHTMLNode/AreHTMLNode";
|
|
19
19
|
import { AreHTMLEngineContext } from "./AreHTML.context";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
import {
|
|
21
|
+
isBooleanAttribute,
|
|
22
|
+
isIDLFormProperty,
|
|
23
|
+
normalizeClassValue,
|
|
24
|
+
normalizeStyleValue,
|
|
25
|
+
parseEventName,
|
|
26
|
+
toDOMString,
|
|
27
|
+
} from "./AreHTML.constants";
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@A_Frame.Define({
|
|
31
|
+
namespace: 'a-are-html',
|
|
32
|
+
description: 'DOM interpreter for the HTML rendering pipeline. Extends AreInterpreter to apply and revert each ARE instruction type directly against the browser DOM — creating and removing elements, setting and removing attributes and event listeners, managing inline styles, and inserting text and comment nodes. Driven by the scene diff computed per render cycle.'
|
|
26
33
|
})
|
|
27
34
|
export class AreHTMLInterpreter extends AreInterpreter {
|
|
28
35
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
36
|
// ── CreateElement — Apply / Revert ───────────────────────────────────────────
|
|
30
37
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
31
|
-
@A_Frame.
|
|
38
|
+
@A_Frame.Define({
|
|
32
39
|
description: 'Create an HTML element based on the provided declaration instruction. Handles both root-level mounting and child element creation based on the structural parent hierarchy.'
|
|
33
40
|
})
|
|
34
41
|
@AreInterpreter.Apply(AreInstructionDefaultNames.Default)
|
|
@@ -68,6 +75,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
const element = context.container.createElement(tag);
|
|
78
|
+
element.setAttribute('data-aseid', node.aseid.toString());
|
|
71
79
|
|
|
72
80
|
if (mountPoint.nodeType === Node.ELEMENT_NODE) {
|
|
73
81
|
// parent is a real element — just append
|
|
@@ -109,7 +117,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
|
|
112
|
-
@A_Frame.
|
|
120
|
+
@A_Frame.Define({
|
|
113
121
|
description: 'Remove an HTML element that was created by a CreateElement declaration. Cleans up the DOM and the context index.'
|
|
114
122
|
})
|
|
115
123
|
@AreInterpreter.Revert(AreInstructionDefaultNames.Default)
|
|
@@ -131,7 +139,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
131
139
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
132
140
|
// ── AddAttribute — Apply / Revert ────────────────────────────────────────────
|
|
133
141
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
134
|
-
@A_Frame.
|
|
142
|
+
@A_Frame.Define({
|
|
135
143
|
description: 'Add an attribute to an HTML element based on the provided mutation instruction.'
|
|
136
144
|
})
|
|
137
145
|
@AreInterpreter.Apply(AreHTMLInstructions.AddAttribute)
|
|
@@ -156,43 +164,93 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
156
164
|
}
|
|
157
165
|
const { name, content, evaluate } = mutation.payload;
|
|
158
166
|
|
|
159
|
-
const
|
|
167
|
+
const rawValue = evaluate ? syntax.evaluate(content, store, {
|
|
160
168
|
...(directiveContext?.scope || {})
|
|
161
169
|
}) : content;
|
|
162
170
|
|
|
171
|
+
const el = element as HTMLElement;
|
|
172
|
+
const lowerName = name.toLowerCase();
|
|
163
173
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
// ── 1. Boolean attributes ────────────────────────────────────────────
|
|
175
|
+
if (isBooleanAttribute(lowerName)) {
|
|
176
|
+
if (rawValue) {
|
|
177
|
+
el.setAttribute(lowerName, '');
|
|
178
|
+
// also reflect IDL property where supported (disabled, hidden, …)
|
|
179
|
+
try { (el as any)[lowerName] = true; } catch { /* ignore */ }
|
|
180
|
+
} else {
|
|
181
|
+
el.removeAttribute(lowerName);
|
|
182
|
+
try { (el as any)[lowerName] = false; } catch { /* ignore */ }
|
|
183
|
+
}
|
|
184
|
+
mutation.cache = rawValue ? 'true' : '';
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
176
187
|
|
|
177
|
-
|
|
188
|
+
// ── 2. Form-control IDL properties (value/checked/selected) ─────────
|
|
189
|
+
if (isIDLFormProperty(el.tagName, name)) {
|
|
190
|
+
const propName = name === 'value' ? 'value'
|
|
191
|
+
: name === 'checked' ? 'checked'
|
|
192
|
+
: name === 'selected' ? 'selected'
|
|
193
|
+
: name === 'indeterminate' ? 'indeterminate'
|
|
194
|
+
: name;
|
|
195
|
+
try {
|
|
196
|
+
if (propName === 'checked' || propName === 'selected' || propName === 'indeterminate') {
|
|
197
|
+
(el as any)[propName] = !!rawValue;
|
|
198
|
+
} else {
|
|
199
|
+
(el as any)[propName] = toDOMString(rawValue);
|
|
200
|
+
}
|
|
201
|
+
} catch { /* ignore */ }
|
|
202
|
+
// also keep the attribute in sync for SSR/CSS selectors
|
|
203
|
+
if (propName !== 'value') {
|
|
204
|
+
if (rawValue) el.setAttribute(name, ''); else el.removeAttribute(name);
|
|
205
|
+
} else {
|
|
206
|
+
el.setAttribute(name, toDOMString(rawValue));
|
|
207
|
+
}
|
|
208
|
+
mutation.cache = toDOMString(rawValue);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
178
211
|
|
|
179
|
-
|
|
212
|
+
// ── 3. Class binding — supports object/array/string and merges ──────
|
|
213
|
+
if (lowerName === 'class') {
|
|
214
|
+
const newValue = normalizeClassValue(rawValue);
|
|
180
215
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
216
|
+
if (mutation.cache === undefined) {
|
|
217
|
+
const existingValue = el.getAttribute('class');
|
|
218
|
+
const merged = existingValue ? `${existingValue} ${newValue}`.trim() : newValue;
|
|
219
|
+
if (merged) el.setAttribute('class', merged); else el.removeAttribute('class');
|
|
220
|
+
} else {
|
|
221
|
+
const existingValue = el.getAttribute('class');
|
|
222
|
+
const existingParts = existingValue ? existingValue.split(/\s+/).filter(Boolean) : [];
|
|
223
|
+
const oldParts = new Set((mutation.cache as string).split(/\s+/).filter(Boolean));
|
|
224
|
+
const newParts = newValue ? newValue.split(/\s+/).filter(Boolean) : [];
|
|
184
225
|
|
|
185
|
-
|
|
226
|
+
const merged = [...existingParts.filter(p => !oldParts.has(p)), ...newParts].join(' ');
|
|
227
|
+
if (merged) el.setAttribute('class', merged); else el.removeAttribute('class');
|
|
228
|
+
}
|
|
229
|
+
mutation.cache = newValue;
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
186
232
|
|
|
187
|
-
|
|
233
|
+
// ── 4. Style binding — supports object/array/string ─────────────────
|
|
234
|
+
if (lowerName === 'style') {
|
|
235
|
+
const newValue = normalizeStyleValue(rawValue);
|
|
236
|
+
if (newValue) el.setAttribute('style', newValue); else el.removeAttribute('style');
|
|
237
|
+
mutation.cache = newValue;
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
188
240
|
|
|
189
|
-
|
|
241
|
+
// ── 5. Default: replace attribute (no whitespace merge) ─────────────
|
|
242
|
+
const stringValue = toDOMString(rawValue);
|
|
243
|
+
if (stringValue === '' && evaluate && (rawValue === false || rawValue === null || rawValue === undefined)) {
|
|
244
|
+
el.removeAttribute(name);
|
|
245
|
+
} else {
|
|
246
|
+
el.setAttribute(name, stringValue);
|
|
190
247
|
}
|
|
248
|
+
mutation.cache = stringValue;
|
|
191
249
|
|
|
192
250
|
|
|
193
251
|
}
|
|
194
252
|
|
|
195
|
-
@A_Frame.
|
|
253
|
+
@A_Frame.Define({
|
|
196
254
|
description: 'Remove an attribute from an HTML element based on the provided mutation instruction.'
|
|
197
255
|
})
|
|
198
256
|
@AreInterpreter.Revert(AreHTMLInstructions.AddAttribute)
|
|
@@ -221,7 +279,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
221
279
|
// ── addEventListener — Apply / Revert ────────────────────────────────────────
|
|
222
280
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
223
281
|
|
|
224
|
-
@A_Frame.
|
|
282
|
+
@A_Frame.Define({
|
|
225
283
|
description: 'Add an event listener to an HTML element based on the provided mutation instruction.'
|
|
226
284
|
})
|
|
227
285
|
@AreInterpreter.Apply(AreHTMLInstructions.AddListener)
|
|
@@ -244,54 +302,117 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
244
302
|
}
|
|
245
303
|
|
|
246
304
|
/**
|
|
247
|
-
* e.g. @click="handleClick"
|
|
248
|
-
*
|
|
305
|
+
* e.g. @click="handleClick"
|
|
249
306
|
* e.g. @click="handleClick($event, element)"
|
|
250
|
-
*
|
|
251
|
-
* e.g. @
|
|
252
|
-
*
|
|
253
|
-
* e.g. @click="(e)=> isValid(user.name) ? handleClick(e) : null" (with conditional logic)
|
|
254
|
-
*
|
|
255
|
-
* e.g. @click="(e)=> isValid(user.name) ? handleClick(e, format(user.name)) : null" (with conditional logic)
|
|
307
|
+
* e.g. @click.stop.prevent="handleClick"
|
|
308
|
+
* e.g. @keydown.enter="submit"
|
|
309
|
+
* e.g. @click="(e)=> user.name ? handleClick(e) : null"
|
|
256
310
|
*/
|
|
257
311
|
|
|
312
|
+
const { event: eventName, modifiers } = parseEventName(mutation.payload.name);
|
|
313
|
+
|
|
314
|
+
const listenerOptions: AddEventListenerOptions = {};
|
|
315
|
+
if (modifiers.has('capture')) listenerOptions.capture = true;
|
|
316
|
+
if (modifiers.has('once')) listenerOptions.once = true;
|
|
317
|
+
if (modifiers.has('passive')) listenerOptions.passive = true;
|
|
258
318
|
|
|
259
319
|
const handlers = syntax.extractEmitHandlers(mutation.payload.handler);
|
|
260
|
-
|
|
320
|
+
|
|
321
|
+
// Holds the live DOM event so handler invocations (with or without
|
|
322
|
+
// template arguments) always have access to it.
|
|
323
|
+
let liveEvent: Event | null = null;
|
|
324
|
+
|
|
325
|
+
const handlerScope: Record<string, any> = {};
|
|
261
326
|
|
|
262
327
|
for (const handler of handlers) {
|
|
263
328
|
const handlerFn = (...args: any[]) => {
|
|
264
|
-
const event = new AreEvent(handler)
|
|
265
|
-
|
|
266
|
-
event.
|
|
329
|
+
const event = new AreEvent(handler);
|
|
330
|
+
// If user passed only template args (e.g. $h('x')), append the DOM
|
|
331
|
+
// event as the last arg. If they passed nothing, args[0] is the DOM event.
|
|
332
|
+
const effectiveArgs = args.length === 0 && liveEvent
|
|
333
|
+
? [liveEvent]
|
|
334
|
+
: liveEvent
|
|
335
|
+
? [...args, liveEvent]
|
|
336
|
+
: args;
|
|
337
|
+
event.set('args', effectiveArgs);
|
|
267
338
|
event.set('element', element);
|
|
268
339
|
event.set('instruction', mutation);
|
|
269
|
-
|
|
270
340
|
mutation.owner.emit(event);
|
|
271
|
-
}
|
|
272
|
-
|
|
341
|
+
};
|
|
273
342
|
handlerScope[`$${handler}`] = handlerFn;
|
|
274
343
|
}
|
|
275
344
|
|
|
276
345
|
const callback = (e: Event) => {
|
|
277
|
-
|
|
346
|
+
try {
|
|
347
|
+
liveEvent = e;
|
|
348
|
+
|
|
349
|
+
if (modifiers.has('self') && e.target !== element) return;
|
|
350
|
+
if (modifiers.has('stop')) e.stopPropagation();
|
|
351
|
+
if (modifiers.has('prevent')) e.preventDefault();
|
|
352
|
+
|
|
353
|
+
// key-name modifiers for keyboard events: @keydown.enter / .esc / .tab / .space / .up / .down / .left / .right / .delete
|
|
354
|
+
if (e instanceof KeyboardEvent && modifiers.size > 0) {
|
|
355
|
+
const key = (e.key || '').toLowerCase();
|
|
356
|
+
const KEY_ALIASES: Record<string, string[]> = {
|
|
357
|
+
enter: ['enter'],
|
|
358
|
+
esc: ['escape'],
|
|
359
|
+
escape: ['escape'],
|
|
360
|
+
tab: ['tab'],
|
|
361
|
+
space: [' ', 'spacebar'],
|
|
362
|
+
up: ['arrowup'],
|
|
363
|
+
down: ['arrowdown'],
|
|
364
|
+
left: ['arrowleft'],
|
|
365
|
+
right: ['arrowright'],
|
|
366
|
+
delete: ['delete', 'backspace'],
|
|
367
|
+
};
|
|
368
|
+
const keyMods = [...modifiers].filter(m =>
|
|
369
|
+
m in KEY_ALIASES ||
|
|
370
|
+
m === 'ctrl' || m === 'alt' || m === 'shift' || m === 'meta');
|
|
371
|
+
|
|
372
|
+
if (keyMods.length > 0) {
|
|
373
|
+
const keyMatch = keyMods.some(m => {
|
|
374
|
+
if (m === 'ctrl') return e.ctrlKey;
|
|
375
|
+
if (m === 'alt') return e.altKey;
|
|
376
|
+
if (m === 'shift') return e.shiftKey;
|
|
377
|
+
if (m === 'meta') return e.metaKey;
|
|
378
|
+
const aliases = KEY_ALIASES[m];
|
|
379
|
+
return aliases && aliases.includes(key);
|
|
380
|
+
});
|
|
381
|
+
if (!keyMatch) return;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
278
384
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
385
|
+
context.startPerformance('event:' + eventName);
|
|
386
|
+
|
|
387
|
+
const result = syntax.evaluate(mutation.payload.handler, store, {
|
|
388
|
+
...handlerScope,
|
|
389
|
+
$event: e,
|
|
390
|
+
...(directiveContext?.scope || {})
|
|
391
|
+
});
|
|
392
|
+
if (typeof result === 'function') result(e);
|
|
285
393
|
|
|
394
|
+
context.endPerformance('event:' + eventName);
|
|
395
|
+
} catch (err) {
|
|
396
|
+
logger?.error(err);
|
|
397
|
+
} finally {
|
|
398
|
+
liveEvent = null;
|
|
399
|
+
}
|
|
400
|
+
};
|
|
286
401
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
402
|
+
const useOptions = listenerOptions.capture || listenerOptions.once || listenerOptions.passive;
|
|
403
|
+
if (useOptions) {
|
|
404
|
+
element.addEventListener(eventName, callback, listenerOptions);
|
|
405
|
+
} else {
|
|
406
|
+
element.addEventListener(eventName, callback);
|
|
290
407
|
}
|
|
408
|
+
// Track on both the context (for diagnostics) and the mutation itself
|
|
409
|
+
// so the revert path can detach the exact same callback.
|
|
410
|
+
(mutation.payload as any)._callback = callback;
|
|
411
|
+
context.addListener(element, mutation.payload.name, callback);
|
|
291
412
|
}
|
|
292
413
|
|
|
293
414
|
|
|
294
|
-
@A_Frame.
|
|
415
|
+
@A_Frame.Define({
|
|
295
416
|
description: 'Remove an event listener from an HTML element based on the provided mutation instruction.'
|
|
296
417
|
})
|
|
297
418
|
@AreInterpreter.Revert(AreHTMLInstructions.AddListener)
|
|
@@ -304,12 +425,14 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
304
425
|
if (!element) return;
|
|
305
426
|
|
|
306
427
|
const { name } = mutation.payload;
|
|
428
|
+
const { event: eventName } = parseEventName(name);
|
|
307
429
|
|
|
308
|
-
const listener =
|
|
430
|
+
const listener = (mutation.payload as any)._callback as EventListenerOrEventListenerObject | undefined;
|
|
309
431
|
|
|
310
432
|
if (listener) {
|
|
311
|
-
element.removeEventListener(
|
|
312
|
-
context.removeListener(element, name);
|
|
433
|
+
element.removeEventListener(eventName, listener);
|
|
434
|
+
context.removeListener(element, name, listener);
|
|
435
|
+
(mutation.payload as any)._callback = undefined;
|
|
313
436
|
}
|
|
314
437
|
}
|
|
315
438
|
|
|
@@ -318,7 +441,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
318
441
|
// ── AddText — Apply / Revert ─────────────────────────────────────────────────
|
|
319
442
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
320
443
|
|
|
321
|
-
@A_Frame.
|
|
444
|
+
@A_Frame.Define({
|
|
322
445
|
description: 'Add text content to an HTML element based on the provided declaration instruction.'
|
|
323
446
|
})
|
|
324
447
|
@AreInterpreter.Apply(AreHTMLInstructions.AddText)
|
|
@@ -335,10 +458,12 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
335
458
|
const node = declaration.owner.parent;
|
|
336
459
|
const { content, evaluate } = declaration.payload;
|
|
337
460
|
|
|
338
|
-
const
|
|
461
|
+
const rawValue = evaluate ? syntax.evaluate(content, store, {
|
|
339
462
|
...(directiveContext?.scope || {})
|
|
340
463
|
}) : content;
|
|
341
464
|
|
|
465
|
+
const value = toDOMString(rawValue);
|
|
466
|
+
|
|
342
467
|
|
|
343
468
|
if (!node) {
|
|
344
469
|
const textNode = context.container.createTextNode(value);
|
|
@@ -375,7 +500,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
375
500
|
}
|
|
376
501
|
|
|
377
502
|
|
|
378
|
-
@A_Frame.
|
|
503
|
+
@A_Frame.Define({
|
|
379
504
|
description: 'Remove text content from an HTML element based on the provided declaration instruction.'
|
|
380
505
|
})
|
|
381
506
|
@AreInterpreter.Revert(AreHTMLInstructions.AddText)
|
|
@@ -393,7 +518,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
393
518
|
|
|
394
519
|
|
|
395
520
|
|
|
396
|
-
@A_Frame.
|
|
521
|
+
@A_Frame.Define({
|
|
397
522
|
description: 'Add a comment node to the DOM based on the provided declaration instruction.'
|
|
398
523
|
})
|
|
399
524
|
@AreInterpreter.Apply(AreHTMLInstructions.AddComment)
|
|
@@ -410,10 +535,12 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
410
535
|
const node = declaration.owner.parent;
|
|
411
536
|
const { content, evaluate } = declaration.payload;
|
|
412
537
|
|
|
413
|
-
const
|
|
538
|
+
const rawValue = evaluate ? syntax.evaluate(content, store, {
|
|
414
539
|
...(directiveContext?.scope || {})
|
|
415
540
|
}) : content;
|
|
416
541
|
|
|
542
|
+
const value = toDOMString(rawValue);
|
|
543
|
+
|
|
417
544
|
|
|
418
545
|
if (!node) {
|
|
419
546
|
const commentNode = context.container.createComment(value);
|
|
@@ -448,7 +575,7 @@ export class AreHTMLInterpreter extends AreInterpreter {
|
|
|
448
575
|
}
|
|
449
576
|
|
|
450
577
|
|
|
451
|
-
@A_Frame.
|
|
578
|
+
@A_Frame.Define({
|
|
452
579
|
description: 'Remove a comment node from the DOM based on the provided declaration instruction.'
|
|
453
580
|
})
|
|
454
581
|
@AreInterpreter.Revert(AreHTMLInstructions.AddComment)
|