@hypen-space/core 0.4.31 → 0.4.35
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/app.d.ts +73 -2
- package/dist/app.js +112 -9
- package/dist/app.js.map +6 -5
- package/dist/components/builtin.js +112 -9
- package/dist/components/builtin.js.map +6 -5
- package/dist/context.d.ts +8 -0
- package/dist/context.js +6 -2
- package/dist/context.js.map +3 -3
- package/dist/datasource.d.ts +168 -0
- package/dist/discovery.js +114 -9
- package/dist/discovery.js.map +7 -6
- package/dist/disposable.js +6 -2
- package/dist/disposable.js.map +2 -2
- package/dist/engine.browser.d.ts +15 -0
- package/dist/engine.browser.js +19 -2
- package/dist/engine.browser.js.map +3 -3
- package/dist/engine.d.ts +22 -0
- package/dist/engine.js +37 -3
- package/dist/engine.js.map +3 -3
- package/dist/events.js +6 -2
- package/dist/events.js.map +2 -2
- package/dist/index.browser.js +295 -179
- package/dist/index.browser.js.map +9 -8
- package/dist/index.d.ts +3 -1
- package/dist/index.js +298 -179
- package/dist/index.js.map +10 -9
- package/dist/loader.js +6 -2
- package/dist/loader.js.map +2 -2
- package/dist/logger.js +6 -2
- package/dist/logger.js.map +2 -2
- package/dist/plugin.js +6 -2
- package/dist/plugin.js.map +2 -2
- package/dist/remote/client.js +6 -2
- package/dist/remote/client.js.map +2 -2
- package/dist/remote/index.js +152 -11
- package/dist/remote/index.js.map +9 -8
- package/dist/remote/server.js +152 -11
- package/dist/remote/server.js.map +9 -8
- package/dist/renderer.js +6 -2
- package/dist/renderer.js.map +2 -2
- package/dist/resolver.js +6 -2
- package/dist/resolver.js.map +2 -2
- package/dist/router.d.ts +9 -0
- package/dist/router.js +186 -18
- package/dist/router.js.map +6 -5
- package/dist/state.js +13 -6
- package/dist/state.js.map +3 -3
- package/package.json +1 -1
- package/src/app.ts +121 -4
- package/src/context.ts +10 -2
- package/src/datasource.ts +252 -0
- package/src/discovery.ts +2 -0
- package/src/engine.browser.ts +30 -0
- package/src/engine.ts +56 -1
- package/src/index.ts +16 -0
- package/src/managed-router.ts +3 -0
- package/src/remote/server.ts +11 -2
- package/src/router.ts +36 -10
- package/src/state.ts +10 -3
- package/wasm-browser/README.md +10 -10
- package/wasm-browser/hypen_engine.d.ts +368 -131
- package/wasm-browser/hypen_engine.js +896 -645
- package/wasm-browser/hypen_engine_bg.wasm +0 -0
- package/wasm-browser/hypen_engine_bg.wasm.d.ts +20 -13
- package/wasm-browser/package.json +1 -1
- package/wasm-node/README.md +10 -10
- package/wasm-node/hypen_engine.d.ts +318 -89
- package/wasm-node/hypen_engine.js +832 -613
- package/wasm-node/hypen_engine_bg.wasm +0 -0
- package/wasm-node/hypen_engine_bg.wasm.d.ts +20 -13
- package/wasm-node/package.json +1 -1
package/src/router.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { createObservableState, getStateSnapshot } from "./state.js";
|
|
7
|
+
import { disposableListener, type Disposable } from "./disposable.js";
|
|
7
8
|
import { frameworkLoggers } from "./logger.js";
|
|
8
9
|
|
|
9
10
|
const log = frameworkLoggers.router;
|
|
@@ -31,6 +32,7 @@ export class HypenRouter {
|
|
|
31
32
|
private subscribers = new Set<RouteChangeCallback>();
|
|
32
33
|
private isInitialized = false;
|
|
33
34
|
private isUpdating = false;
|
|
35
|
+
private browserListeners: Disposable[] = [];
|
|
34
36
|
|
|
35
37
|
constructor() {
|
|
36
38
|
// Create observable state for reactivity
|
|
@@ -65,18 +67,22 @@ export class HypenRouter {
|
|
|
65
67
|
this.state.query = this.parseQuery();
|
|
66
68
|
|
|
67
69
|
// Listen for browser back/forward
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
this.browserListeners.push(
|
|
71
|
+
disposableListener(window, "popstate", () => {
|
|
72
|
+
const newPath = this.getPathFromBrowser();
|
|
73
|
+
this.updatePath(newPath, false); // Don't push to history again
|
|
74
|
+
})
|
|
75
|
+
);
|
|
72
76
|
|
|
73
77
|
// Listen for hash changes
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
this.browserListeners.push(
|
|
79
|
+
disposableListener(window, "hashchange", () => {
|
|
80
|
+
// Don't respond to hashchange events we triggered ourselves
|
|
81
|
+
if (this.isUpdating) return;
|
|
82
|
+
const newPath = this.getPathFromBrowser();
|
|
83
|
+
this.updatePath(newPath, false);
|
|
84
|
+
})
|
|
85
|
+
);
|
|
80
86
|
|
|
81
87
|
this.isInitialized = true;
|
|
82
88
|
log.debug("Router initialized at:", initialPath);
|
|
@@ -333,4 +339,24 @@ export class HypenRouter {
|
|
|
333
339
|
const queryString = new URLSearchParams(query).toString();
|
|
334
340
|
return `${path}?${queryString}`;
|
|
335
341
|
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Clean up browser event listeners and subscriptions
|
|
345
|
+
*/
|
|
346
|
+
dispose(): void {
|
|
347
|
+
for (const listener of this.browserListeners) {
|
|
348
|
+
listener.dispose();
|
|
349
|
+
}
|
|
350
|
+
this.browserListeners = [];
|
|
351
|
+
this.subscribers.clear();
|
|
352
|
+
this.isInitialized = false;
|
|
353
|
+
log.debug("Router disposed");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Support `using` syntax for automatic cleanup
|
|
358
|
+
*/
|
|
359
|
+
[Symbol.dispose](): void {
|
|
360
|
+
this.dispose();
|
|
361
|
+
}
|
|
336
362
|
}
|
package/src/state.ts
CHANGED
|
@@ -279,9 +279,15 @@ export function createObservableState<T extends object>(
|
|
|
279
279
|
notificationPending = false;
|
|
280
280
|
if (batchDepth === 0) {
|
|
281
281
|
notifyChange();
|
|
282
|
+
} else {
|
|
283
|
+
// A batch started after we scheduled; the batch's __endBatch will
|
|
284
|
+
// call notifyChange() when it completes, so nothing to do here.
|
|
282
285
|
}
|
|
283
286
|
});
|
|
284
287
|
}
|
|
288
|
+
} else {
|
|
289
|
+
// Inside a batch — mark that changes occurred so __endBatch knows to notify
|
|
290
|
+
pendingChange = pendingChange || { paths: [], newValues: {} };
|
|
285
291
|
}
|
|
286
292
|
}
|
|
287
293
|
|
|
@@ -377,11 +383,12 @@ export function createObservableState<T extends object>(
|
|
|
377
383
|
},
|
|
378
384
|
|
|
379
385
|
deleteProperty(obj, prop) {
|
|
380
|
-
|
|
381
|
-
|
|
386
|
+
const existed = Object.prototype.hasOwnProperty.call(obj, prop);
|
|
387
|
+
const result = delete obj[prop];
|
|
388
|
+
if (existed) {
|
|
382
389
|
scheduleBatch();
|
|
383
390
|
}
|
|
384
|
-
return
|
|
391
|
+
return result;
|
|
385
392
|
},
|
|
386
393
|
});
|
|
387
394
|
|
package/wasm-browser/README.md
CHANGED
|
@@ -11,7 +11,7 @@ The core reactive rendering engine for Hypen, written in Rust. Compiles to WASM
|
|
|
11
11
|
### Rust
|
|
12
12
|
|
|
13
13
|
```rust
|
|
14
|
-
use hypen_engine::{Engine,
|
|
14
|
+
use hypen_engine::{Engine, ast_to_ir_node};
|
|
15
15
|
use hypen_parser::parse_component;
|
|
16
16
|
use serde_json::json;
|
|
17
17
|
|
|
@@ -21,7 +21,7 @@ engine.set_render_callback(|patches| {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
let ast = parse_component(r#"Column { Text("Hello") }"#)?;
|
|
24
|
-
engine.
|
|
24
|
+
engine.render_ir_node(&ast_to_ir_node(&ast));
|
|
25
25
|
engine.update_state(json!({ "count": 42 }));
|
|
26
26
|
```
|
|
27
27
|
|
|
@@ -120,7 +120,7 @@ use serde_json::json;
|
|
|
120
120
|
let mut engine = Engine::new();
|
|
121
121
|
|
|
122
122
|
// Register a custom component
|
|
123
|
-
// Note: In practice, you'd typically parse Hypen DSL with
|
|
123
|
+
// Note: In practice, you'd typically parse Hypen DSL with ast_to_ir_node
|
|
124
124
|
engine.register_component(Component::new("Greeting", |props: IndexMap<String, serde_json::Value>| {
|
|
125
125
|
Element::new("Text")
|
|
126
126
|
.with_prop("text", Value::Binding(
|
|
@@ -400,7 +400,7 @@ The engine integrates with the Hypen parser from `../parser`:
|
|
|
400
400
|
|
|
401
401
|
```rust
|
|
402
402
|
use hypen_parser::parse_component;
|
|
403
|
-
use hypen_engine::
|
|
403
|
+
use hypen_engine::ast_to_ir_node;
|
|
404
404
|
|
|
405
405
|
let source = r#"
|
|
406
406
|
Column {
|
|
@@ -410,14 +410,14 @@ let source = r#"
|
|
|
410
410
|
"#;
|
|
411
411
|
|
|
412
412
|
let ast = parse_component(source)?;
|
|
413
|
-
let
|
|
414
|
-
engine.
|
|
413
|
+
let ir_node = ast_to_ir_node(&ast); // Convert AST → IR
|
|
414
|
+
engine.render_ir_node(&ir_node);
|
|
415
415
|
```
|
|
416
416
|
|
|
417
417
|
### Full Example with Parser
|
|
418
418
|
|
|
419
419
|
```rust
|
|
420
|
-
use hypen_engine::{Engine,
|
|
420
|
+
use hypen_engine::{Engine, ast_to_ir_node};
|
|
421
421
|
use hypen_parser::parse_component;
|
|
422
422
|
use serde_json::json;
|
|
423
423
|
|
|
@@ -438,10 +438,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
438
438
|
"#;
|
|
439
439
|
|
|
440
440
|
let ast = parse_component(source)?;
|
|
441
|
-
let
|
|
441
|
+
let ir_node = ast_to_ir_node(&ast);
|
|
442
442
|
|
|
443
443
|
// Render
|
|
444
|
-
engine.
|
|
444
|
+
engine.render_ir_node(&ir_node);
|
|
445
445
|
|
|
446
446
|
// Update state
|
|
447
447
|
engine.update_state(json!({"count": 42}));
|
|
@@ -557,7 +557,7 @@ impl Engine {
|
|
|
557
557
|
|
|
558
558
|
```rust
|
|
559
559
|
pub use engine::Engine;
|
|
560
|
-
pub use ir::{
|
|
560
|
+
pub use ir::{ast_to_ir_node, Element, IRNode, Value};
|
|
561
561
|
pub use lifecycle::{Module, ModuleInstance};
|
|
562
562
|
pub use reconcile::Patch;
|
|
563
563
|
pub use state::StateChange;
|