kopular 0.17.2 → 0.18.0

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.
Files changed (3) hide show
  1. package/LLM.md +17 -0
  2. package/README.md +59 -0
  3. package/package.json +1 -1
package/LLM.md CHANGED
@@ -284,6 +284,23 @@ w.Bump(); // re-render + diff + patch
284
284
  components, a modal that comes and goes.
285
285
  - Hand-written `Render()` only — there's no template (`.html`) syntax yet for embedding a
286
286
  child component the way `*if`/`*for` embed structural logic.
287
+ - **Content projection (React's `children`/Angular's `<ng-content>`) needs no separate
288
+ mechanism** — pass a `() => VElement` into a child's constructor and call it from inside
289
+ its own `Render()`; it's invoked fresh every render and closes over the parent's `this`,
290
+ so projected content reflects the parent's current state on every patch:
291
+ ```ks
292
+ class Card : Component {
293
+ private () => VElement ContentBuilder;
294
+ constructor(() => VElement contentBuilder) : base() { this.ContentBuilder = contentBuilder; }
295
+ public override VElement Render() {
296
+ VElement div = VElement.Create("div");
297
+ div.AppendChild(this.ContentBuilder());
298
+ return div;
299
+ }
300
+ }
301
+ ```
302
+ More than one slot: one named `() => VElement` callback per slot (same fixed-named-slot
303
+ convention as `VElement`'s own `OnClick`/etc.), not a generic bag.
287
304
  - **`Update()` before `Mount()` is a safe no-op**, not an error. This matters for two
288
305
  sibling `Component`s (e.g. two `Router` pages) that share one injected service's
289
306
  `state<T>` and both `Subscribe()` it — every route's page is constructed eagerly (see
package/README.md CHANGED
@@ -468,6 +468,65 @@ removal to get right, so there's nothing this mechanism would add there. Reach f
468
468
  `VElement.Mount` for anything with real add/remove/reorder: a list of components, a modal
469
469
  that comes and goes, anything genuinely dynamic.
470
470
 
471
+ ## Content projection — a parent giving a child what to render
472
+
473
+ React's `children` prop and Angular's `<ng-content>` both let a parent hand a child
474
+ arbitrary markup to render at a spot the child itself decides. Kopular needs no separate
475
+ mechanism for this at all: pass a `() => VElement` into the child's constructor, the same
476
+ as any other constructor argument, and have the child call it from inside its own
477
+ `Render()`:
478
+
479
+ ```ks
480
+ class Card : Component {
481
+ private () => VElement ContentBuilder;
482
+ constructor(() => VElement contentBuilder) : base() {
483
+ this.ContentBuilder = contentBuilder;
484
+ }
485
+ public override VElement Render() {
486
+ VElement div = VElement.Create("div");
487
+ div.ClassName = "card";
488
+ div.AppendChild(this.ContentBuilder());
489
+ return div;
490
+ }
491
+ }
492
+
493
+ // Usage — the parent decides what's inside the card, Card decides the chrome around it:
494
+ Card card = new Card(() => this.BuildCardBody());
495
+ ```
496
+
497
+ Because the callback is invoked fresh on every one of `Card`'s own renders (not a value
498
+ captured once and frozen), and it's a closure over the *parent's* own `this`, the projected
499
+ content reflects the parent's current state every time — bump a field the parent's own
500
+ `BuildCardBody()` reads, call the parent's `Update()`, and `Card`'s own next patch shows the
501
+ new value, patched in place like any other content. No new API: this is just
502
+ `VElement.Mount` plus an ordinary function-typed constructor argument, the same "no hidden
503
+ magic, explicit constructor args" pattern dependency injection above already uses.
504
+
505
+ More than one projection point works the same way — one named callback per slot, the same
506
+ fixed-named-slot convention `VElement`'s own `OnClick`/`OnInput`/`OnBlur`/`OnChange` already
507
+ use rather than a generic, unordered bag:
508
+
509
+ ```ks
510
+ class Panel : Component {
511
+ private () => VElement HeaderBuilder;
512
+ private () => VElement BodyBuilder;
513
+ constructor(() => VElement headerBuilder, () => VElement bodyBuilder) : base() {
514
+ this.HeaderBuilder = headerBuilder;
515
+ this.BodyBuilder = bodyBuilder;
516
+ }
517
+ public override VElement Render() {
518
+ VElement div = VElement.Create("div");
519
+ VElement header = VElement.Create("header");
520
+ header.AppendChild(this.HeaderBuilder());
521
+ div.AppendChild(header);
522
+ VElement body = VElement.Create("section");
523
+ body.AppendChild(this.BodyBuilder());
524
+ div.AppendChild(body);
525
+ return div;
526
+ }
527
+ }
528
+ ```
529
+
471
530
  ## HTTP
472
531
 
473
532
  ```ks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kopular",
3
- "version": "0.17.2",
3
+ "version": "0.18.0",
4
4
  "description": "Kopular: a small component framework for KopScript — components, reactive state, constructor-injected services, routing, real compiled templates, and HTTP, with no DI container",
5
5
  "type": "module",
6
6
  "license": "MIT",