{
  "id": "@typed/template/many#many",
  "canonicalId": "@typed/template#many",
  "symbol": {
    "id": "@typed/template/many#many",
    "packageName": "@typed/template",
    "moduleName": "many",
    "exportName": "many",
    "kind": "function",
    "signatures": [
      "export declare function many<A, E, R, B extends PropertyKey, R2, E2>(values: Fx.Fx<ReadonlyArray<A>, E, R>, getKey: (a: A) => B, render: (value: RefSubject.RefSubject<A>, key: B) => Fx.Fx<RenderEvent, E2, R2 | Scope>): Many<A, E | E2 | Cause.IllegalArgumentError, R | R2 | Scope | RenderTemplate>;"
    ],
    "summary": "Efficiently renders a reactive list of items by using keys to minimize DOM operations and maintain component state.\n\n`many` returns a renderer descriptor rather than an `Fx`. The active renderer\nconsumes its source directly and can therefore retain keyed entries without\nflattening each child back through a generic collection stream.",
    "sections": {
      "Why": "Keys turn collection identity into a local rendering contract. The DOM\nrenderer keeps one entry map for the dynamic range: a new key starts one\nchild, a removed key closes one child Scope, a retained changed value updates\nthat child's `RefSubject`, and a pure reorder does not publish unchanged item\ndata. The same descriptor lets the HTML renderer serialize the first array in\nsource order and emit compatible hydration markers.",
      "Ownership and lifetime": "Each DOM key owns a forked child Scope. Removing the key closes that Scope;\ninterruption closes every remaining child. Both DOM and HTML rendering reject\nduplicate keys with `Cause.IllegalArgumentError`. Hydratable output also\nrejects local symbols because their identity cannot survive serialization;\nuse strings, numbers, or `Symbol.for()` keys across the server boundary.",
      "Cost model and moves": "Every source array requires O(n) key validation and ordering work; `many` does\nnot pretend an arbitrary list change is O(1). Within that pass, retained-key\nlookup is O(1) on average, unchanged values skip `RefSubject.set`, and only\nadded or removed keys allocate or close child Scopes. DOM reconciliation is\nconfined to this range and uses equal-edge, append/remove, and reverse-swap\nfast paths before an O(n) map fallback. An already-connected node is moved\nwith `ParentNode.moveBefore` when supported, preserving browser-managed state;\n`insertBefore` is the compatibility fallback. HTML setup is O(n) for the\ninitial array and performs no live DOM reconciliation."
    },
    "examples": [
      {
        "language": "ts",
        "code": "import { Effect, Layer } from \"effect\"\nimport { Fx, RefSubject } from \"@typed/fx\"\nimport { html, many } from \"@typed/template\"\nimport { DomRenderTemplate, render } from \"@typed/template/Render\"\n\ninterface Todo {\n  readonly id: string\n  readonly text: string\n  readonly completed: boolean\n}\n\nconst program = Effect.gen(function* () {\n  const todos = yield* RefSubject.make<Todo[]>([\n    { id: \"1\", text: \"Learn Effect\", completed: false },\n    { id: \"2\", text: \"Build app\", completed: false }\n  ])\n\n  const todoList = many(\n    todos,\n    (todo) => todo.id, // Key function\n    (todoRef, key) => // Render function receives RefSubject\n      html`<li>\n        ${RefSubject.map(todoRef, (todo) => todo.text)}\n        <button onclick=${RefSubject.update(todoRef, (todo) =>\n          ({ ...todo, completed: !todo.completed })\n        )}>Toggle</button>\n      </li>`\n  )\n\n  const template = html`<ul>${todoList}</ul>`\n\n  return yield* render(template, document.body).pipe(\n    Fx.drainLayer,\n    Layer.provide(DomRenderTemplate),\n    Layer.launch\n  )\n})"
      }
    ],
    "relations": [
      {
        "kind": "glossary",
        "target": "dynamic-range"
      }
    ],
    "source": {
      "file": "packages/template/src/many.ts",
      "line": 138
    },
    "since": "1.0.0",
    "category": "Keyed collection rendering"
  },
  "exposure": {
    "recordKind": "declaration",
    "id": "@typed/template/many#many",
    "packageName": "@typed/template",
    "packageVersion": "1.0.0-beta.7",
    "moduleName": "many",
    "consumerSpecifier": "@typed/template/many",
    "exportName": "many",
    "qualifiedName": "many",
    "declarationKey": "declaration:5b8e2a46e3b8e39ff320cfbb",
    "family": "function",
    "signatures": [
      "export declare function many<A, E, R, B extends PropertyKey, R2, E2>(values: Fx.Fx<ReadonlyArray<A>, E, R>, getKey: (a: A) => B, render: (value: RefSubject.RefSubject<A>, key: B) => Fx.Fx<RenderEvent, E2, R2 | Scope>): Many<A, E | E2 | Cause.IllegalArgumentError, R | R2 | Scope | RenderTemplate>;"
    ],
    "sourceSpans": [
      {
        "file": "packages/template/src/many.ts",
        "start": {
          "line": 138,
          "column": 1
        },
        "end": {
          "line": 149,
          "column": 2
        }
      }
    ],
    "aliases": [
      "@typed/template#many"
    ],
    "isAlias": false,
    "static": false
  },
  "declaration": {
    "declarationKey": "declaration:5b8e2a46e3b8e39ff320cfbb",
    "name": "many",
    "family": "function",
    "facets": [
      {
        "family": "function",
        "syntaxKind": "FunctionDeclaration",
        "signatures": [
          "export declare function many<A, E, R, B extends PropertyKey, R2, E2>(values: Fx.Fx<ReadonlyArray<A>, E, R>, getKey: (a: A) => B, render: (value: RefSubject.RefSubject<A>, key: B) => Fx.Fx<RenderEvent, E2, R2 | Scope>): Many<A, E | E2 | Cause.IllegalArgumentError, R | R2 | Scope | RenderTemplate>;"
        ],
        "typeParameters": [
          "A",
          "E",
          "R",
          "B extends PropertyKey",
          "R2",
          "E2"
        ],
        "sourceSpans": [
          {
            "file": "packages/template/src/many.ts",
            "start": {
              "line": 138,
              "column": 1
            },
            "end": {
              "line": 149,
              "column": 2
            }
          }
        ],
        "static": false,
        "readonly": false,
        "optional": false
      }
    ],
    "signatures": [
      "export declare function many<A, E, R, B extends PropertyKey, R2, E2>(values: Fx.Fx<ReadonlyArray<A>, E, R>, getKey: (a: A) => B, render: (value: RefSubject.RefSubject<A>, key: B) => Fx.Fx<RenderEvent, E2, R2 | Scope>): Many<A, E | E2 | Cause.IllegalArgumentError, R | R2 | Scope | RenderTemplate>;"
    ],
    "typeParameters": [
      "A",
      "E",
      "R",
      "B extends PropertyKey",
      "R2",
      "E2"
    ],
    "summary": "Efficiently renders a reactive list of items by using keys to minimize DOM operations and maintain component state.\n\n`many` returns a renderer descriptor rather than an `Fx`. The active renderer\nconsumes its source directly and can therefore retain keyed entries without\nflattening each child back through a generic collection stream.",
    "sections": {
      "Why": "Keys turn collection identity into a local rendering contract. The DOM\nrenderer keeps one entry map for the dynamic range: a new key starts one\nchild, a removed key closes one child Scope, a retained changed value updates\nthat child's `RefSubject`, and a pure reorder does not publish unchanged item\ndata. The same descriptor lets the HTML renderer serialize the first array in\nsource order and emit compatible hydration markers.",
      "Ownership and lifetime": "Each DOM key owns a forked child Scope. Removing the key closes that Scope;\ninterruption closes every remaining child. Both DOM and HTML rendering reject\nduplicate keys with `Cause.IllegalArgumentError`. Hydratable output also\nrejects local symbols because their identity cannot survive serialization;\nuse strings, numbers, or `Symbol.for()` keys across the server boundary.",
      "Cost model and moves": "Every source array requires O(n) key validation and ordering work; `many` does\nnot pretend an arbitrary list change is O(1). Within that pass, retained-key\nlookup is O(1) on average, unchanged values skip `RefSubject.set`, and only\nadded or removed keys allocate or close child Scopes. DOM reconciliation is\nconfined to this range and uses equal-edge, append/remove, and reverse-swap\nfast paths before an O(n) map fallback. An already-connected node is moved\nwith `ParentNode.moveBefore` when supported, preserving browser-managed state;\n`insertBefore` is the compatibility fallback. HTML setup is O(n) for the\ninitial array and performs no live DOM reconciliation."
    },
    "examples": [
      {
        "language": "ts",
        "code": "import { Effect, Layer } from \"effect\"\nimport { Fx, RefSubject } from \"@typed/fx\"\nimport { html, many } from \"@typed/template\"\nimport { DomRenderTemplate, render } from \"@typed/template/Render\"\n\ninterface Todo {\n  readonly id: string\n  readonly text: string\n  readonly completed: boolean\n}\n\nconst program = Effect.gen(function* () {\n  const todos = yield* RefSubject.make<Todo[]>([\n    { id: \"1\", text: \"Learn Effect\", completed: false },\n    { id: \"2\", text: \"Build app\", completed: false }\n  ])\n\n  const todoList = many(\n    todos,\n    (todo) => todo.id, // Key function\n    (todoRef, key) => // Render function receives RefSubject\n      html`<li>\n        ${RefSubject.map(todoRef, (todo) => todo.text)}\n        <button onclick=${RefSubject.update(todoRef, (todo) =>\n          ({ ...todo, completed: !todo.completed })\n        )}>Toggle</button>\n      </li>`\n  )\n\n  const template = html`<ul>${todoList}</ul>`\n\n  return yield* render(template, document.body).pipe(\n    Fx.drainLayer,\n    Layer.provide(DomRenderTemplate),\n    Layer.launch\n  )\n})"
      }
    ],
    "sourceSpans": [
      {
        "file": "packages/template/src/many.ts",
        "start": {
          "line": 138,
          "column": 1
        },
        "end": {
          "line": 149,
          "column": 2
        }
      }
    ],
    "since": "1.0.0",
    "category": "Keyed collection rendering"
  }
}
