@adaas/are-html 0.0.11 → 0.0.13
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 +19 -4
- package/dist/browser/index.mjs +115 -8
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/{AreBinding.attribute-C6JasbJL.d.ts → AreBinding.attribute-Bm5LlOyE.d.ts} +7 -0
- package/dist/node/{AreBinding.attribute-C6qrxN8K.d.mts → AreBinding.attribute-doUvtOjc.d.mts} +7 -0
- package/dist/node/attributes/AreBinding.attribute.d.mts +1 -1
- package/dist/node/attributes/AreBinding.attribute.d.ts +1 -1
- package/dist/node/attributes/AreDirective.attribute.d.mts +1 -1
- package/dist/node/attributes/AreDirective.attribute.d.ts +1 -1
- package/dist/node/attributes/AreEvent.attribute.d.mts +1 -1
- package/dist/node/attributes/AreEvent.attribute.d.ts +1 -1
- package/dist/node/attributes/AreStatic.attribute.d.mts +1 -1
- package/dist/node/attributes/AreStatic.attribute.d.ts +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.mts +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.d.ts +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.js +11 -1
- package/dist/node/directives/AreDirectiveFor.directive.js.map +1 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs +11 -1
- package/dist/node/directives/AreDirectiveFor.directive.mjs.map +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.d.mts +1 -1
- package/dist/node/directives/AreDirectiveIf.directive.d.ts +1 -1
- package/dist/node/engine/AreHTML.compiler.d.mts +8 -1
- package/dist/node/engine/AreHTML.compiler.d.ts +8 -1
- package/dist/node/engine/AreHTML.compiler.js +17 -0
- package/dist/node/engine/AreHTML.compiler.js.map +1 -1
- package/dist/node/engine/AreHTML.compiler.mjs +17 -0
- package/dist/node/engine/AreHTML.compiler.mjs.map +1 -1
- package/dist/node/engine/AreHTML.context.js +2 -2
- package/dist/node/engine/AreHTML.context.js.map +1 -1
- package/dist/node/engine/AreHTML.context.mjs +3 -3
- package/dist/node/engine/AreHTML.context.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 +44 -0
- package/dist/node/engine/AreHTML.interpreter.js.map +1 -1
- package/dist/node/engine/AreHTML.interpreter.mjs +44 -0
- package/dist/node/engine/AreHTML.interpreter.mjs.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.d.mts +2 -1
- package/dist/node/engine/AreHTML.lifecycle.d.ts +2 -1
- package/dist/node/engine/AreHTML.lifecycle.js +13 -1
- package/dist/node/engine/AreHTML.lifecycle.js.map +1 -1
- package/dist/node/engine/AreHTML.lifecycle.mjs +13 -1
- package/dist/node/engine/AreHTML.lifecycle.mjs.map +1 -1
- package/dist/node/engine/AreHTML.tokenizer.d.mts +1 -1
- package/dist/node/engine/AreHTML.tokenizer.d.ts +1 -1
- package/dist/node/engine/AreHTML.transformer.d.mts +1 -1
- package/dist/node/engine/AreHTML.transformer.d.ts +1 -1
- package/dist/node/index.d.mts +1 -1
- package/dist/node/index.d.ts +1 -1
- package/dist/node/instructions/AreHTML.instructions.types.d.mts +2 -4
- package/dist/node/instructions/AreHTML.instructions.types.d.ts +2 -4
- package/dist/node/lib/AreDirective/AreDirective.component.d.mts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.component.d.ts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.types.d.mts +1 -1
- package/dist/node/lib/AreDirective/AreDirective.types.d.ts +1 -1
- package/dist/node/lib/AreHTML/AreHTML.tokenizer.d.mts +1 -1
- package/dist/node/lib/AreHTML/AreHTML.tokenizer.d.ts +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.d.mts +1 -1
- package/dist/node/lib/AreHTMLAttribute/AreHTML.attribute.d.ts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.d.mts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.d.ts +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js +14 -0
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.js.map +1 -1
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs +14 -0
- package/dist/node/lib/AreHTMLNode/AreHTMLNode.mjs.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.js +16 -3
- package/dist/node/lib/AreRoot/AreRoot.component.js.map +1 -1
- package/dist/node/lib/AreRoot/AreRoot.component.mjs +16 -3
- package/dist/node/lib/AreRoot/AreRoot.component.mjs.map +1 -1
- package/dist/node/nodes/AreComment.d.mts +1 -1
- package/dist/node/nodes/AreComment.d.ts +1 -1
- package/dist/node/nodes/AreComponent.d.mts +1 -1
- package/dist/node/nodes/AreComponent.d.ts +1 -1
- package/dist/node/nodes/AreInterpolation.d.mts +1 -1
- package/dist/node/nodes/AreInterpolation.d.ts +1 -1
- package/dist/node/nodes/AreRoot.d.mts +1 -1
- package/dist/node/nodes/AreRoot.d.ts +1 -1
- package/dist/node/nodes/AreText.d.mts +1 -1
- package/dist/node/nodes/AreText.d.ts +1 -1
- package/examples/component-styles/concept.ts +41 -0
- package/examples/component-styles/containers/UI.container.ts +122 -0
- package/examples/component-styles/dist/index.html +25 -0
- package/examples/{jumpstart/dist/mor90p6y-0plg7g.js → component-styles/dist/mpq29j47-owas2v.js} +8326 -5942
- package/examples/component-styles/public/index.html +25 -0
- package/examples/component-styles/src/components/AppPage.component.ts +74 -0
- package/examples/component-styles/src/components/TheAlert.component.ts +81 -0
- package/examples/component-styles/src/components/TheButton.component.ts +71 -0
- package/examples/component-styles/src/components/TheCard.component.ts +64 -0
- package/examples/component-styles/src/concept.ts +70 -0
- package/examples/dashboard/dist/index.html +1 -1
- package/examples/dashboard/dist/{mpmt0gys-1r9rcu.js → mppzjw80-9gwa4h.js} +1223 -863
- package/examples/jumpstart/dist/index.html +1 -1
- package/examples/jumpstart/dist/{mor90p7p-1898bz.js → mppwx932-xbmb0x.js} +4215 -1984
- package/examples/signal-routing/concept.ts +41 -0
- package/examples/signal-routing/containers/UI.container.ts +126 -0
- package/examples/signal-routing/dist/index.html +18 -0
- package/examples/signal-routing/dist/mpq6u1wz-2pkqe2.js +14002 -0
- package/examples/signal-routing/public/index.html +18 -0
- package/examples/signal-routing/src/components/AboutPage.component.ts +74 -0
- package/examples/signal-routing/src/components/AppShell.component.ts +42 -0
- package/examples/signal-routing/src/components/HomePage.component.ts +76 -0
- package/examples/signal-routing/src/components/NavBar.component.ts +104 -0
- package/examples/signal-routing/src/components/SettingsPage.component.ts +98 -0
- package/examples/signal-routing/src/concept.ts +114 -0
- package/package.json +7 -5
- package/src/directives/AreDirectiveFor.directive.ts +12 -1
- package/src/engine/AreHTML.compiler.ts +24 -7
- package/src/engine/AreHTML.context.ts +6 -4
- package/src/engine/AreHTML.interpreter.ts +54 -0
- package/src/engine/AreHTML.lifecycle.ts +16 -12
- package/src/instructions/AreHTML.instructions.types.ts +2 -4
- package/src/lib/AreHTMLNode/AreHTMLNode.ts +15 -0
- package/src/lib/AreRoot/AreRoot.component.ts +31 -7
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>ARE · Signal Routing</title>
|
|
7
|
+
<style>
|
|
8
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
9
|
+
body { background: #09090b; color: #f4f4f5; }
|
|
10
|
+
are-root { display: block; }
|
|
11
|
+
</style>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<are-root id="app"><app-shell></app-shell></are-root>
|
|
15
|
+
|
|
16
|
+
<script type="module" src="./{{BUNDLE_ID}}.js"></script>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { Are, AreNode } from "@adaas/are";
|
|
3
|
+
import { AreHTMLNode } from "src";
|
|
4
|
+
import { AreRoute } from "src/signals/AreRoute.signal";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* About page — rendered when the route is "/about".
|
|
9
|
+
*/
|
|
10
|
+
@Are.Condition([new AreRoute('/about')])
|
|
11
|
+
export class AboutPage extends Are {
|
|
12
|
+
|
|
13
|
+
@Are.Template
|
|
14
|
+
template(@A_Inject(A_Caller) node: AreNode) {
|
|
15
|
+
node.setContent(`
|
|
16
|
+
<section class="page page-about">
|
|
17
|
+
<h1 class="page-title">About this example</h1>
|
|
18
|
+
<p class="page-subtitle">
|
|
19
|
+
This example demonstrates signal-based SPA routing using the ARE framework.
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<div class="about-block">
|
|
23
|
+
<h2>How it works</h2>
|
|
24
|
+
<ol class="steps">
|
|
25
|
+
<li>
|
|
26
|
+
<strong>Signal emitted</strong> — clicking a nav link calls
|
|
27
|
+
<code>bus.emit(new AreRoute('/about'))</code> and updates the browser
|
|
28
|
+
URL via <code>history.pushState</code>.
|
|
29
|
+
</li>
|
|
30
|
+
<li>
|
|
31
|
+
<strong>AreRoot reacts</strong> — the root node is subscribed to the
|
|
32
|
+
signal bus. When the vector matches a registered condition it replaces
|
|
33
|
+
its inner content with the mapped component.
|
|
34
|
+
</li>
|
|
35
|
+
<li>
|
|
36
|
+
<strong>Page renders</strong> — the new component goes through the normal
|
|
37
|
+
ARE lifecycle: <code>@Are.Template</code> → <code>@Are.Data</code> →
|
|
38
|
+
<code>@Are.Styles</code> → mount.
|
|
39
|
+
</li>
|
|
40
|
+
</ol>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="about-block">
|
|
44
|
+
<h2>Key pieces</h2>
|
|
45
|
+
<table class="info-table">
|
|
46
|
+
<tr><th>AreRoute(path)</th><td>Signal carrying the new URL path.</td></tr>
|
|
47
|
+
<tr><th>AreRouteWatcher</th><td>Listens to popstate / pushState and re-emits the signal on browser back/forward.</td></tr>
|
|
48
|
+
<tr><th>AreSignalsContext</th><td>Fragment that maps (rootId, signal vector) → component class.</td></tr>
|
|
49
|
+
<tr><th>A_SignalState</th><td>Persists the last emitted signal so a fresh page load still routes correctly.</td></tr>
|
|
50
|
+
</table>
|
|
51
|
+
</div>
|
|
52
|
+
</section>
|
|
53
|
+
`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@Are.Styles
|
|
57
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
58
|
+
node.setStyles(`
|
|
59
|
+
.page { padding: 48px 40px; max-width: 860px; margin: 0 auto; }
|
|
60
|
+
.page-title { font-size: 32px; font-weight: 800; color: #f4f4f5; margin-bottom: 12px; }
|
|
61
|
+
.page-subtitle { font-size: 16px; color: #a1a1aa; line-height: 1.7; margin-bottom: 36px; }
|
|
62
|
+
.about-block { margin-bottom: 40px; }
|
|
63
|
+
.about-block h2 { font-size: 18px; font-weight: 700; color: #e4e4e7; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid #27272a; }
|
|
64
|
+
.steps { padding-left: 24px; color: #a1a1aa; line-height: 2; font-size: 14px; }
|
|
65
|
+
.steps li { margin-bottom: 8px; }
|
|
66
|
+
.steps strong { color: #e4e4e7; }
|
|
67
|
+
.steps code, .info-table code { background: #27272a; padding: 1px 6px; border-radius: 4px; color: #a78bfa; font-size: 12px; }
|
|
68
|
+
.info-table { width: 100%; border-collapse: collapse; font-size: 14px; }
|
|
69
|
+
.info-table tr { border-bottom: 1px solid #27272a; }
|
|
70
|
+
.info-table th { text-align: left; padding: 10px 12px; color: #a78bfa; font-weight: 600; width: 200px; }
|
|
71
|
+
.info-table td { padding: 10px 12px; color: #a1a1aa; }
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { Are, AreNode } from "@adaas/are";
|
|
3
|
+
import { AreHTMLNode } from "src";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Root shell — holds the persistent NavBar and the router outlet (`<are-root>`).
|
|
8
|
+
*
|
|
9
|
+
* The inner `<are-root id="page-outlet">` is the actual dynamic slot.
|
|
10
|
+
* `AreSignalsContext` maps route signals to page components keyed by "page-outlet".
|
|
11
|
+
*/
|
|
12
|
+
export class AppShell extends Are {
|
|
13
|
+
|
|
14
|
+
@Are.Template
|
|
15
|
+
template(@A_Inject(A_Caller) node: AreNode) {
|
|
16
|
+
node.setContent(`
|
|
17
|
+
<div class="app-shell">
|
|
18
|
+
<nav-bar></nav-bar>
|
|
19
|
+
<main class="app-main">
|
|
20
|
+
<are-root id="page-outlet"><home-page></home-page></are-root>
|
|
21
|
+
</main>
|
|
22
|
+
</div>
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Are.Styles
|
|
27
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
28
|
+
node.setStyles(`
|
|
29
|
+
.app-shell {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
min-height: 100vh;
|
|
33
|
+
background: #09090b;
|
|
34
|
+
color: #f4f4f5;
|
|
35
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
36
|
+
}
|
|
37
|
+
.app-main {
|
|
38
|
+
flex: 1;
|
|
39
|
+
}
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { A_SignalVector } from "@adaas/a-utils/a-signal";
|
|
3
|
+
import { Are, AreNode, AreSignalsContext, AreStore } from "@adaas/are";
|
|
4
|
+
import { AreHTMLNode } from "src";
|
|
5
|
+
import { AreRoute } from "src/signals/AreRoute.signal";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Home page — rendered when the route is "/".
|
|
10
|
+
*/
|
|
11
|
+
@Are.Condition([new AreRoute('/')])
|
|
12
|
+
export class HomePage extends Are {
|
|
13
|
+
|
|
14
|
+
@Are.Template
|
|
15
|
+
template(@A_Inject(A_Caller) node: AreNode) {
|
|
16
|
+
node.setContent(`
|
|
17
|
+
<section class="page page-home">
|
|
18
|
+
<div class="page-hero">
|
|
19
|
+
<h1 class="page-title">Welcome to Signal Routing</h1>
|
|
20
|
+
<p class="page-subtitle">
|
|
21
|
+
This page is rendered because the current route matched <code>/</code>.<br/>
|
|
22
|
+
Navigate using the links above — no full page reload, just signals.
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="card-grid">
|
|
26
|
+
<div class="card">
|
|
27
|
+
<div class="card-icon">⚡</div>
|
|
28
|
+
<h3>Signal-based</h3>
|
|
29
|
+
<p>Route changes emit an <code>AreRoute</code> signal on the bus. <code>AreRoot</code> responds and swaps the active component.</p>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="card">
|
|
32
|
+
<div class="card-icon">🔀</div>
|
|
33
|
+
<h3>Zero reload</h3>
|
|
34
|
+
<p>No browser navigation occurs. <code>history.pushState</code> keeps the URL bar in sync so deep-links and back/forward still work.</p>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="card">
|
|
37
|
+
<div class="card-icon">🧩</div>
|
|
38
|
+
<h3>Component-level</h3>
|
|
39
|
+
<p>Each page is a plain <code>Are</code> component. Register it in <code>AreSignalsContext</code> and the router does the rest.</p>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</section>
|
|
43
|
+
`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Are.Styles
|
|
47
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
48
|
+
node.setStyles(`
|
|
49
|
+
.page { padding: 48px 40px; max-width: 960px; margin: 0 auto; }
|
|
50
|
+
.page-hero { margin-bottom: 40px; }
|
|
51
|
+
.page-title { font-size: 32px; font-weight: 800; color: #f4f4f5; margin-bottom: 12px; }
|
|
52
|
+
.page-subtitle { font-size: 16px; color: #a1a1aa; line-height: 1.7; }
|
|
53
|
+
.page-subtitle code { background: #27272a; padding: 2px 6px; border-radius: 4px; color: #a78bfa; font-size: 13px; }
|
|
54
|
+
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 20px; }
|
|
55
|
+
.card { background: #1c1c1f; border: 1px solid #27272a; border-radius: 12px; padding: 24px; }
|
|
56
|
+
.card-icon { font-size: 28px; margin-bottom: 12px; }
|
|
57
|
+
.card h3 { font-size: 16px; font-weight: 600; color: #f4f4f5; margin-bottom: 8px; }
|
|
58
|
+
.card p { font-size: 14px; color: #71717a; line-height: 1.6; }
|
|
59
|
+
.card p code { background: #27272a; padding: 1px 5px; border-radius: 3px; color: #a78bfa; font-size: 12px; }
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@Are.Signal
|
|
65
|
+
async onSignal(
|
|
66
|
+
@A_Inject(A_Caller) root: AreNode,
|
|
67
|
+
@A_Inject(A_SignalVector) vector: A_SignalVector,
|
|
68
|
+
@A_Inject(AreStore) store: AreStore<{ default: string }>,
|
|
69
|
+
@A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,
|
|
70
|
+
) {
|
|
71
|
+
const rootId = root.id;
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
console.log(`HomePage received signal: ${vector.toString()} for rootId: ${rootId}`, root, signalsContext);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { A_SignalBus, A_SignalVector } from "@adaas/a-utils/a-signal";
|
|
3
|
+
import { Are, AreEvent, AreNode, AreSignalsContext, AreStore } from "@adaas/are";
|
|
4
|
+
import { AreHTMLNode } from "src";
|
|
5
|
+
import { AreRoute } from "@adaas/are-html/signals/AreRoute.signal";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Top navigation bar.
|
|
10
|
+
*
|
|
11
|
+
* Each nav link dispatches an `AreRoute` signal via the SignalBus.
|
|
12
|
+
* `AreRoot` picks up the signal and swaps the active page component.
|
|
13
|
+
*
|
|
14
|
+
* No browser hard-navigation happens — history.pushState keeps the URL
|
|
15
|
+
* in sync for deep-linking and the back/forward buttons.
|
|
16
|
+
*/
|
|
17
|
+
export class NavBar extends Are {
|
|
18
|
+
|
|
19
|
+
@Are.Template
|
|
20
|
+
template(@A_Inject(A_Caller) node: AreNode) {
|
|
21
|
+
node.setContent(`
|
|
22
|
+
<nav class="navbar">
|
|
23
|
+
<div class="navbar-brand">ARE · Signal Router</div>
|
|
24
|
+
<ul class="navbar-links">
|
|
25
|
+
<li><a href="/" @click="$navigate('/')">Home</a></li>
|
|
26
|
+
<li><a href="/about" @click="$navigate('/about')">About</a></li>
|
|
27
|
+
<li><a href="/settings" @click="$navigate('/settings')">Settings</a></li>
|
|
28
|
+
</ul>
|
|
29
|
+
</nav>
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Are.Styles
|
|
34
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
35
|
+
node.setStyles(`
|
|
36
|
+
.navbar {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: space-between;
|
|
40
|
+
padding: 0 32px;
|
|
41
|
+
height: 56px;
|
|
42
|
+
background: #18181b;
|
|
43
|
+
border-bottom: 1px solid #27272a;
|
|
44
|
+
position: sticky;
|
|
45
|
+
top: 0;
|
|
46
|
+
z-index: 100;
|
|
47
|
+
}
|
|
48
|
+
.navbar-brand {
|
|
49
|
+
font-size: 16px;
|
|
50
|
+
font-weight: 700;
|
|
51
|
+
color: #a78bfa;
|
|
52
|
+
letter-spacing: -0.02em;
|
|
53
|
+
}
|
|
54
|
+
.navbar-links {
|
|
55
|
+
list-style: none;
|
|
56
|
+
display: flex;
|
|
57
|
+
gap: 8px;
|
|
58
|
+
margin: 0;
|
|
59
|
+
padding: 0;
|
|
60
|
+
}
|
|
61
|
+
.navbar-links a {
|
|
62
|
+
display: inline-block;
|
|
63
|
+
padding: 6px 16px;
|
|
64
|
+
border-radius: 6px;
|
|
65
|
+
text-decoration: none;
|
|
66
|
+
color: #a1a1aa;
|
|
67
|
+
font-size: 14px;
|
|
68
|
+
font-weight: 500;
|
|
69
|
+
transition: background 0.15s, color 0.15s;
|
|
70
|
+
}
|
|
71
|
+
.navbar-links a:hover {
|
|
72
|
+
background: #27272a;
|
|
73
|
+
color: #f4f4f5;
|
|
74
|
+
}
|
|
75
|
+
`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@Are.EventHandler
|
|
79
|
+
navigate(
|
|
80
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
81
|
+
@A_Inject(A_SignalBus) bus: A_SignalBus,
|
|
82
|
+
) {
|
|
83
|
+
const e = event.get('native') as MouseEvent;
|
|
84
|
+
e?.preventDefault();
|
|
85
|
+
|
|
86
|
+
const path = event.get('args')?.[0] as string ?? '/';
|
|
87
|
+
history.pushState({}, '', path);
|
|
88
|
+
bus.next(new AreRoute(path));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@Are.Signal
|
|
93
|
+
async onSignal(
|
|
94
|
+
@A_Inject(A_Caller) root: AreNode,
|
|
95
|
+
@A_Inject(A_SignalVector) vector: A_SignalVector,
|
|
96
|
+
@A_Inject(AreStore) store: AreStore<{ default: string }>,
|
|
97
|
+
@A_Inject(AreSignalsContext) signalsContext?: AreSignalsContext,
|
|
98
|
+
) {
|
|
99
|
+
const rootId = root.id;
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
console.log(`NavBar received signal: ${vector.toString()} for rootId: ${rootId}`, root, signalsContext);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { A_Caller, A_Inject } from "@adaas/a-concept";
|
|
2
|
+
import { A_SignalBus } from "@adaas/a-utils/a-signal";
|
|
3
|
+
import { Are, AreEvent, AreNode, AreStore } from "@adaas/are";
|
|
4
|
+
import { AreHTMLNode } from "src";
|
|
5
|
+
import { AreRoute } from "src/signals/AreRoute.signal";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Settings page — rendered when the route is "/settings".
|
|
10
|
+
*/
|
|
11
|
+
@Are.Condition([new AreRoute('/settings')])
|
|
12
|
+
export class SettingsPage extends Are {
|
|
13
|
+
|
|
14
|
+
@Are.Template
|
|
15
|
+
template(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
16
|
+
node.setContent(`
|
|
17
|
+
<section class="page page-settings">
|
|
18
|
+
<h1 class="page-title">Settings</h1>
|
|
19
|
+
<p class="page-subtitle">Preferences are stored in the component's local store.</p>
|
|
20
|
+
|
|
21
|
+
<div class="settings-group">
|
|
22
|
+
<h2>Appearance</h2>
|
|
23
|
+
<label class="setting-row">
|
|
24
|
+
<span>Dark mode</span>
|
|
25
|
+
<input type="checkbox" checked disabled />
|
|
26
|
+
</label>
|
|
27
|
+
<label class="setting-row">
|
|
28
|
+
<span>Compact layout</span>
|
|
29
|
+
<input type="checkbox" @change="$toggleCompact" />
|
|
30
|
+
</label>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="settings-group">
|
|
34
|
+
<h2>Display name</h2>
|
|
35
|
+
<div class="input-row">
|
|
36
|
+
<input
|
|
37
|
+
id="display-name"
|
|
38
|
+
type="text"
|
|
39
|
+
placeholder="Enter your name…"
|
|
40
|
+
@input="$onNameInput"
|
|
41
|
+
/>
|
|
42
|
+
<span class="preview">Preview: <strong>{{displayName}}</strong></span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="settings-group">
|
|
47
|
+
<h2>Routing state</h2>
|
|
48
|
+
<p class="hint">
|
|
49
|
+
Current route is held in <code>A_SignalState</code> so refreshing the page
|
|
50
|
+
at <code>/settings</code> still lands here — no extra server config needed.
|
|
51
|
+
</p>
|
|
52
|
+
</div>
|
|
53
|
+
</section>
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@Are.Data
|
|
58
|
+
data(@A_Inject(AreStore) store: AreStore) {
|
|
59
|
+
store.set({ displayName: 'Guest', compact: false });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Are.Styles
|
|
63
|
+
styles(@A_Inject(A_Caller) node: AreHTMLNode) {
|
|
64
|
+
node.setStyles(`
|
|
65
|
+
.page { padding: 48px 40px; max-width: 720px; margin: 0 auto; }
|
|
66
|
+
.page-title { font-size: 32px; font-weight: 800; color: #f4f4f5; margin-bottom: 12px; }
|
|
67
|
+
.page-subtitle { font-size: 15px; color: #a1a1aa; margin-bottom: 36px; }
|
|
68
|
+
.settings-group { margin-bottom: 36px; }
|
|
69
|
+
.settings-group h2 { font-size: 15px; font-weight: 700; color: #e4e4e7; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid #27272a; }
|
|
70
|
+
.setting-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; color: #a1a1aa; font-size: 14px; cursor: pointer; }
|
|
71
|
+
.input-row { display: flex; align-items: center; gap: 16px; }
|
|
72
|
+
.input-row input[type="text"] { background: #1c1c1f; border: 1px solid #3f3f46; border-radius: 8px; color: #f4f4f5; padding: 8px 14px; font-size: 14px; outline: none; width: 260px; }
|
|
73
|
+
.input-row input[type="text"]:focus { border-color: #a78bfa; }
|
|
74
|
+
.preview { font-size: 14px; color: #71717a; }
|
|
75
|
+
.preview strong { color: #a78bfa; }
|
|
76
|
+
.hint { font-size: 13px; color: #71717a; line-height: 1.7; }
|
|
77
|
+
.hint code { background: #27272a; padding: 1px 6px; border-radius: 4px; color: #a78bfa; font-size: 12px; }
|
|
78
|
+
`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@Are.EventHandler
|
|
82
|
+
onNameInput(
|
|
83
|
+
@A_Inject(AreStore) store: AreStore,
|
|
84
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
85
|
+
) {
|
|
86
|
+
const el = (event.get('native') as Event)?.target as HTMLInputElement;
|
|
87
|
+
store.set('displayName', el?.value || 'Guest');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@Are.EventHandler
|
|
91
|
+
toggleCompact(
|
|
92
|
+
@A_Inject(AreStore) store: AreStore,
|
|
93
|
+
@A_Inject(AreEvent) event: AreEvent,
|
|
94
|
+
) {
|
|
95
|
+
const el = (event.get('native') as Event)?.target as HTMLInputElement;
|
|
96
|
+
store.set('compact', el?.checked ?? false);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { A_Concept, A_Context } from "@adaas/a-concept";
|
|
2
|
+
import { A_Config, ConfigReader } from "@adaas/a-utils/a-config";
|
|
3
|
+
import { A_Logger, A_LOGGER_ENV_KEYS } from "@adaas/a-utils/a-logger";
|
|
4
|
+
import { A_SignalBus, A_SignalState } from "@adaas/a-utils/a-signal";
|
|
5
|
+
import { A_Polyfill } from "@adaas/a-utils/a-polyfill";
|
|
6
|
+
import {
|
|
7
|
+
AreContainer,
|
|
8
|
+
AreInit,
|
|
9
|
+
AreSignalsContext,
|
|
10
|
+
} from "@adaas/are";
|
|
11
|
+
import {
|
|
12
|
+
AreRoot,
|
|
13
|
+
AreHTMLEngine,
|
|
14
|
+
AreHTMLEngineContext,
|
|
15
|
+
AreDirectiveIf,
|
|
16
|
+
AreDirectiveFor,
|
|
17
|
+
AreRouteWatcher,
|
|
18
|
+
} from "src";
|
|
19
|
+
|
|
20
|
+
// ── Components ─────────────────────────────────────────────────────────────
|
|
21
|
+
import { AppShell } from "./components/AppShell.component";
|
|
22
|
+
import { NavBar } from "./components/NavBar.component";
|
|
23
|
+
import { HomePage } from "./components/HomePage.component";
|
|
24
|
+
import { AboutPage } from "./components/AboutPage.component";
|
|
25
|
+
import { SettingsPage } from "./components/SettingsPage.component";
|
|
26
|
+
|
|
27
|
+
// ── Signals ────────────────────────────────────────────────────────────────
|
|
28
|
+
// AreRoute must come from are-html (not @adaas/are) — it must match the class
|
|
29
|
+
// NavBar emits. Using the base-lib class causes state.has() to return false
|
|
30
|
+
// and the bus silently drops every route signal.
|
|
31
|
+
import { AreRoute as AreRouteSignal } from "src/signals/AreRoute.signal";
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
(async () => {
|
|
35
|
+
try {
|
|
36
|
+
/**
|
|
37
|
+
* AreSignalsContext maps (rootId → conditions).
|
|
38
|
+
*
|
|
39
|
+
* The outer <are-root id="app"> renders the AppShell unconditionally
|
|
40
|
+
* via the `default` attribute in HTML — no routing config needed there.
|
|
41
|
+
*
|
|
42
|
+
* The inner <are-root id="page-outlet"> is the dynamic slot.
|
|
43
|
+
* Each condition says: "when this AreRoute signal arrives, render this component".
|
|
44
|
+
*/
|
|
45
|
+
const signalsContext = new AreSignalsContext({
|
|
46
|
+
'page-outlet': {
|
|
47
|
+
default: HomePage,
|
|
48
|
+
pool: [HomePage, AboutPage, SettingsPage],
|
|
49
|
+
// Route conditions are registered via @Are.Condition decorators
|
|
50
|
+
// on each page component — no explicit conditions needed here.
|
|
51
|
+
conditions: [],
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const container = new AreContainer({
|
|
56
|
+
name: 'ARE Signal Routing',
|
|
57
|
+
components: [
|
|
58
|
+
// ── Pages ────────────────────────────────────────────────
|
|
59
|
+
AppShell,
|
|
60
|
+
NavBar,
|
|
61
|
+
HomePage,
|
|
62
|
+
AboutPage,
|
|
63
|
+
SettingsPage,
|
|
64
|
+
// ── Directives ───────────────────────────────────────────
|
|
65
|
+
AreDirectiveIf,
|
|
66
|
+
AreDirectiveFor,
|
|
67
|
+
// ── Engine ───────────────────────────────────────────────
|
|
68
|
+
A_SignalBus,
|
|
69
|
+
AreRoot,
|
|
70
|
+
AreRouteWatcher,
|
|
71
|
+
ConfigReader,
|
|
72
|
+
AreHTMLEngine,
|
|
73
|
+
A_Logger,
|
|
74
|
+
],
|
|
75
|
+
entities: [
|
|
76
|
+
AreInit,
|
|
77
|
+
AreRouteSignal,
|
|
78
|
+
],
|
|
79
|
+
fragments: [
|
|
80
|
+
// Persist the current route so a hard refresh on /about still
|
|
81
|
+
// renders the correct page. Both AreInit AND AreRouteSignal
|
|
82
|
+
// must be in this structure — if either is missing, state.has()
|
|
83
|
+
// returns false and the bus silently drops the signal.
|
|
84
|
+
new A_SignalState([AreInit, AreRouteSignal]),
|
|
85
|
+
signalsContext,
|
|
86
|
+
new AreHTMLEngineContext({ container: document, }),
|
|
87
|
+
new A_Config({
|
|
88
|
+
defaults: {
|
|
89
|
+
[A_LOGGER_ENV_KEYS.LOG_LEVEL]: 'info',
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const concept = new A_Concept({
|
|
96
|
+
name: 'adaas-are-example-signal-routing',
|
|
97
|
+
fragments: [
|
|
98
|
+
new A_Config({
|
|
99
|
+
variables: ['CONFIG_VERBOSE', 'DEV_MODE'] as const,
|
|
100
|
+
defaults: { CONFIG_VERBOSE: true, DEV_MODE: true },
|
|
101
|
+
}),
|
|
102
|
+
],
|
|
103
|
+
components: [A_Logger, ConfigReader, A_Polyfill],
|
|
104
|
+
containers: [container],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await concept.load();
|
|
108
|
+
await concept.start();
|
|
109
|
+
|
|
110
|
+
} catch (error) {
|
|
111
|
+
const logger = A_Context.root.resolve<A_Logger>(A_Logger)!;
|
|
112
|
+
logger.error(error);
|
|
113
|
+
}
|
|
114
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaas/are-html",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "A-Concept Rendering Engine (ARE) is a powerful rendering engine designed to work seamlessly with the A-Concept framework. This library provides an HTML engine implementation of ARE, enabling developers to create dynamic and interactive user interfaces for web applications using standard HTML syntax.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"a-concept",
|
|
@@ -70,6 +70,8 @@
|
|
|
70
70
|
"test": "jest",
|
|
71
71
|
"example:jumpstart": "nodemon ./examples/jumpstart/concept.ts",
|
|
72
72
|
"example:dashboard": "nodemon ./examples/dashboard/concept.ts",
|
|
73
|
+
"example:signal-routing": "nodemon ./examples/signal-routing/concept.ts",
|
|
74
|
+
"example:component-styles": "nodemon ./examples/component-styles/concept.ts",
|
|
73
75
|
"example:auxta": "nodemon ./examples/auxta/concept.ts",
|
|
74
76
|
"test:test": "nodemon ./src/test/app.ts",
|
|
75
77
|
"release": " npm run build && git add . && git commit -m \"new version created :: $(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g')\" && npm version patch && npm publish --access public",
|
|
@@ -82,14 +84,14 @@
|
|
|
82
84
|
"peerDependencies": {
|
|
83
85
|
"@adaas/a-concept": "^0.3.17",
|
|
84
86
|
"@adaas/a-frame": "^0.1.2",
|
|
85
|
-
"@adaas/a-utils": "^0.3.
|
|
86
|
-
"@adaas/are": "^0.0.
|
|
87
|
+
"@adaas/a-utils": "^0.3.24",
|
|
88
|
+
"@adaas/are": "^0.0.15"
|
|
87
89
|
},
|
|
88
90
|
"devDependencies": {
|
|
89
91
|
"@adaas/a-concept": "^0.3.17",
|
|
90
92
|
"@adaas/a-frame": "^0.1.2",
|
|
91
|
-
"@adaas/a-utils": "^0.3.
|
|
92
|
-
"@adaas/are": "^0.0.
|
|
93
|
+
"@adaas/a-utils": "^0.3.24",
|
|
94
|
+
"@adaas/are": "^0.0.15",
|
|
93
95
|
"@types/chai": "^4.3.14",
|
|
94
96
|
"@types/jest": "^29.5.12",
|
|
95
97
|
"@types/mocha": "^10.0.6",
|
|
@@ -288,7 +288,18 @@ export class AreDirectiveFor extends AreDirective {
|
|
|
288
288
|
if (arg.startsWith("'") && arg.endsWith("'")) return arg.slice(1, -1);
|
|
289
289
|
if (arg.startsWith('"') && arg.endsWith('"')) return arg.slice(1, -1);
|
|
290
290
|
if (!isNaN(Number(arg))) return Number(arg);
|
|
291
|
-
|
|
291
|
+
// Dotted-path / optional-chain: e.g. `record?.embedding` or `record.data`
|
|
292
|
+
const stripped = arg.replace(/\?$/, '');
|
|
293
|
+
if (stripped.includes('.')) {
|
|
294
|
+
const parts = stripped.split('.').map(p => p.replace(/\?$/, ''));
|
|
295
|
+
let val: any = store.get(parts[0] as any);
|
|
296
|
+
for (let j = 1; j < parts.length; j++) {
|
|
297
|
+
if (val == null) return undefined;
|
|
298
|
+
val = val[parts[j]];
|
|
299
|
+
}
|
|
300
|
+
return val ?? undefined;
|
|
301
|
+
}
|
|
302
|
+
return store.get(stripped as any);
|
|
292
303
|
});
|
|
293
304
|
|
|
294
305
|
result = (fn as Function)(...resolvedArgs);
|
|
@@ -12,6 +12,8 @@ import { AreText } from "@adaas/are-html/nodes/AreText";
|
|
|
12
12
|
import { AddAttributeInstruction} from "@adaas/are-html/instructions/AddAttribute.instruction";
|
|
13
13
|
import { AddTextInstruction} from "@adaas/are-html/instructions/AddText.instruction";
|
|
14
14
|
import { AddListenerInstruction} from "@adaas/are-html/instructions/AddListener.instruction";
|
|
15
|
+
import { AddStyleInstruction } from "@adaas/are-html/instructions/AddStyle.instruction";
|
|
16
|
+
import { AreHTMLNode } from "@adaas/are-html/node";
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
|
|
@@ -22,13 +24,28 @@ import { AddListenerInstruction} from "@adaas/are-html/instructions/AddListener.
|
|
|
22
24
|
})
|
|
23
25
|
export class AreHTMLCompiler extends AreCompiler {
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Extends the base compile for all AreHTMLNode instances (elements, components, root nodes).
|
|
29
|
+
* After the standard element/attribute/children instructions are emitted, checks whether
|
|
30
|
+
* the node has a registered AreStyle and plans an AddStyleInstruction so the interpreter
|
|
31
|
+
* can inject the CSS into the document head during mount.
|
|
32
|
+
*/
|
|
33
|
+
@AreCompiler.Compile(AreHTMLNode)
|
|
34
|
+
compileHTMLNode(
|
|
35
|
+
@A_Inject(A_Caller) node: AreHTMLNode,
|
|
36
|
+
@A_Inject(AreScene) scene: AreScene,
|
|
37
|
+
@A_Inject(A_Logger) logger?: A_Logger,
|
|
38
|
+
...args: any[]
|
|
39
|
+
): void {
|
|
40
|
+
super.compile(node, scene, logger, ...args);
|
|
41
|
+
|
|
42
|
+
if (node.styles?.styles) {
|
|
43
|
+
const host = scene.host;
|
|
44
|
+
if (host) {
|
|
45
|
+
scene.plan(new AddStyleInstruction(host, { styles: node.styles.styles }));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
32
49
|
|
|
33
50
|
// -----------------------------------------------------------------------------------------
|
|
34
51
|
// -------------------------Are-Interpolation Compile Section-----------------------------------
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AreContext, AreInstruction, AreNode } from "@adaas/are";
|
|
1
|
+
import { AreContext, AreDeclaration, AreInstruction, AreNode } from "@adaas/are";
|
|
2
2
|
import { AreHTMLContextConstructor } from "./AreHTML.types";
|
|
3
3
|
import { A_Frame } from "@adaas/a-frame/core";
|
|
4
4
|
|
|
@@ -92,7 +92,10 @@ export class AreHTMLEngineContext extends AreContext {
|
|
|
92
92
|
this.index.instructionToElement.set(instruction.aseid.toString(), element);
|
|
93
93
|
this.index.elementToInstruction.set(element, instruction.aseid.toString());
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
// Only update the host-element pointer for declaration instructions.
|
|
96
|
+
// Mutations (attributes, styles, event listeners, …) produce auxiliary DOM
|
|
97
|
+
// that must never overwrite the owning node's primary element in the index.
|
|
98
|
+
if (node && instruction instanceof AreDeclaration) {
|
|
96
99
|
this.index.nodeToHostElements.set(node.aseid.toString(), element);
|
|
97
100
|
}
|
|
98
101
|
|
|
@@ -105,7 +108,6 @@ export class AreHTMLEngineContext extends AreContext {
|
|
|
105
108
|
}
|
|
106
109
|
}
|
|
107
110
|
|
|
108
|
-
|
|
109
111
|
/**
|
|
110
112
|
* Retrieves the DOM element associated with a given instruction. This method looks up the instruction's ASEID in the instructionToElement map to find the corresponding DOM element. If the instruction is not found, it returns undefined. This allows the engine to efficiently access and manipulate the DOM elements that correspond to specific instructions, enabling dynamic updates and interactions based on the application state.
|
|
111
113
|
*
|
|
@@ -134,7 +136,7 @@ export class AreHTMLEngineContext extends AreContext {
|
|
|
134
136
|
this.index.elementToInstruction.delete(element);
|
|
135
137
|
|
|
136
138
|
const node = instruction.owner;
|
|
137
|
-
if (node) {
|
|
139
|
+
if (node && instruction instanceof AreDeclaration) {
|
|
138
140
|
this.index.nodeToHostElements.delete(node.aseid.toString());
|
|
139
141
|
}
|
|
140
142
|
|