[{"data":1,"prerenderedAt":1357},["ShallowReactive",2],{"navigation_docs":3,"-guide-components":223,"-guide-components-surround":1352},[4,26,96,105,202],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":25},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F1.installation","i-lucide-download",{"title":16,"path":17,"stem":18,"icon":19},"The first app","\u002Fgetting-started\u002Ffirst-app","1.getting-started\u002F2.first-app","i-lucide-play",{"title":21,"path":22,"stem":23,"icon":24},"The first test","\u002Fgetting-started\u002Ffirst-test","1.getting-started\u002F3.first-test","i-lucide-flask-conical",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[32,37,42,47,52,57,62,67,72,77,81,86,91],{"title":33,"path":34,"stem":35,"icon":36},"Components","\u002Fguide\u002Fcomponents","2.guide\u002F01.components","i-lucide-component",{"title":38,"path":39,"stem":40,"icon":41},"Inputs and forms","\u002Fguide\u002Finputs-and-forms","2.guide\u002F02.inputs-and-forms","i-lucide-text-cursor-input",{"title":43,"path":44,"stem":45,"icon":46},"Scrolling and viewports","\u002Fguide\u002Fscrolling","2.guide\u002F03.scrolling","i-lucide-scroll-text",{"title":48,"path":49,"stem":50,"icon":51},"Overlays and layers","\u002Fguide\u002Foverlays","2.guide\u002F04.overlays","i-lucide-layers",{"title":53,"path":54,"stem":55,"icon":56},"Styles and theme","\u002Fguide\u002Fstyles","2.guide\u002F05.styles","i-lucide-palette",{"title":58,"path":59,"stem":60,"icon":61},"Composables","\u002Fguide\u002Fcomposables","2.guide\u002F06.composables","i-lucide-puzzle",{"title":63,"path":64,"stem":65,"icon":66},"Widgets","\u002Fguide\u002Fwidgets","2.guide\u002F07.widgets","i-lucide-blocks",{"title":68,"path":69,"stem":70,"icon":71},"The assistant","\u002Fguide\u002Fassistant","2.guide\u002F08.assistant","i-lucide-message-square",{"title":73,"path":74,"stem":75,"icon":76},"The same app on the web","\u002Fguide\u002Fweb","2.guide\u002F09.web","i-lucide-globe",{"title":78,"path":79,"stem":80,"icon":24},"Testing","\u002Fguide\u002Ftesting","2.guide\u002F10.testing",{"title":82,"path":83,"stem":84,"icon":85},"Running and packaging","\u002Fguide\u002Fpackaging","2.guide\u002F11.packaging","i-lucide-package",{"title":87,"path":88,"stem":89,"icon":90},"The terminal contract","\u002Fguide\u002Fterminal","2.guide\u002F12.terminal","i-lucide-square-terminal",{"title":92,"path":93,"stem":94,"icon":95},"Benchmarks","\u002Fguide\u002Fbenchmarks","2.guide\u002F13.benchmarks","i-lucide-gauge",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":25},"AI and agents","i-lucide-bot","\u002Fai","3.ai",[102],{"title":97,"path":103,"stem":104,"icon":98},"\u002Fai\u002Fagents","3.ai\u002F1.agents",{"title":106,"icon":107,"path":108,"stem":109,"children":110},"Decisions","i-lucide-scale","\u002Fdecisions","4.decisions",[111,114,118,122,126,130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,194,198],{"title":112,"path":108,"stem":113,"icon":46},"All decisions","4.decisions\u002Findex",{"title":115,"path":116,"stem":117},"0001. kyo-ui is the DSL","\u002Fdecisions\u002F0001-kyo-ui-is-the-dsl","4.decisions\u002F0001-kyo-ui-is-the-dsl",{"title":119,"path":120,"stem":121},"0002. jatatui renders the cells","\u002Fdecisions\u002F0002-jatatui-renders-the-cells","4.decisions\u002F0002-jatatui-renders-the-cells",{"title":123,"path":124,"stem":125},"0003. Pin Kyo 1.0.0-RC7 and JDK 25","\u002Fdecisions\u002F0003-pin-kyo-rc7-and-jdk-25","4.decisions\u002F0003-pin-kyo-rc7-and-jdk-25",{"title":127,"path":128,"stem":129},"0004. Public Kyo APIs only","\u002Fdecisions\u002F0004-public-kyo-apis-only","4.decisions\u002F0004-public-kyo-apis-only",{"title":131,"path":132,"stem":133},"0005. A SOFT frame contract and an own watcher loop","\u002Fdecisions\u002F0005-soft-frame-contract-and-own-watcher-loop","4.decisions\u002F0005-soft-frame-contract-and-own-watcher-loop",{"title":135,"path":136,"stem":137},"0006. Purity: edge files, lint and a pure painter","\u002Fdecisions\u002F0006-purity-edge-files-and-lint","4.decisions\u002F0006-purity-edge-files-and-lint",{"title":139,"path":140,"stem":141},"0007. Compiler flags from sbt-tpolecat","\u002Fdecisions\u002F0007-compiler-flags-from-sbt-tpolecat","4.decisions\u002F0007-compiler-flags-from-sbt-tpolecat",{"title":143,"path":144,"stem":145},"0008. The artifact split: runner, app, testkit and core","\u002Fdecisions\u002F0008-artifact-split-runner-app-testkit-core","4.decisions\u002F0008-artifact-split-runner-app-testkit-core",{"title":147,"path":148,"stem":149},"0009. tui4s-use and tui4s-widgets, cross-built","\u002Fdecisions\u002F0009-use-and-widgets-cross-built","4.decisions\u002F0009-use-and-widgets-cross-built",{"title":151,"path":152,"stem":153},"0010. The flagship assistant is the blueprint of a real app","\u002Fdecisions\u002F0010-the-flagship-assistant-as-blueprint","4.decisions\u002F0010-the-flagship-assistant-as-blueprint",{"title":155,"path":156,"stem":157},"0011. The web target: a standalone Scala.js app and one theme","\u002Fdecisions\u002F0011-web-target-standalone-scalajs-and-one-theme","4.decisions\u002F0011-web-target-standalone-scalajs-and-one-theme",{"title":159,"path":160,"stem":161},"0012. The documentation is example-first","\u002Fdecisions\u002F0012-documentation-is-example-first","4.decisions\u002F0012-documentation-is-example-first",{"title":163,"path":164,"stem":165},"0013. Benchmarks in the repository, with their own build","\u002Fdecisions\u002F0013-benchmarks-in-repo-with-own-build","4.decisions\u002F0013-benchmarks-in-repo-with-own-build",{"title":167,"path":168,"stem":169},"0014. Release per module, by tag, as 0.1.0-RC1","\u002Fdecisions\u002F0014-release-per-module-tags-and-rc1","4.decisions\u002F0014-release-per-module-tags-and-rc1",{"title":171,"path":172,"stem":173},"0015. Packaging: the AOT cache in the start scripts, native-image as an option","\u002Fdecisions\u002F0015-packaging-aot-cache-and-native-image","4.decisions\u002F0015-packaging-aot-cache-and-native-image",{"title":175,"path":176,"stem":177},"0016. Process: lean mode and agent roles","\u002Fdecisions\u002F0016-process-lean-mode-and-agent-roles","4.decisions\u002F0016-process-lean-mode-and-agent-roles",{"title":179,"path":180,"stem":181},"0017. Deferred: templates, mouse, the kitty keyboard protocol and Windows","\u002Fdecisions\u002F0017-deferred-templates-mouse-and-kitty","4.decisions\u002F0017-deferred-templates-mouse-and-kitty",{"title":183,"path":184,"stem":185},"0018. pini4s is a vendored Git submodule","\u002Fdecisions\u002F0018-pini4s-as-a-vendored-submodule","4.decisions\u002F0018-pini4s-as-a-vendored-submodule",{"title":187,"path":188,"stem":189},"0019. Upstream issues are drafts that the user posts","\u002Fdecisions\u002F0019-upstream-kyo-issues-as-drafts","4.decisions\u002F0019-upstream-kyo-issues-as-drafts",{"title":191,"path":192,"stem":193},"0020. Release from the Actions form","\u002Fdecisions\u002F0020-release-from-the-actions-form","4.decisions\u002F0020-release-from-the-actions-form",{"title":195,"path":196,"stem":197},"0021. The rulebook is CONTRIBUTING.md","\u002Fdecisions\u002F0021-the-rulebook-is-contributing-md","4.decisions\u002F0021-the-rulebook-is-contributing-md",{"title":199,"path":200,"stem":201},"0022. The logo is text","\u002Fdecisions\u002F0022-the-logo-is-text","4.decisions\u002F0022-the-logo-is-text",{"title":203,"icon":204,"path":205,"stem":206,"children":207,"page":25},"Project","i-lucide-compass","\u002Fproject","5.project",[208,213,218],{"title":209,"path":210,"stem":211,"icon":212},"Roadmap","\u002Fproject\u002Froadmap","5.project\u002F1.roadmap","i-lucide-map",{"title":214,"path":215,"stem":216,"icon":217},"Contributing","\u002Fproject\u002Fcontributing","5.project\u002F2.contributing","i-lucide-git-pull-request",{"title":219,"path":220,"stem":221,"icon":222},"Security","\u002Fproject\u002Fsecurity","5.project\u002F3.security","i-lucide-shield",{"id":224,"title":33,"body":225,"description":1345,"extension":1346,"links":1347,"meta":1348,"navigation":1349,"path":34,"seo":1350,"stem":35,"__hash__":1351},"docs\u002F2.guide\u002F01.components.md",{"type":226,"value":227,"toc":1340},"minimark",[228,232,451,469,483,721,728,1055,1059,1074,1153,1182,1188,1192,1216,1220,1310,1316,1323,1329,1336],[229,230,231],"p",{},"A hook component is a function that allocates its state:",[233,234,240],"pre",{"className":235,"code":236,"filename":237,"language":238,"meta":239,"style":239},"language-scala shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","    def counter(label: String): UI \u003C Sync =\n      for count \u003C- Signal.initRef(0)\n      yield div.style(_.border(1.px, CounterStyles.frame).padding(0.px, 1.px))(\n        span(label).style(_.bold.color(CounterStyles.label)),\n        span(\"Count: \", count.map(_.toString))\n          .style(_.color(CounterStyles.count)),\n        div.style(_.row.gap(1.px))(\n          button(\"+\").onClick(count.updateAndGet(_ + 1)),\n          button(\"-\").onClick(count.updateAndGet(_ - 1)),\n        ),\n      )\n","CounterStyles.scala","scala","",[241,242,243,289,315,345,356,374,385,395,419,439,445],"code",{"__ignoreMap":239},[244,245,248,252,256,260,264,267,271,274,277,280,283,286],"span",{"class":246,"line":247},"line",1,[244,249,251],{"class":250},"sMK4o","    def",[244,253,255],{"class":254},"s2Zo4"," counter",[244,257,259],{"class":258},"sTEyZ","(",[244,261,263],{"class":262},"sHdIc","label",[244,265,266],{"class":258},": ",[244,268,270],{"class":269},"sBMFI","String",[244,272,273],{"class":258},")",[244,275,276],{"class":250},":",[244,278,279],{"class":269}," UI",[244,281,282],{"class":250}," \u003C",[244,284,285],{"class":269}," Sync",[244,287,288],{"class":250}," =\n",[244,290,292,296,299,302,305,308,312],{"class":246,"line":291},2,[244,293,295],{"class":294},"s7zQu","      for",[244,297,298],{"class":258}," count ",[244,300,301],{"class":250},"\u003C-",[244,303,304],{"class":269}," Signal",[244,306,307],{"class":258},".initRef(",[244,309,311],{"class":310},"sbssI","0",[244,313,314],{"class":258},")\n",[244,316,318,321,324,327,330,333,336,338,340,342],{"class":246,"line":317},3,[244,319,320],{"class":294},"      yield",[244,322,323],{"class":258}," div.style(_.border(",[244,325,326],{"class":310},"1",[244,328,329],{"class":258},".px, ",[244,331,332],{"class":269},"CounterStyles",[244,334,335],{"class":258},".frame).padding(",[244,337,311],{"class":310},[244,339,329],{"class":258},[244,341,326],{"class":310},[244,343,344],{"class":258},".px))(\n",[244,346,348,351,353],{"class":246,"line":347},4,[244,349,350],{"class":258},"        span(label).style(_.bold.color(",[244,352,332],{"class":269},[244,354,355],{"class":258},".label)),\n",[244,357,359,362,365,369,371],{"class":246,"line":358},5,[244,360,361],{"class":258},"        span(",[244,363,364],{"class":250},"\"",[244,366,368],{"class":367},"sfazB","Count: ",[244,370,364],{"class":250},[244,372,373],{"class":258},", count.map(_.toString))\n",[244,375,377,380,382],{"class":246,"line":376},6,[244,378,379],{"class":258},"          .style(_.color(",[244,381,332],{"class":269},[244,383,384],{"class":258},".count)),\n",[244,386,388,391,393],{"class":246,"line":387},7,[244,389,390],{"class":258},"        div.style(_.row.gap(",[244,392,326],{"class":310},[244,394,344],{"class":258},[244,396,398,401,403,406,408,411,413,416],{"class":246,"line":397},8,[244,399,400],{"class":258},"          button(",[244,402,364],{"class":250},[244,404,405],{"class":367},"+",[244,407,364],{"class":250},[244,409,410],{"class":258},").onClick(count.updateAndGet(_ ",[244,412,405],{"class":250},[244,414,415],{"class":310}," 1",[244,417,418],{"class":258},")),\n",[244,420,422,424,426,429,431,433,435,437],{"class":246,"line":421},9,[244,423,400],{"class":258},[244,425,364],{"class":250},[244,427,428],{"class":367},"-",[244,430,364],{"class":250},[244,432,410],{"class":258},[244,434,428],{"class":250},[244,436,415],{"class":310},[244,438,418],{"class":258},[244,440,442],{"class":246,"line":441},10,[244,443,444],{"class":258},"        ),\n",[244,446,448],{"class":246,"line":447},11,[244,449,450],{"class":258},"      )\n",[229,452,453,456,457,460,461,464,465,468],{},[241,454,455],{},"initSig(0)"," (",[241,458,459],{},"import tui4s.initSig",") is the short name of ",[241,462,463],{},"Signal.initRef(0)",", akin to Vue's ",[241,466,467],{},"ref(0)",". The Counter of the quick start uses it.",[229,470,471,472,475,476,479,480,276],{},"A class component has a ",[241,473,474],{},"State"," type, an ",[241,477,478],{},"initial"," value and a pure ",[241,481,482],{},"view",[233,484,486],{"className":235,"code":485,"filename":237,"language":238,"meta":239,"style":239},"\u002F** Style 2: a component class with a type member for its state. The runner\n  * allocates the state at mount.\n  *\u002F\nfinal class CounterBox(label: String) extends Component:\n    type State = Int\n    def initial: Int                    = 0\n    \u002F\u002F claude 2026-10-19: changed: the colours of the stylesheet (L1b)\n    def view(count: SignalRef[Int]): UI =\n      div.style(_.border(1.px, CounterStyles.frame).padding(0.px, 1.px))(\n        span(label).style(_.bold.color(CounterStyles.label)),\n        span(\"Count: \", count.map(_.toString))\n          .style(_.color(CounterStyles.count)),\n        div.style(_.row.gap(1.px))(\n          button(\"+\").onClick(count.updateAndGet(_ + 1)),\n          button(\"-\").onClick(count.updateAndGet(_ - 1)),\n        ),\n      )\nend CounterBox\n",[241,487,488,494,499,504,536,550,568,573,605,626,634,646,655,664,683,702,707,712],{"__ignoreMap":239},[244,489,490],{"class":246,"line":247},[244,491,493],{"class":492},"sHwdD","\u002F** Style 2: a component class with a type member for its state. The runner\n",[244,495,496],{"class":246,"line":291},[244,497,498],{"class":492},"  * allocates the state at mount.\n",[244,500,501],{"class":246,"line":317},[244,502,503],{"class":492},"  *\u002F\n",[244,505,506,510,513,516,518,520,522,524,527,530,533],{"class":246,"line":347},[244,507,509],{"class":508},"spNyl","final",[244,511,512],{"class":250}," class",[244,514,515],{"class":269}," CounterBox",[244,517,259],{"class":258},[244,519,263],{"class":262},[244,521,266],{"class":258},[244,523,270],{"class":269},[244,525,526],{"class":258},") ",[244,528,529],{"class":250},"extends",[244,531,532],{"class":269}," Component",[244,534,535],{"class":250},":\n",[244,537,538,541,544,547],{"class":246,"line":358},[244,539,540],{"class":250},"    type",[244,542,543],{"class":269}," State",[244,545,546],{"class":250}," =",[244,548,549],{"class":269}," Int\n",[244,551,552,554,557,559,562,565],{"class":246,"line":376},[244,553,251],{"class":250},[244,555,556],{"class":254}," initial",[244,558,276],{"class":250},[244,560,561],{"class":269}," Int",[244,563,564],{"class":250},"                    =",[244,566,567],{"class":310}," 0\n",[244,569,570],{"class":246,"line":387},[244,571,572],{"class":492},"    \u002F\u002F claude 2026-10-19: changed: the colours of the stylesheet (L1b)\n",[244,574,575,577,580,582,585,587,590,593,596,599,601,603],{"class":246,"line":397},[244,576,251],{"class":250},[244,578,579],{"class":254}," view",[244,581,259],{"class":258},[244,583,584],{"class":262},"count",[244,586,266],{"class":258},[244,588,589],{"class":269},"SignalRef",[244,591,592],{"class":258},"[",[244,594,595],{"class":269},"Int",[244,597,598],{"class":258},"])",[244,600,276],{"class":250},[244,602,279],{"class":269},[244,604,288],{"class":250},[244,606,607,610,612,614,616,618,620,622,624],{"class":246,"line":421},[244,608,609],{"class":258},"      div.style(_.border(",[244,611,326],{"class":310},[244,613,329],{"class":258},[244,615,332],{"class":269},[244,617,335],{"class":258},[244,619,311],{"class":310},[244,621,329],{"class":258},[244,623,326],{"class":310},[244,625,344],{"class":258},[244,627,628,630,632],{"class":246,"line":441},[244,629,350],{"class":258},[244,631,332],{"class":269},[244,633,355],{"class":258},[244,635,636,638,640,642,644],{"class":246,"line":447},[244,637,361],{"class":258},[244,639,364],{"class":250},[244,641,368],{"class":367},[244,643,364],{"class":250},[244,645,373],{"class":258},[244,647,649,651,653],{"class":246,"line":648},12,[244,650,379],{"class":258},[244,652,332],{"class":269},[244,654,384],{"class":258},[244,656,658,660,662],{"class":246,"line":657},13,[244,659,390],{"class":258},[244,661,326],{"class":310},[244,663,344],{"class":258},[244,665,667,669,671,673,675,677,679,681],{"class":246,"line":666},14,[244,668,400],{"class":258},[244,670,364],{"class":250},[244,672,405],{"class":367},[244,674,364],{"class":250},[244,676,410],{"class":258},[244,678,405],{"class":250},[244,680,415],{"class":310},[244,682,418],{"class":258},[244,684,686,688,690,692,694,696,698,700],{"class":246,"line":685},15,[244,687,400],{"class":258},[244,689,364],{"class":250},[244,691,428],{"class":367},[244,693,364],{"class":250},[244,695,410],{"class":258},[244,697,428],{"class":250},[244,699,415],{"class":310},[244,701,418],{"class":258},[244,703,705],{"class":246,"line":704},16,[244,706,444],{"class":258},[244,708,710],{"class":246,"line":709},17,[244,711,450],{"class":258},[244,713,715,718],{"class":246,"line":714},18,[244,716,717],{"class":250},"end",[244,719,720],{"class":269}," CounterBox\n",[229,722,723,724,727],{},"The app puts both styles in one tree. ",[241,725,726],{},"component(...)"," is a node that the runner mounts:",[233,729,731],{"className":235,"code":730,"filename":237,"language":238,"meta":239,"style":239},"    def ui: UI \u003C Sync =\n      for shown \u003C- Signal.initRef(true)\n      yield div.onKeyDown {\n        case KeyboardEvent(Keyboard.Char('h'), _, _) => shown.updateAndGet(!_)\n        case KeyboardEvent(Keyboard.Char('q'), _, _) => Tui.quit\n        case _                                       => ()\n      }(\n        h1(\"Counter styles: h hides the hook counters, q quits\"),\n        div.style(_.row.gap(4.px))(\n          div(\n            h2(\"Hooks\"),\n            when(shown)(\n              div.style(_.row.gap(2.px))(\n                component(CounterHooks.counter(\"Left\")),\n                component(CounterHooks.counter(\"Right\")),\n              ),\n            ),\n          ),\n          div(\n            h2(\"Components\"),\n            div.style(_.row.gap(2.px))(CounterBox(\"Left\"), CounterBox(\"Right\")),\n          ),\n        ),\n      )\n",[241,732,733,750,768,778,822,855,867,875,890,899,904,918,923,933,953,970,975,980,985,990,1003,1040,1045,1050],{"__ignoreMap":239},[244,734,735,737,740,742,744,746,748],{"class":246,"line":247},[244,736,251],{"class":250},[244,738,739],{"class":254}," ui",[244,741,276],{"class":250},[244,743,279],{"class":269},[244,745,282],{"class":250},[244,747,285],{"class":269},[244,749,288],{"class":250},[244,751,752,754,757,759,761,763,766],{"class":246,"line":291},[244,753,295],{"class":294},[244,755,756],{"class":258}," shown ",[244,758,301],{"class":250},[244,760,304],{"class":269},[244,762,307],{"class":258},[244,764,765],{"class":250},"true",[244,767,314],{"class":258},[244,769,770,772,775],{"class":246,"line":317},[244,771,320],{"class":294},[244,773,774],{"class":258}," div.onKeyDown ",[244,776,777],{"class":250},"{\n",[244,779,780,783,786,788,791,794,797,799,802,805,807,810,813,816,819],{"class":246,"line":347},[244,781,782],{"class":294},"        case",[244,784,785],{"class":269}," KeyboardEvent",[244,787,259],{"class":258},[244,789,790],{"class":269},"Keyboard",[244,792,793],{"class":258},".",[244,795,796],{"class":269},"Char",[244,798,259],{"class":258},[244,800,801],{"class":250},"'",[244,803,804],{"class":367},"h",[244,806,801],{"class":250},[244,808,809],{"class":258},"), _, _) ",[244,811,812],{"class":250},"=>",[244,814,815],{"class":258}," shown.updateAndGet(",[244,817,818],{"class":250},"!",[244,820,821],{"class":258},"_)\n",[244,823,824,826,828,830,832,834,836,838,840,843,845,847,849,852],{"class":246,"line":358},[244,825,782],{"class":294},[244,827,785],{"class":269},[244,829,259],{"class":258},[244,831,790],{"class":269},[244,833,793],{"class":258},[244,835,796],{"class":269},[244,837,259],{"class":258},[244,839,801],{"class":250},[244,841,842],{"class":367},"q",[244,844,801],{"class":250},[244,846,809],{"class":258},[244,848,812],{"class":250},[244,850,851],{"class":269}," Tui",[244,853,854],{"class":258},".quit\n",[244,856,857,859,862,864],{"class":246,"line":376},[244,858,782],{"class":294},[244,860,861],{"class":258}," _                                       ",[244,863,812],{"class":250},[244,865,866],{"class":258}," ()\n",[244,868,869,872],{"class":246,"line":387},[244,870,871],{"class":250},"      }",[244,873,874],{"class":258},"(\n",[244,876,877,880,882,885,887],{"class":246,"line":397},[244,878,879],{"class":258},"        h1(",[244,881,364],{"class":250},[244,883,884],{"class":367},"Counter styles: h hides the hook counters, q quits",[244,886,364],{"class":250},[244,888,889],{"class":258},"),\n",[244,891,892,894,897],{"class":246,"line":421},[244,893,390],{"class":258},[244,895,896],{"class":310},"4",[244,898,344],{"class":258},[244,900,901],{"class":246,"line":441},[244,902,903],{"class":258},"          div(\n",[244,905,906,909,911,914,916],{"class":246,"line":447},[244,907,908],{"class":258},"            h2(",[244,910,364],{"class":250},[244,912,913],{"class":367},"Hooks",[244,915,364],{"class":250},[244,917,889],{"class":258},[244,919,920],{"class":246,"line":648},[244,921,922],{"class":258},"            when(shown)(\n",[244,924,925,928,931],{"class":246,"line":657},[244,926,927],{"class":258},"              div.style(_.row.gap(",[244,929,930],{"class":310},"2",[244,932,344],{"class":258},[244,934,935,938,941,944,946,949,951],{"class":246,"line":666},[244,936,937],{"class":258},"                component(",[244,939,940],{"class":269},"CounterHooks",[244,942,943],{"class":258},".counter(",[244,945,364],{"class":250},[244,947,948],{"class":367},"Left",[244,950,364],{"class":250},[244,952,418],{"class":258},[244,954,955,957,959,961,963,966,968],{"class":246,"line":685},[244,956,937],{"class":258},[244,958,940],{"class":269},[244,960,943],{"class":258},[244,962,364],{"class":250},[244,964,965],{"class":367},"Right",[244,967,364],{"class":250},[244,969,418],{"class":258},[244,971,972],{"class":246,"line":704},[244,973,974],{"class":258},"              ),\n",[244,976,977],{"class":246,"line":709},[244,978,979],{"class":258},"            ),\n",[244,981,982],{"class":246,"line":714},[244,983,984],{"class":258},"          ),\n",[244,986,988],{"class":246,"line":987},19,[244,989,903],{"class":258},[244,991,993,995,997,999,1001],{"class":246,"line":992},20,[244,994,908],{"class":258},[244,996,364],{"class":250},[244,998,33],{"class":367},[244,1000,364],{"class":250},[244,1002,889],{"class":258},[244,1004,1006,1009,1011,1014,1017,1019,1021,1023,1025,1028,1030,1032,1034,1036,1038],{"class":246,"line":1005},21,[244,1007,1008],{"class":258},"            div.style(_.row.gap(",[244,1010,930],{"class":310},[244,1012,1013],{"class":258},".px))(",[244,1015,1016],{"class":269},"CounterBox",[244,1018,259],{"class":258},[244,1020,364],{"class":250},[244,1022,948],{"class":367},[244,1024,364],{"class":250},[244,1026,1027],{"class":258},"), ",[244,1029,1016],{"class":269},[244,1031,259],{"class":258},[244,1033,364],{"class":250},[244,1035,965],{"class":367},[244,1037,364],{"class":250},[244,1039,418],{"class":258},[244,1041,1043],{"class":246,"line":1042},22,[244,1044,984],{"class":258},[244,1046,1048],{"class":246,"line":1047},23,[244,1049,444],{"class":258},[244,1051,1053],{"class":246,"line":1052},24,[244,1054,450],{"class":258},[1056,1057,913],"h2",{"id":1058},"hooks",[229,1060,1061,1062,1065,1066,1069,1070,1073],{},"A hook component returns ",[241,1063,1064],{},"UI \u003C Sync",". It returns ",[241,1067,1068],{},"UI \u003C (Sync & Scope)"," when it uses a hook that starts a fiber, and ",[241,1071,1072],{},"UI \u003C (Async & Scope)"," when its body waits.",[1075,1076,1077,1090],"table",{},[1078,1079,1080],"thead",{},[1081,1082,1083,1087],"tr",{},[1084,1085,1086],"th",{},"Hook",[1084,1088,1089],{},"What it gives",[1091,1092,1093,1106,1116,1126,1140],"tbody",{},[1081,1094,1095,1101],{},[1096,1097,1098],"td",{},[241,1099,1100],{},"Signal.initRef(initial)",[1096,1102,1103,1104,793],{},"A piece of state: a Kyo ",[241,1105,589],{},[1081,1107,1108,1113],{},[1096,1109,1110],{},[241,1111,1112],{},"useHold(initial)(stream)",[1096,1114,1115],{},"The last value of a stream, as a signal.",[1081,1117,1118,1123],{},[1096,1119,1120],{},[241,1121,1122],{},"useFold(initial)(stream)(f)",[1096,1124,1125],{},"A stream folded into a signal.",[1081,1127,1128,1133],{},[1096,1129,1130],{},[241,1131,1132],{},"useEffect(effect)",[1096,1134,1135,1136,1139],{},"An effect that runs while the ",[241,1137,1138],{},"Scope"," is open.",[1081,1141,1142,1147],{},[1096,1143,1144],{},[241,1145,1146],{},"useInterval(period)(action)",[1096,1148,1149,1150,793],{},"An action that runs again after each ",[241,1151,1152],{},"period",[229,1154,1155,1156,1159,1160,1162,1163,1166,1167,1170,1171,1174,1175,1178,1179,1181],{},"At the top of an app, sequence the components in a ",[241,1157,1158],{},"for",". They run once, and their effects live as long as the ",[241,1161,1138],{}," of the app. Inside a reactive part of the tree (a ",[241,1164,1165],{},"render",", a ",[241,1168,1169],{},"foreach"," row, a ",[241,1172,1173],{},"when","), wrap the component in ",[241,1176,1177],{},"component(body)",". The runner runs the body when the node mounts, in a ",[241,1180,1138],{}," that closes when the node unmounts.",[229,1183,1184,1185,793],{},"The identity of a node is its call site and its key. While a node of the same identity stays at the same position, the mount goes on: its state, its effects and its UI stay, and the body does not run again. Give a key when one call site shows different things at one position: ",[241,1186,1187],{},"component(user.id)(...)",[1056,1189,1191],{"id":1190},"the-class-style","The class style",[229,1193,1194,1195,1198,1199,1201,1202,1205,1206,1209,1210,1212,1213,1215],{},"The runner allocates a ",[241,1196,1197],{},"SignalRef[State]"," with ",[241,1200,478],{}," when the component mounts. It keeps the state under the position and the ",[241,1203,1204],{},"stateKey"," (the class name by default). When the parent renders again, the new instance gets the same state. ",[241,1207,1208],{},"onMount(state)"," runs once per mount, on a fiber with a ",[241,1211,1138],{}," of its own. Override ",[241,1214,1204],{}," to keep one state for each value, for example one for each id.",[1056,1217,1219],{"id":1218},"how-long-the-state-lives","How long the state lives",[1075,1221,1222,1238],{},[1078,1223,1224],{},[1081,1225,1226,1229,1235],{},[1084,1227,1228],{},"Event",[1084,1230,1231,1232,273],{},"Hook component (",[241,1233,1234],{},"component",[1084,1236,1237],{},"Class component",[1091,1239,1240,1255,1275,1288,1300],{},[1081,1241,1242,1245,1248],{},[1096,1243,1244],{},"The parent renders again",[1096,1246,1247],{},"The state stays. The body does not run again.",[1096,1249,1250,1251,1254],{},"The state stays. ",[241,1252,1253],{},"onMount"," does not run again.",[1081,1256,1257,1263,1269],{},[1096,1258,1259,1260,1262],{},"A ",[241,1261,1173],{}," hides it",[1096,1264,1265,1266,1268],{},"The state goes. The ",[241,1267,1138],{}," closes and its fibers stop.",[1096,1270,1271,1272,1274],{},"The state goes. The fiber of ",[241,1273,1253],{}," stops.",[1081,1276,1277,1280,1283],{},[1096,1278,1279],{},"It comes back",[1096,1281,1282],{},"It starts fresh.",[1096,1284,1285,1286,793],{},"It starts from ",[241,1287,478],{},[1081,1289,1290,1295,1298],{},[1096,1291,1292,1262],{},[241,1293,1294],{},"displayNone",[1096,1296,1297],{},"The state stays.",[1096,1299,1297],{},[1081,1301,1302,1305,1308],{},[1096,1303,1304],{},"The run ends",[1096,1306,1307],{},"Its fibers stop.",[1096,1309,1307],{},[229,1311,1312,1313,1315],{},"In the example, ",[241,1314,804],{}," hides the hook counters. When they come back, they count from 0 again. The class counters keep their counts.",[229,1317,1318,1319,1322],{},"The frame of the event that mounts a hook component waits for its first UI at most ",[241,1320,1321],{},"TuiOptions.pendingTimeout"," (2 s). Then the frame comes without it, and the UI comes in a later frame.",[229,1324,1325,1326,1328],{},"A failure of a hook body or of ",[241,1327,1253],{}," gives one line at error in the log of the run, with the position. The run goes on.",[1330,1331,1332,1333,1335],"note",{},"A kyo-ui UI that is built outside tui4s keeps no state between two builds. The mount of a node and its state are a part of the tui4s runner. In another kyo-ui runner, a ",[241,1334,1234],{}," node is empty.",[1337,1338,1339],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":239,"searchDepth":291,"depth":291,"links":1341},[1342,1343,1344],{"id":1058,"depth":291,"text":913},{"id":1190,"depth":291,"text":1191},{"id":1218,"depth":291,"text":1219},"Two styles of components, hooks and a class, and how long their state lives.","md",null,{},{"icon":36},{"title":33,"description":1345},"vn_-J8k2IINXiGSN_-6B7sF4WByvcS_0MQIjTAiw_AU",[1353,1355],{"title":21,"path":22,"stem":23,"description":1354,"icon":24,"children":-1},"Test the Counter on the headless test kit, with no terminal.",{"title":38,"path":39,"stem":40,"description":1356,"icon":41,"children":-1},"The native inputs of kyo-ui in the terminal, their bindings and their keys.",1792528752826]